use crate::dfa::DFA;
use crate::mir::SymbolOp;
use std::collections::{BTreeMap, HashMap};
use std::hash::Hash;
#[derive(Debug)]
pub struct StateTransTable<S, T> {
table: Box<[usize]>,
init_id: usize,
num_states: usize,
sym_map: BTreeMap<S, (S, usize)>,
tags: HashMap<usize, T>,
}
impl<S, T> StateTransTable<S, T> {
pub fn new(dfa: DFA<S, T>) -> Self
where
S: Clone + Hash + Eq + Ord + SymbolOp,
{
let (equivs, trans_table, init_id, tags) = TempTable::new(dfa).into_optimized();
let num_states = trans_table[0].len();
let table = trans_table
.into_iter()
.flat_map(|s| s.into_iter())
.collect::<Vec<_>>()
.into_boxed_slice();
let sym_map = equivs
.into_iter()
.enumerate()
.flat_map(|(i, es)| es.into_iter().map(move |(l, r)| (r, (l, i))))
.collect();
Self {
table,
init_id,
num_states,
sym_map,
tags,
}
}
pub fn table(&self) -> &[usize] {
&self.table
}
pub fn init_id(&self) -> usize {
self.init_id
}
pub fn num_states(&self) -> usize {
self.num_states
}
pub fn sym_map(&self) -> &BTreeMap<S, (S, usize)> {
&self.sym_map
}
pub fn tags(&self) -> &HashMap<usize, T> {
&self.tags
}
pub fn next_state(&self, id: usize, s: &S) -> Option<usize>
where
S: Ord,
{
if id >= self.num_states {
return None;
}
let equiv = match self.sym_map.range(s..).next() {
Some((_, (l, id))) if s >= l => *id,
_ => return None,
};
let next = self.table[equiv * self.num_states + id];
(next < self.num_states).then_some(next)
}
pub fn is_final(&self, id: usize) -> Option<&T> {
self.tags.get(&id)
}
}
impl<S, T> From<DFA<S, T>> for StateTransTable<S, T>
where
S: Clone + Hash + Eq + Ord + SymbolOp,
{
fn from(dfa: DFA<S, T>) -> Self {
Self::new(dfa)
}
}
struct TempTable<S, T> {
table: HashMap<Vec<(S, S)>, Vec<usize>>,
tags: HashMap<usize, T>,
init_id: usize,
}
impl<S, T> TempTable<S, T> {
fn new(dfa: DFA<S, T>) -> Self
where
S: Clone + Hash + Eq,
{
let (fa, tags) = dfa.into_fa_tags();
let num_states = fa.states().len();
let mut ids = HashMap::new();
for id in fa.states().keys() {
let next_id = ids.len();
ids.insert(*id, next_id);
}
let mut table = HashMap::new();
for (id, state) in fa.states() {
let id = ids[id];
for (sym, next) in state.outs() {
let states = table.entry(sym.clone()).or_insert_with(|| {
let mut v = Vec::new();
v.resize(num_states, num_states);
v
});
states[id] = ids[next];
}
}
let tags = tags.into_iter().map(|(id, tag)| (ids[&id], tag)).collect();
Self {
table,
tags,
init_id: ids[&fa.init_id()],
}
}
fn into_optimized(self) -> OptimizedTable<S, T>
where
S: Ord + SymbolOp,
{
let mut table: Vec<_> = self.table.into_iter().map(|(s, t)| (t, s)).collect();
table.sort_unstable();
let mut equivs: Vec<Vec<(S, S)>> = Vec::new();
let mut trans_table = Vec::new();
for (states, sym) in table {
match trans_table.last() {
Some(t) if t == &states => {
let equiv = equivs.last_mut().unwrap();
let (_, last_r) = equiv.last_mut().unwrap();
let mut iter = sym.into_iter();
let first_sym = iter.next().unwrap();
if last_r.next().as_ref() == Some(&first_sym.0) {
*last_r = first_sym.1;
} else {
equiv.push(first_sym);
}
equiv.extend(iter);
}
_ => {
equivs.push(sym);
trans_table.push(states);
}
}
}
(equivs, trans_table, self.init_id, self.tags)
}
}
type OptimizedTable<S, T> = (Vec<Vec<(S, S)>>, Vec<Vec<usize>>, usize, HashMap<usize, T>);