use std::{collections::HashMap, hash};
#[derive(Debug)]
pub struct Trie<Sym, V, TT> {
nodes: Vec<TrieNode<Sym, V, TT>>,
}
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum TrieCursor {
Start,
Match { idx: usize, is_partial: bool },
NoMatch,
}
#[derive(Debug)]
pub struct TrieNode<Sym, V, TT> {
phantom: std::marker::PhantomData<Sym>,
value: Option<V>,
tab: TT,
}
impl<Sym, V, TT> Trie<Sym, V, TT>
where
TT: TrieTab<Sym>,
Sym: Copy,
{
pub fn new() -> Self {
Trie { nodes: vec![TrieNode::new(None)] }
}
pub fn insert<Seq: Iterator<Item = Sym>>(&mut self, seq: Seq, value: V) {
let mut current_node = 0;
for sym in seq {
current_node = if let Some(next_node) = self.nodes[current_node].tab.get(sym) {
*next_node
} else {
let idx = self.nodes.len();
self.nodes.push(TrieNode::new(None));
self.nodes[current_node].tab.set(sym, idx);
idx
};
}
self.nodes[current_node].value = Some(value);
}
#[allow(dead_code)]
pub fn contains<Seq: Iterator<Item = Sym>>(&self, seq: Seq) -> bool {
let mut match_state = TrieCursor::Start;
for sym in seq {
match_state = self.advance(match_state, sym);
if let TrieCursor::NoMatch = match_state {
return false;
}
}
if let TrieCursor::Start = match_state {
return self.nodes[0].value.is_some();
}
if let TrieCursor::Match { is_partial, .. } = match_state {
!is_partial
} else {
false
}
}
pub fn advance(&self, cursor: TrieCursor, sym: Sym) -> TrieCursor {
let node = match cursor {
TrieCursor::Start => &self.nodes[0],
TrieCursor::Match { idx, .. } => &self.nodes[idx],
TrieCursor::NoMatch => return TrieCursor::NoMatch,
};
if let Some(idx) = node.tab.get(sym) {
TrieCursor::Match { idx: *idx, is_partial: self.nodes[*idx].value.is_none() }
} else {
TrieCursor::NoMatch
}
}
pub fn get(&self, cursor: TrieCursor) -> Option<&V> {
if let TrieCursor::Match { idx, .. } = cursor {
self.nodes[idx].value.as_ref()
} else {
None
}
}
}
impl<Sym, V, TT> TrieNode<Sym, V, TT>
where
TT: TrieTab<Sym>,
{
fn new(value: Option<V>) -> Self {
TrieNode { phantom: std::marker::PhantomData, value, tab: TT::new() }
}
}
pub trait TrieTab<Idx> {
fn new() -> Self;
fn get(&self, index: Idx) -> Option<&usize>;
fn set(&mut self, index: Idx, elem: usize);
}
impl<Sym> TrieTab<Sym> for HashMap<Sym, usize>
where
Sym: hash::Hash + Eq + PartialEq,
{
fn new() -> Self {
HashMap::new()
}
fn get(&self, index: Sym) -> Option<&usize> {
self.get(&index)
}
fn set(&mut self, index: Sym, elem: usize) {
self.insert(index, elem);
}
}
impl TrieTab<u8> for Vec<Option<usize>> {
fn new() -> Self {
vec![None; u8::MAX as usize]
}
fn get(&self, index: u8) -> Option<&usize> {
self[index as usize].as_ref()
}
fn set(&mut self, index: u8, elem: usize) {
self[index as usize] = Some(elem)
}
}