1use crate::{
2 dfa::{
3 accel,
4 automaton::{Automaton, OverlappingState},
5 },
6 util::{
7 prefilter::Prefilter,
8 primitives::StateID,
9 search::{Anchored, HalfMatch, Input, Span},
10 },
11 MatchError,
12};
13
14#[inline(never)]
15pub fn find_fwd<A: Automaton + ?Sized>(
16 dfa: &A,
17 input: &Input<'_>,
18) -> Result<Option<HalfMatch>, MatchError> {
19 if input.is_done() {
20 return Ok(None);
21 }
22 let pre = if input.get_anchored().is_anchored() {
23 None
24 } else {
25 dfa.get_prefilter()
26 };
27 if pre.is_some() {
30 if input.get_earliest() {
31 find_fwd_imp(dfa, input, pre, true)
32 } else {
33 find_fwd_imp(dfa, input, pre, false)
34 }
35 } else {
36 if input.get_earliest() {
37 find_fwd_imp(dfa, input, None, true)
38 } else {
39 find_fwd_imp(dfa, input, None, false)
40 }
41 }
42}
43
44#[cfg_attr(feature = "perf-inline", inline(always))]
45fn find_fwd_imp<A: Automaton + ?Sized>(
46 dfa: &A,
47 input: &Input<'_>,
48 pre: Option<&'_ Prefilter>,
49 earliest: bool,
50) -> Result<Option<HalfMatch>, MatchError> {
51 let universal_start = dfa.universal_start_state(Anchored::No).is_some();
53 let mut mat = None;
54 let mut sid = init_fwd(dfa, input)?;
55 let mut at = input.start();
56 macro_rules! next_unchecked {
60 ($sid:expr, $at:expr) => {{
61 let byte = *input.haystack().get_unchecked($at);
62 dfa.next_state_unchecked($sid, byte)
63 }};
64 }
65
66 if let Some(ref pre) = pre {
67 let span = Span::from(at..input.end());
68 match pre.find(input.haystack(), span) {
74 None => return Ok(mat),
75 Some(ref span) => {
76 at = span.start;
77 if !universal_start {
78 sid = prefilter_restart(dfa, &input, at)?;
79 }
80 }
81 }
82 }
83 while at < input.end() {
84 let mut prev_sid;
98 while at < input.end() {
99 prev_sid = unsafe { next_unchecked!(sid, at) };
100 if dfa.is_special_state(prev_sid) || at + 3 >= input.end() {
101 core::mem::swap(&mut prev_sid, &mut sid);
102 break;
103 }
104 at += 1;
105
106 sid = unsafe { next_unchecked!(prev_sid, at) };
107 if dfa.is_special_state(sid) {
108 break;
109 }
110 at += 1;
111
112 prev_sid = unsafe { next_unchecked!(sid, at) };
113 if dfa.is_special_state(prev_sid) {
114 core::mem::swap(&mut prev_sid, &mut sid);
115 break;
116 }
117 at += 1;
118
119 sid = unsafe { next_unchecked!(prev_sid, at) };
120 if dfa.is_special_state(sid) {
121 break;
122 }
123 at += 1;
124 }
125 if dfa.is_special_state(sid) {
126 if dfa.is_start_state(sid) {
127 if let Some(ref pre) = pre {
128 let span = Span::from(at..input.end());
129 match pre.find(input.haystack(), span) {
130 None => return Ok(mat),
131 Some(ref span) => {
132 if span.start > at {
142 at = span.start;
143 if !universal_start {
144 sid = prefilter_restart(dfa, &input, at)?;
145 }
146 continue;
147 }
148 }
149 }
150 } else if dfa.is_accel_state(sid) {
151 let needles = dfa.accelerator(sid);
152 at = accel::find_fwd(needles, input.haystack(), at + 1)
153 .unwrap_or(input.end());
154 continue;
155 }
156 } else if dfa.is_match_state(sid) {
157 let pattern = dfa.match_pattern(sid, 0);
158 mat = Some(HalfMatch::new(pattern, at));
159 if earliest {
160 return Ok(mat);
161 }
162 if dfa.is_accel_state(sid) {
163 let needles = dfa.accelerator(sid);
164 at = accel::find_fwd(needles, input.haystack(), at + 1)
165 .unwrap_or(input.end());
166 continue;
167 }
168 } else if dfa.is_accel_state(sid) {
169 let needs = dfa.accelerator(sid);
170 at = accel::find_fwd(needs, input.haystack(), at + 1)
171 .unwrap_or(input.end());
172 continue;
173 } else if dfa.is_dead_state(sid) {
174 return Ok(mat);
175 } else {
176 return Err(MatchError::quit(input.haystack()[at], at));
180 }
181 }
182 at += 1;
183 }
184 eoi_fwd(dfa, input, &mut sid, &mut mat)?;
185 Ok(mat)
186}
187
188#[inline(never)]
189pub fn find_rev<A: Automaton + ?Sized>(
190 dfa: &A,
191 input: &Input<'_>,
192) -> Result<Option<HalfMatch>, MatchError> {
193 if input.is_done() {
194 return Ok(None);
195 }
196 if input.get_earliest() {
197 find_rev_imp(dfa, input, true)
198 } else {
199 find_rev_imp(dfa, input, false)
200 }
201}
202
203#[cfg_attr(feature = "perf-inline", inline(always))]
204fn find_rev_imp<A: Automaton + ?Sized>(
205 dfa: &A,
206 input: &Input<'_>,
207 earliest: bool,
208) -> Result<Option<HalfMatch>, MatchError> {
209 let mut mat = None;
210 let mut sid = init_rev(dfa, input)?;
211 if input.start() == input.end() {
218 eoi_rev(dfa, input, &mut sid, &mut mat)?;
219 return Ok(mat);
220 }
221
222 let mut at = input.end() - 1;
223 macro_rules! next_unchecked {
224 ($sid:expr, $at:expr) => {{
225 let byte = *input.haystack().get_unchecked($at);
226 dfa.next_state_unchecked($sid, byte)
227 }};
228 }
229 loop {
230 let mut prev_sid;
232 while at >= input.start() {
233 prev_sid = unsafe { next_unchecked!(sid, at) };
234 if dfa.is_special_state(prev_sid)
235 || at <= input.start().saturating_add(3)
236 {
237 core::mem::swap(&mut prev_sid, &mut sid);
238 break;
239 }
240 at -= 1;
241
242 sid = unsafe { next_unchecked!(prev_sid, at) };
243 if dfa.is_special_state(sid) {
244 break;
245 }
246 at -= 1;
247
248 prev_sid = unsafe { next_unchecked!(sid, at) };
249 if dfa.is_special_state(prev_sid) {
250 core::mem::swap(&mut prev_sid, &mut sid);
251 break;
252 }
253 at -= 1;
254
255 sid = unsafe { next_unchecked!(prev_sid, at) };
256 if dfa.is_special_state(sid) {
257 break;
258 }
259 at -= 1;
260 }
261 if dfa.is_special_state(sid) {
262 if dfa.is_start_state(sid) {
263 if dfa.is_accel_state(sid) {
264 let needles = dfa.accelerator(sid);
265 at = accel::find_rev(needles, input.haystack(), at)
266 .map(|i| i + 1)
267 .unwrap_or(input.start());
268 }
269 } else if dfa.is_match_state(sid) {
270 let pattern = dfa.match_pattern(sid, 0);
271 mat = Some(HalfMatch::new(pattern, at + 1));
275 if earliest {
276 return Ok(mat);
277 }
278 if dfa.is_accel_state(sid) {
279 let needles = dfa.accelerator(sid);
280 at = accel::find_rev(needles, input.haystack(), at)
281 .map(|i| i + 1)
282 .unwrap_or(input.start());
283 }
284 } else if dfa.is_accel_state(sid) {
285 let needles = dfa.accelerator(sid);
286 at = accel::find_rev(needles, input.haystack(), at)
294 .map(|i| i + 1)
295 .unwrap_or(input.start());
296 } else if dfa.is_dead_state(sid) {
297 return Ok(mat);
298 } else {
299 return Err(MatchError::quit(input.haystack()[at], at));
300 }
301 }
302 if at == input.start() {
303 break;
304 }
305 at -= 1;
306 }
307 eoi_rev(dfa, input, &mut sid, &mut mat)?;
308 Ok(mat)
309}
310
311#[inline(never)]
312pub fn find_overlapping_fwd<A: Automaton + ?Sized>(
313 dfa: &A,
314 input: &Input<'_>,
315 state: &mut OverlappingState,
316) -> Result<(), MatchError> {
317 state.mat = None;
318 if input.is_done() {
319 return Ok(());
320 }
321 let pre = if input.get_anchored().is_anchored() {
322 None
323 } else {
324 dfa.get_prefilter()
325 };
326 if pre.is_some() {
327 find_overlapping_fwd_imp(dfa, input, pre, state)
328 } else {
329 find_overlapping_fwd_imp(dfa, input, None, state)
330 }
331}
332
333#[cfg_attr(feature = "perf-inline", inline(always))]
334fn find_overlapping_fwd_imp<A: Automaton + ?Sized>(
335 dfa: &A,
336 input: &Input<'_>,
337 pre: Option<&'_ Prefilter>,
338 state: &mut OverlappingState,
339) -> Result<(), MatchError> {
340 let universal_start = dfa.universal_start_state(Anchored::No).is_some();
342 let mut sid = match state.id {
343 None => {
344 state.at = input.start();
345 init_fwd(dfa, input)?
346 }
347 Some(sid) => {
348 if let Some(match_index) = state.next_match_index {
349 let match_len = dfa.match_len(sid);
350 if match_index < match_len {
351 state.next_match_index = Some(match_index + 1);
352 let pattern = dfa.match_pattern(sid, match_index);
353 state.mat = Some(HalfMatch::new(pattern, state.at));
354 return Ok(());
355 }
356 }
357 state.at += 1;
360 if state.at > input.end() {
361 return Ok(());
362 }
363 sid
364 }
365 };
366
367 while state.at < input.end() {
372 sid = dfa.next_state(sid, input.haystack()[state.at]);
373 if dfa.is_special_state(sid) {
374 state.id = Some(sid);
375 if dfa.is_start_state(sid) {
376 if let Some(ref pre) = pre {
377 let span = Span::from(state.at..input.end());
378 match pre.find(input.haystack(), span) {
379 None => return Ok(()),
380 Some(ref span) => {
381 if span.start > state.at {
382 state.at = span.start;
383 if !universal_start {
384 sid = prefilter_restart(
385 dfa, &input, state.at,
386 )?;
387 }
388 continue;
389 }
390 }
391 }
392 } else if dfa.is_accel_state(sid) {
393 let needles = dfa.accelerator(sid);
394 state.at = accel::find_fwd(
395 needles,
396 input.haystack(),
397 state.at + 1,
398 )
399 .unwrap_or(input.end());
400 continue;
401 }
402 } else if dfa.is_match_state(sid) {
403 state.next_match_index = Some(1);
404 let pattern = dfa.match_pattern(sid, 0);
405 state.mat = Some(HalfMatch::new(pattern, state.at));
406 return Ok(());
407 } else if dfa.is_accel_state(sid) {
408 let needs = dfa.accelerator(sid);
409 state.at =
417 accel::find_fwd(needs, input.haystack(), state.at + 1)
418 .unwrap_or(input.end());
419 continue;
420 } else if dfa.is_dead_state(sid) {
421 return Ok(());
422 } else {
423 return Err(MatchError::quit(
424 input.haystack()[state.at],
425 state.at,
426 ));
427 }
428 }
429 state.at += 1;
430 }
431
432 let result = eoi_fwd(dfa, input, &mut sid, &mut state.mat);
433 state.id = Some(sid);
434 if state.mat.is_some() {
435 state.next_match_index = Some(1);
440 }
441 result
442}
443
444#[inline(never)]
445pub(crate) fn find_overlapping_rev<A: Automaton + ?Sized>(
446 dfa: &A,
447 input: &Input<'_>,
448 state: &mut OverlappingState,
449) -> Result<(), MatchError> {
450 state.mat = None;
451 if input.is_done() {
452 return Ok(());
453 }
454 let mut sid = match state.id {
455 None => {
456 let sid = init_rev(dfa, input)?;
457 state.id = Some(sid);
458 if input.start() == input.end() {
459 state.rev_eoi = true;
460 } else {
461 state.at = input.end() - 1;
462 }
463 sid
464 }
465 Some(sid) => {
466 if let Some(match_index) = state.next_match_index {
467 let match_len = dfa.match_len(sid);
468 if match_index < match_len {
469 state.next_match_index = Some(match_index + 1);
470 let pattern = dfa.match_pattern(sid, match_index);
471 state.mat = Some(HalfMatch::new(pattern, state.at));
472 return Ok(());
473 }
474 }
475 if state.rev_eoi {
480 return Ok(());
481 } else if state.at == input.start() {
482 state.rev_eoi = true;
486 } else {
487 state.at -= 1;
489 }
490 sid
491 }
492 };
493 while !state.rev_eoi {
494 sid = dfa.next_state(sid, input.haystack()[state.at]);
495 if dfa.is_special_state(sid) {
496 state.id = Some(sid);
497 if dfa.is_start_state(sid) {
498 if dfa.is_accel_state(sid) {
499 let needles = dfa.accelerator(sid);
500 state.at =
501 accel::find_rev(needles, input.haystack(), state.at)
502 .map(|i| i + 1)
503 .unwrap_or(input.start());
504 }
505 } else if dfa.is_match_state(sid) {
506 state.next_match_index = Some(1);
507 let pattern = dfa.match_pattern(sid, 0);
508 state.mat = Some(HalfMatch::new(pattern, state.at + 1));
509 return Ok(());
510 } else if dfa.is_accel_state(sid) {
511 let needles = dfa.accelerator(sid);
512 state.at =
520 accel::find_rev(needles, input.haystack(), state.at)
521 .map(|i| i + 1)
522 .unwrap_or(input.start());
523 } else if dfa.is_dead_state(sid) {
524 return Ok(());
525 } else {
526 return Err(MatchError::quit(
527 input.haystack()[state.at],
528 state.at,
529 ));
530 }
531 }
532 if state.at == input.start() {
533 break;
534 }
535 state.at -= 1;
536 }
537
538 let result = eoi_rev(dfa, input, &mut sid, &mut state.mat);
539 state.rev_eoi = true;
540 state.id = Some(sid);
541 if state.mat.is_some() {
542 state.next_match_index = Some(1);
547 }
548 result
549}
550
551#[cfg_attr(feature = "perf-inline", inline(always))]
552fn init_fwd<A: Automaton + ?Sized>(
553 dfa: &A,
554 input: &Input<'_>,
555) -> Result<StateID, MatchError> {
556 let sid = dfa.start_state_forward(input)?;
557 debug_assert!(!dfa.is_match_state(sid));
560 Ok(sid)
561}
562
563#[cfg_attr(feature = "perf-inline", inline(always))]
564fn init_rev<A: Automaton + ?Sized>(
565 dfa: &A,
566 input: &Input<'_>,
567) -> Result<StateID, MatchError> {
568 let sid = dfa.start_state_reverse(input)?;
569 debug_assert!(!dfa.is_match_state(sid));
572 Ok(sid)
573}
574
575#[cfg_attr(feature = "perf-inline", inline(always))]
576fn eoi_fwd<A: Automaton + ?Sized>(
577 dfa: &A,
578 input: &Input<'_>,
579 sid: &mut StateID,
580 mat: &mut Option<HalfMatch>,
581) -> Result<(), MatchError> {
582 let sp = input.get_span();
583 match input.haystack().get(sp.end) {
584 Some(&b) => {
585 *sid = dfa.next_state(*sid, b);
586 if dfa.is_match_state(*sid) {
587 let pattern = dfa.match_pattern(*sid, 0);
588 *mat = Some(HalfMatch::new(pattern, sp.end));
589 } else if dfa.is_quit_state(*sid) {
590 return Err(MatchError::quit(b, sp.end));
591 }
592 }
593 None => {
594 *sid = dfa.next_eoi_state(*sid);
595 if dfa.is_match_state(*sid) {
596 let pattern = dfa.match_pattern(*sid, 0);
597 *mat = Some(HalfMatch::new(pattern, input.haystack().len()));
598 }
599 }
600 }
601 Ok(())
602}
603
604#[cfg_attr(feature = "perf-inline", inline(always))]
605fn eoi_rev<A: Automaton + ?Sized>(
606 dfa: &A,
607 input: &Input<'_>,
608 sid: &mut StateID,
609 mat: &mut Option<HalfMatch>,
610) -> Result<(), MatchError> {
611 let sp = input.get_span();
612 if sp.start > 0 {
613 let byte = input.haystack()[sp.start - 1];
614 *sid = dfa.next_state(*sid, byte);
615 if dfa.is_match_state(*sid) {
616 let pattern = dfa.match_pattern(*sid, 0);
617 *mat = Some(HalfMatch::new(pattern, sp.start));
618 } else if dfa.is_quit_state(*sid) {
619 return Err(MatchError::quit(byte, sp.start - 1));
620 }
621 } else {
622 *sid = dfa.next_eoi_state(*sid);
623 if dfa.is_match_state(*sid) {
624 let pattern = dfa.match_pattern(*sid, 0);
625 *mat = Some(HalfMatch::new(pattern, 0));
626 }
627 }
628 Ok(())
629}
630
631#[cfg_attr(feature = "perf-inline", inline(always))]
636fn prefilter_restart<A: Automaton + ?Sized>(
637 dfa: &A,
638 input: &Input<'_>,
639 at: usize,
640) -> Result<StateID, MatchError> {
641 let mut input = input.clone();
642 input.set_start(at);
643 init_fwd(dfa, &input)
644}