regex_automata/meta/
limited.rs1use crate::{
40 meta::error::{RetryError, RetryQuadraticError},
41 HalfMatch, Input, MatchError,
42};
43
44#[cfg(feature = "dfa-build")]
45pub(crate) fn dfa_try_search_half_rev(
46 dfa: &crate::dfa::dense::DFA<alloc::vec::Vec<u32>>,
47 input: &Input<'_>,
48 min_start: usize,
49) -> Result<Option<HalfMatch>, RetryError> {
50 use crate::dfa::Automaton;
51
52 let mut mat = None;
53 let mut sid = dfa.start_state_reverse(input)?;
54 if input.start() == input.end() {
55 dfa_eoi_rev(dfa, input, &mut sid, &mut mat)?;
56 return Ok(mat);
57 }
58 let mut at = input.end() - 1;
59 loop {
60 sid = dfa.next_state(sid, input.haystack()[at]);
61 if dfa.is_special_state(sid) {
62 if dfa.is_match_state(sid) {
63 let pattern = dfa.match_pattern(sid, 0);
64 mat = Some(HalfMatch::new(pattern, at + 1));
69 } else if dfa.is_dead_state(sid) {
70 return Ok(mat);
71 } else if dfa.is_quit_state(sid) {
72 return Err(MatchError::quit(input.haystack()[at], at).into());
73 }
74 }
75 if at == input.start() {
76 break;
77 }
78 at -= 1;
79 if at < min_start {
80 trace!(
81 "reached position {at} which is before the previous literal \
82 match, quitting to avoid quadratic behavior",
83 );
84 return Err(RetryError::Quadratic(RetryQuadraticError::new()));
85 }
86 }
87 let was_dead = dfa.is_dead_state(sid);
88 dfa_eoi_rev(dfa, input, &mut sid, &mut mat)?;
89 if at == input.start()
112 && mat.map_or(false, |m| m.offset() > input.start())
113 && !was_dead
114 {
115 trace!(
116 "reached beginning of search at offset {at} without hitting \
117 a dead state, quitting to avoid potential false positive match",
118 );
119 return Err(RetryError::Quadratic(RetryQuadraticError::new()));
120 }
121 Ok(mat)
122}
123
124#[cfg(feature = "hybrid")]
125pub(crate) fn hybrid_try_search_half_rev(
126 dfa: &crate::hybrid::dfa::DFA,
127 cache: &mut crate::hybrid::dfa::Cache,
128 input: &Input<'_>,
129 min_start: usize,
130) -> Result<Option<HalfMatch>, RetryError> {
131 let mut mat = None;
132 let mut sid = dfa.start_state_reverse(cache, input)?;
133 if input.start() == input.end() {
134 hybrid_eoi_rev(dfa, cache, input, &mut sid, &mut mat)?;
135 return Ok(mat);
136 }
137 let mut at = input.end() - 1;
138 loop {
139 sid = dfa
140 .next_state(cache, sid, input.haystack()[at])
141 .map_err(|_| MatchError::gave_up(at))?;
142 if sid.is_tagged() {
143 if sid.is_match() {
144 let pattern = dfa.match_pattern(cache, sid, 0);
145 mat = Some(HalfMatch::new(pattern, at + 1));
150 } else if sid.is_dead() {
151 return Ok(mat);
152 } else if sid.is_quit() {
153 return Err(MatchError::quit(input.haystack()[at], at).into());
154 }
155 }
156 if at == input.start() {
157 break;
158 }
159 at -= 1;
160 if at < min_start {
161 trace!(
162 "reached position {at} which is before the previous literal \
163 match, quitting to avoid quadratic behavior",
164 );
165 return Err(RetryError::Quadratic(RetryQuadraticError::new()));
166 }
167 }
168 let was_dead = sid.is_dead();
169 hybrid_eoi_rev(dfa, cache, input, &mut sid, &mut mat)?;
170 if at == input.start()
172 && mat.map_or(false, |m| m.offset() > input.start())
173 && !was_dead
174 {
175 trace!(
176 "reached beginning of search at offset {at} without hitting \
177 a dead state, quitting to avoid potential false positive match",
178 );
179 return Err(RetryError::Quadratic(RetryQuadraticError::new()));
180 }
181 Ok(mat)
182}
183
184#[cfg(feature = "dfa-build")]
185#[cfg_attr(feature = "perf-inline", inline(always))]
186fn dfa_eoi_rev(
187 dfa: &crate::dfa::dense::DFA<alloc::vec::Vec<u32>>,
188 input: &Input<'_>,
189 sid: &mut crate::util::primitives::StateID,
190 mat: &mut Option<HalfMatch>,
191) -> Result<(), MatchError> {
192 use crate::dfa::Automaton;
193
194 let sp = input.get_span();
195 if sp.start > 0 {
196 let byte = input.haystack()[sp.start - 1];
197 *sid = dfa.next_state(*sid, byte);
198 if dfa.is_match_state(*sid) {
199 let pattern = dfa.match_pattern(*sid, 0);
200 *mat = Some(HalfMatch::new(pattern, sp.start));
201 } else if dfa.is_quit_state(*sid) {
202 return Err(MatchError::quit(byte, sp.start - 1));
203 }
204 } else {
205 *sid = dfa.next_eoi_state(*sid);
206 if dfa.is_match_state(*sid) {
207 let pattern = dfa.match_pattern(*sid, 0);
208 *mat = Some(HalfMatch::new(pattern, 0));
209 }
210 if true {
if !!dfa.is_quit_state(*sid) {
::core::panicking::panic("assertion failed: !dfa.is_quit_state(*sid)")
};
};debug_assert!(!dfa.is_quit_state(*sid));
213 }
214 Ok(())
215}
216
217#[cfg(feature = "hybrid")]
218#[cfg_attr(feature = "perf-inline", inline(always))]
219fn hybrid_eoi_rev(
220 dfa: &crate::hybrid::dfa::DFA,
221 cache: &mut crate::hybrid::dfa::Cache,
222 input: &Input<'_>,
223 sid: &mut crate::hybrid::LazyStateID,
224 mat: &mut Option<HalfMatch>,
225) -> Result<(), MatchError> {
226 let sp = input.get_span();
227 if sp.start > 0 {
228 let byte = input.haystack()[sp.start - 1];
229 *sid = dfa
230 .next_state(cache, *sid, byte)
231 .map_err(|_| MatchError::gave_up(sp.start))?;
232 if sid.is_match() {
233 let pattern = dfa.match_pattern(cache, *sid, 0);
234 *mat = Some(HalfMatch::new(pattern, sp.start));
235 } else if sid.is_quit() {
236 return Err(MatchError::quit(byte, sp.start - 1));
237 }
238 } else {
239 *sid = dfa
240 .next_eoi_state(cache, *sid)
241 .map_err(|_| MatchError::gave_up(sp.start))?;
242 if sid.is_match() {
243 let pattern = dfa.match_pattern(cache, *sid, 0);
244 *mat = Some(HalfMatch::new(pattern, 0));
245 }
246 if true {
if !!sid.is_quit() {
::core::panicking::panic("assertion failed: !sid.is_quit()")
};
};debug_assert!(!sid.is_quit());
249 }
250 Ok(())
251}