use std::collections::{btree_map::Entry, BTreeMap, BTreeSet};
use crate::{nfa::Graph as Nfa, Compiled as Dfa};
type SubsetStates<I> = BTreeMap<
BTreeSet<usize>, (
BTreeMap<I, (BTreeSet<usize>, Option<&'static str>)>, // <-- Transitions
bool, // <-- Accepting or not
),
>;
impl<I: Clone + Ord> Nfa<I> {
#[inline]
pub(crate) fn subsets(self) -> Dfa<I> {
let mut subset_states = SubsetStates::new();
let initial_state = traverse(
&self,
self.initial.iter().copied().collect(),
&mut subset_states,
);
let mut ordered: Vec<_> = subset_states.keys().collect();
ordered.sort_unstable();
#[cfg(test)]
{
for (i, subset) in ordered.iter().enumerate() {
assert_eq!(ordered.binary_search(subset), Ok(i));
}
}
let states = ordered
.iter()
.map(|&subset| {
let &(ref states, accepting) = unwrap!(subset_states.get(subset));
crate::dfa::State {
transitions: states
.iter()
.map(|(token, &(ref set, fn_name))| {
(
token.clone(),
(unwrap!(ordered.binary_search(&set)), fn_name),
)
})
.collect(),
accepting,
}
})
.collect();
Dfa {
states,
initial: unwrap!(ordered.binary_search(&&initial_state)),
}
}
}
#[inline]
fn traverse<I: Clone + Ord>(
nfa: &Nfa<I>,
queue: Vec<usize>,
subset_states: &mut SubsetStates<I>,
) -> BTreeSet<usize> {
let post_epsilon = nfa.take_all_epsilon_transitions(queue);
let tmp = match subset_states.entry(post_epsilon.clone()) {
std::collections::btree_map::Entry::Occupied(_) => return post_epsilon,
std::collections::btree_map::Entry::Vacant(empty) => empty,
};
let subset = post_epsilon.iter().map(|&i| get!(nfa.states, i));
let _ = tmp.insert((BTreeMap::new(), subset.clone().any(|state| state.accepting)));
let mut transitions = BTreeMap::<I, (BTreeSet<usize>, Option<&'static str>)>::new();
for state in subset {
for (token, &(ref map, fn_name)) in &state.non_epsilon {
match transitions.entry(token.clone()) {
Entry::Vacant(entry) => {
let _ = entry.insert((map.clone(), fn_name));
}
Entry::Occupied(entry) => {
let &mut (ref mut set, ref mut existing_fn_name) = entry.into_mut();
assert_eq!(fn_name, *existing_fn_name, "MESSAGE TODO");
set.extend(map.iter().copied());
}
}
}
}
for &mut (ref mut dst, _) in transitions.values_mut() {
*dst = traverse(nfa, dst.iter().copied().collect(), subset_states);
}
unwrap!(subset_states.get_mut(&post_epsilon)).0 = transitions;
post_epsilon
}