A helper function for add that avoids excessive pushing to the stack.
(
&mut self,
nlist: &mut Threads,
thread_caps: &mut [Option<usize>],
mut ip: usize,
at: InputAt,
)
| 306 | |
| 307 | /// A helper function for add that avoids excessive pushing to the stack. |
| 308 | fn add_step( |
| 309 | &mut self, |
| 310 | nlist: &mut Threads, |
| 311 | thread_caps: &mut [Option<usize>], |
| 312 | mut ip: usize, |
| 313 | at: InputAt, |
| 314 | ) { |
| 315 | // Instead of pushing and popping to the stack, we mutate ip as we |
| 316 | // traverse the set of states. We only push to the stack when we |
| 317 | // absolutely need recursion (restoring captures or following a |
| 318 | // branch). |
| 319 | use prog::Inst::*; |
| 320 | loop { |
| 321 | // Don't visit states we've already added. |
| 322 | if nlist.set.contains(ip) { |
| 323 | return; |
| 324 | } |
| 325 | nlist.set.insert(ip); |
| 326 | match self.prog[ip] { |
| 327 | EmptyLook(ref inst) => { |
| 328 | if self.input.is_empty_match(at, inst) { |
| 329 | ip = inst.goto; |
| 330 | } |
| 331 | } |
| 332 | Save(ref inst) => { |
| 333 | if inst.slot < thread_caps.len() { |
| 334 | self.stack.push(FollowEpsilon::Capture { |
| 335 | slot: inst.slot, |
| 336 | pos: thread_caps[inst.slot], |
| 337 | }); |
| 338 | thread_caps[inst.slot] = Some(at.pos()); |
| 339 | } |
| 340 | ip = inst.goto; |
| 341 | } |
| 342 | Split(ref inst) => { |
| 343 | self.stack.push(FollowEpsilon::IP(inst.goto2)); |
| 344 | ip = inst.goto1; |
| 345 | } |
| 346 | Match(_) | Char(_) | Ranges(_) | Bytes(_) => { |
| 347 | let t = &mut nlist.caps(ip); |
| 348 | for (slot, val) in t.iter_mut().zip(thread_caps.iter()) { |
| 349 | *slot = *val; |
| 350 | } |
| 351 | return; |
| 352 | } |
| 353 | } |
| 354 | } |
| 355 | } |
| 356 | } |
| 357 | |
| 358 | impl Threads { |