use crate::collections::Map;
use crate::dfa::{StateIdx, DFA};
use std::collections::hash_map::Entry;
pub(crate) fn update_backtracks<A>(dfa: &mut DFA<StateIdx, A>) {
let mut work_list: Vec<(StateIdx, bool)> = dfa
.states
.iter()
.enumerate()
.filter_map(|(state_idx, state)| {
if state.initial {
Some((StateIdx(state_idx), false))
} else {
None
}
})
.collect();
let mut visited: Map<StateIdx, bool> = Default::default();
while let Some((state, backtrack)) = work_list.pop() {
match visited.entry(state) {
Entry::Occupied(mut entry) => {
if *entry.get() == backtrack {
continue;
}
entry.insert(backtrack);
}
Entry::Vacant(entry) => {
entry.insert(backtrack);
}
}
let successor_backtrack = backtrack || dfa.is_accepting_state(state);
for next in dfa.states[state.0].char_transitions.values() {
work_list.push((*next, successor_backtrack));
}
for next_range in dfa.states[state.0].range_transitions.iter() {
work_list.push((next_range.value, successor_backtrack));
}
if let Some(next) = dfa.states[state.0].any_transition {
work_list.push((next, successor_backtrack));
}
if let Some(next) = dfa.states[state.0].end_of_input_transition {
work_list.push((next, successor_backtrack));
}
}
assert_eq!(visited.len(), dfa.states.len());
for (state, backtrack) in visited {
dfa.states[state.0].backtrack = backtrack;
}
}