use std::fmt::Display;
#[derive(Debug)]
pub struct CompactTable {
num_states: u32,
alphabet_size: u32,
default: Box<[u32]>,
base: Box<[u32]>,
value: Box<[u32]>,
check: Box<[u32]>,
}
impl CompactTable {
pub fn eval(&self, s: u32, c: u32) -> u32 {
let k = self.base[s as usize] as usize + c as usize;
if self.check[k] == s {
self.value[k]
} else {
self.default[s as usize]
}
}
pub fn size(&self) -> usize {
self.value.len()
}
pub fn num_states(&self) -> usize {
self.num_states as usize
}
pub fn alphabet_size(&self) -> usize {
self.alphabet_size as usize
}
}
impl Display for CompactTable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let num_states = self.num_states();
writeln!(f, "Map")?;
for i in 0..self.size() {
let c = self.check[i];
if c != num_states as u32 {
let b = self.base[c as usize];
writeln!(f, " {}, {} -> {}", c, i - b as usize, self.value[i])?;
}
}
writeln!(f, "Default")?;
for i in 0..num_states {
writeln!(f, " {} -> {}", i, self.default[i])?;
}
Ok(())
}
}
#[derive(Debug)]
pub struct CompactTableBuilder {
num_states: u32,
alphabet_size: u32,
default: Box<[u32]>,
base: Box<[u32]>,
value: Vec<u32>,
check: Vec<u32>,
}
impl CompactTableBuilder {
pub fn new(num_states: u32, alphabet_size: u32) -> Self {
assert!(num_states > 0 && alphabet_size > 0);
let n = num_states as usize;
let default = vec![0; n].into_boxed_slice();
let base = vec![0; n].into_boxed_slice();
let m = alphabet_size as usize;
let value = vec![0; m];
let check = vec![num_states; m];
CompactTableBuilder {
num_states,
alphabet_size,
default,
base,
value,
check,
}
}
pub fn set_default(&mut self, i: u32, def: u32) {
debug_assert!(def < self.num_states);
self.default[i as usize] = def;
}
fn resize(&mut self, new_size: usize) {
self.check.resize(new_size, self.num_states);
self.value.resize(new_size, 0);
}
fn base_conflicts(&self, b: u32, successors: &[(u32, u32)]) -> bool {
let b = b as usize;
successors
.iter()
.any(|(c, _)| self.check[b + *c as usize] != self.num_states)
}
fn store_successors(&mut self, i: u32, b: u32, successors: &[(u32, u32)]) {
self.base[i as usize] = b;
for (c, v) in successors {
let k = b as usize + *c as usize;
self.check[k] = i;
self.value[k] = *v;
}
}
pub fn set_successors(&mut self, i: u32, successors: &[(u32, u32)]) {
let mut b = 0;
while self.base_conflicts(b, successors) {
b += 1;
if b as usize + self.alphabet_size as usize > self.value.len() {
let new_size = 2 * self.value.len();
assert!(new_size >= b as usize + self.alphabet_size as usize);
self.resize(new_size);
}
}
self.store_successors(i, b, successors);
}
pub fn build(&mut self) -> CompactTable {
let &max_base = self.base.iter().max().unwrap();
let max_index = max_base as usize + self.alphabet_size as usize;
self.value.truncate(max_index);
self.check.truncate(max_index);
let default = std::mem::take(&mut self.default);
let base = std::mem::take(&mut self.base);
let value = std::mem::take(&mut self.value).into_boxed_slice();
let check = std::mem::take(&mut self.check).into_boxed_slice();
CompactTable {
num_states: self.num_states,
alphabet_size: self.alphabet_size,
default,
base,
value,
check,
}
}
}