letmut mat = None; letmut sid = dfa.start_state_reverse(input)?; if input.start() == input.end() {
dfa_eoi_rev(dfa, input, &mut sid, &mut mat)?; return Ok(mat);
} letmut at = input.end() - 1; loop {
sid = dfa.next_state(sid, input.haystack()[at]); if dfa.is_special_state(sid) { if dfa.is_match_state(sid) { let pattern = dfa.match_pattern(sid, 0); // Since reverse searches report the beginning of a // match and the beginning is inclusive (not exclusive // like the end of a match), we add 1 to make it // inclusive.
mat = Some(HalfMatch::new(pattern, at + 1));
} elseif dfa.is_dead_state(sid) { return Ok(mat);
} elseif dfa.is_quit_state(sid) { if mat.is_some() { return Ok(mat);
} return Err(MatchError::quit(input.haystack()[at], at).into());
}
} if at == input.start() { break;
}
at -= 1; if at < min_start {
trace!( "reached position {} which is before the previous literal \ match, quitting to avoid quadratic behavior",
at,
); return Err(RetryError::Quadratic(RetryQuadraticError::new()));
}
} let was_dead = dfa.is_dead_state(sid);
dfa_eoi_rev(dfa, input, &mut sid, &mut mat)?; // If we reach the beginning of the search and we could otherwise still // potentially keep matching if there was more to match, then we actually // return an error to indicate giving up on this optimization. Why? Because // we can't prove that the real match begins at where we would report it. // // This only happens when all of the following are true: // // 1) We reach the starting point of our search span. // 2) The match we found is before the starting point. // 3) The FSM reports we could possibly find a longer match. // // We need (1) because otherwise the search stopped before the starting // point and there is no possible way to find a more leftmost position. // // We need (2) because if the match found has an offset equal to the minimum // possible offset, then there is no possible more leftmost match. // // We need (3) because if the FSM couldn't continue anyway (i.e., it's in // a dead state), then we know we couldn't find anything more leftmost // than what we have. (We have to check the state we were in prior to the // EOI transition since the EOI transition will usually bring us to a dead // state by virtue of it represents the end-of-input.) if at == input.start()
&& mat.map_or(false, |m| m.offset() > input.start())
&& !was_dead
{
trace!( "reached beginning of search at offset {} without hitting \
a dead state, quitting to avoid potential false positive match",
at,
); return Err(RetryError::Quadratic(RetryQuadraticError::new()));
}
Ok(mat)
}
#[cfg(feature = "hybrid")] pub(crate) fn hybrid_try_search_half_rev(
dfa: &crate::hybrid::dfa::DFA,
cache: &mutcrate::hybrid::dfa::Cache,
input: &Input<'_>,
min_start: usize,
) -> Result<Option<HalfMatch>, RetryError> { letmut mat = None; letmut sid = dfa.start_state_reverse(cache, input)?; if input.start() == input.end() {
hybrid_eoi_rev(dfa, cache, input, &mut sid, &mut mat)?; return Ok(mat);
} letmut at = input.end() - 1; loop {
sid = dfa
.next_state(cache, sid, input.haystack()[at])
.map_err(|_| MatchError::gave_up(at))?; if sid.is_tagged() { if sid.is_match() { let pattern = dfa.match_pattern(cache, sid, 0); // Since reverse searches report the beginning of a // match and the beginning is inclusive (not exclusive // like the end of a match), we add 1 to make it // inclusive.
mat = Some(HalfMatch::new(pattern, at + 1));
} elseif sid.is_dead() { return Ok(mat);
} elseif sid.is_quit() { if mat.is_some() { return Ok(mat);
} return Err(MatchError::quit(input.haystack()[at], at).into());
}
} if at == input.start() { break;
}
at -= 1; if at < min_start {
trace!( "reached position {} which is before the previous literal \ match, quitting to avoid quadratic behavior",
at,
); return Err(RetryError::Quadratic(RetryQuadraticError::new()));
}
} let was_dead = sid.is_dead();
hybrid_eoi_rev(dfa, cache, input, &mut sid, &mut mat)?; // See the comments in the full DFA routine above for why we need this. if at == input.start()
&& mat.map_or(false, |m| m.offset() > input.start())
&& !was_dead
{
trace!( "reached beginning of search at offset {} without hitting \
a dead state, quitting to avoid potential false positive match",
at,
); return Err(RetryError::Quadratic(RetryQuadraticError::new()));
}
Ok(mat)
}
let sp = input.get_span(); if sp.start > 0 { let byte = input.haystack()[sp.start - 1];
*sid = dfa.next_state(*sid, byte); if dfa.is_match_state(*sid) { let pattern = dfa.match_pattern(*sid, 0);
*mat = Some(HalfMatch::new(pattern, sp.start));
} elseif dfa.is_quit_state(*sid) { if mat.is_some() { return Ok(());
} return Err(MatchError::quit(byte, sp.start - 1));
}
} else {
*sid = dfa.next_eoi_state(*sid); if dfa.is_match_state(*sid) { let pattern = dfa.match_pattern(*sid, 0);
*mat = Some(HalfMatch::new(pattern, 0));
} // N.B. We don't have to check 'is_quit' here because the EOI // transition can never lead to a quit state.
debug_assert!(!dfa.is_quit_state(*sid));
}
Ok(())
}
#[cfg(feature = "hybrid")] #[cfg_attr(feature = "perf-inline", inline(always))] fn hybrid_eoi_rev(
dfa: &crate::hybrid::dfa::DFA,
cache: &mutcrate::hybrid::dfa::Cache,
input: &Input<'_>,
sid: &mutcrate::hybrid::LazyStateID,
mat: &mut Option<HalfMatch>,
) -> Result<(), MatchError> { let sp = input.get_span(); if sp.start > 0 { let byte = input.haystack()[sp.start - 1];
*sid = dfa
.next_state(cache, *sid, byte)
.map_err(|_| MatchError::gave_up(sp.start))?; if sid.is_match() { let pattern = dfa.match_pattern(cache, *sid, 0);
*mat = Some(HalfMatch::new(pattern, sp.start));
} elseif sid.is_quit() { if mat.is_some() { return Ok(());
} return Err(MatchError::quit(byte, sp.start - 1));
}
} else {
*sid = dfa
.next_eoi_state(cache, *sid)
.map_err(|_| MatchError::gave_up(sp.start))?; if sid.is_match() { let pattern = dfa.match_pattern(cache, *sid, 0);
*mat = Some(HalfMatch::new(pattern, 0));
} // N.B. We don't have to check 'is_quit' here because the EOI // transition can never lead to a quit state.
debug_assert!(!sid.is_quit());
}
Ok(())
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-06-23)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.