226 lines
7.1 KiB
Rust
226 lines
7.1 KiB
Rust
use super::keychecker::KeyChecker;
|
|
use super::trienode::TrieKey;
|
|
use super::trienode::TrieNode;
|
|
use std::collections::BTreeSet;
|
|
use std::iter::Iterator;
|
|
use std::marker::PhantomData;
|
|
|
|
pub enum VisitOutcome {
|
|
Continue,
|
|
Skip,
|
|
EarlyExit,
|
|
}
|
|
|
|
pub struct Trie<KEY, KEYCHECKER>
|
|
where
|
|
KEY: TrieKey,
|
|
KEYCHECKER: KeyChecker<KEY>,
|
|
{
|
|
pub(crate) nodes: Vec<TrieNode<KEY>>,
|
|
tails: BTreeSet<usize>,
|
|
checker: PhantomData<KEYCHECKER>,
|
|
}
|
|
impl<KEY, KEYCHECKER> Default for Trie<KEY, KEYCHECKER>
|
|
where
|
|
KEY: TrieKey,
|
|
KEYCHECKER: KeyChecker<KEY>,
|
|
{
|
|
fn default() -> Self {
|
|
Trie {
|
|
nodes: vec![TrieNode::new0(None)],
|
|
tails: BTreeSet::new(),
|
|
checker: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
impl<KEY, KEYCHECKER> Trie<KEY, KEYCHECKER>
|
|
where
|
|
KEY: TrieKey,
|
|
KEYCHECKER: KeyChecker<KEY>,
|
|
{
|
|
pub fn trie_from_words<T, U>(wordlist: U) -> Trie<KEY, KEYCHECKER>
|
|
where
|
|
T: IntoIterator<Item = KEY>,
|
|
U: IntoIterator<Item = T>,
|
|
{
|
|
let mut result = Trie::default();
|
|
for word in wordlist {
|
|
result.add(word);
|
|
}
|
|
result
|
|
}
|
|
|
|
pub(crate) fn get_node_mut(&mut self, index: usize) -> &mut TrieNode<KEY> {
|
|
&mut self.nodes[index]
|
|
}
|
|
|
|
pub(crate) fn get_node(&self, index: usize) -> &TrieNode<KEY> {
|
|
&self.nodes[index]
|
|
}
|
|
|
|
pub(crate) fn nodes(&self) -> usize {
|
|
self.nodes.len()
|
|
}
|
|
|
|
fn add_node(&mut self, key: Option<KEY>, parent: usize, prev: Option<usize>) -> usize {
|
|
let mut result = TrieNode::new0(key);
|
|
let result_index = self.nodes();
|
|
result.parent = Some(parent);
|
|
match prev {
|
|
Some(prev_node) => {
|
|
self.get_node_mut(prev_node).next = Some(result_index);
|
|
result.prev = prev;
|
|
}
|
|
None => {
|
|
let parent_node = self.get_node_mut(parent);
|
|
match parent_node.child {
|
|
None => {
|
|
parent_node.child = Some(result_index);
|
|
}
|
|
Some(parent_child) => {
|
|
let mut node = parent_child;
|
|
loop {
|
|
let next = self.get_node(node).next;
|
|
match next {
|
|
Some(next_node) => {
|
|
node = next_node;
|
|
}
|
|
None => {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
self.get_node_mut(node).next = Some(result_index);
|
|
result.prev = Some(node)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
self.nodes.push(result);
|
|
result_index
|
|
}
|
|
|
|
pub fn add<T>(&mut self, path: T) -> (bool, usize)
|
|
where
|
|
T: IntoIterator<Item = KEY>,
|
|
{
|
|
let mut result = false;
|
|
let mut pnode = 0;
|
|
'wordLoop: for key in path {
|
|
let mut cnode = self.get_node(pnode).child;
|
|
while let Some(cnode_index) = cnode {
|
|
let cnode_node = self.get_node(cnode_index);
|
|
if KEYCHECKER::check(cnode_node.key, Some(key)) {
|
|
pnode = cnode_index;
|
|
continue 'wordLoop;
|
|
} else if self.get_node(cnode_index).next.is_none() {
|
|
break;
|
|
} else {
|
|
cnode = self.get_node(cnode_index).next;
|
|
}
|
|
}
|
|
pnode = self.add_node(Some(key), pnode, cnode);
|
|
result = true;
|
|
}
|
|
if result {
|
|
let tail = self.add_node(None, pnode, None);
|
|
self.tails.insert(tail);
|
|
let mut node = Some(tail);
|
|
while let Some(n) = node {
|
|
let current_node = self.get_node_mut(n);
|
|
current_node.ref_count += 1;
|
|
node = current_node.parent;
|
|
}
|
|
(true, tail)
|
|
} else {
|
|
(false, pnode)
|
|
}
|
|
}
|
|
|
|
pub fn search(&mut self, path: Vec<KEY>) -> Option<usize> {
|
|
let mut result: Option<usize> = None;
|
|
let visit_pre = |stack: &Vec<usize>| -> VisitOutcome {
|
|
if stack.len() == 1 {
|
|
VisitOutcome::Continue
|
|
} else {
|
|
let last = *stack.last().expect("");
|
|
let index = stack.len() - 2;
|
|
let node = self.get_node(last);
|
|
if index < path.len() {
|
|
if KEYCHECKER::check(node.key, Some(path[index])) {
|
|
VisitOutcome::Continue
|
|
} else {
|
|
VisitOutcome::Skip
|
|
}
|
|
} else {
|
|
if node.key.is_none() {
|
|
result = Some(last);
|
|
}
|
|
VisitOutcome::EarlyExit
|
|
}
|
|
}
|
|
};
|
|
let visit_post = |_: &Vec<usize>| {};
|
|
self.walk(visit_pre, visit_post);
|
|
result
|
|
}
|
|
|
|
pub fn lineal_descendant(&self, start: usize) -> impl Iterator<Item = &KEY> {
|
|
let mut nodes: Vec<usize> = vec![];
|
|
let mut node_option = Some(start);
|
|
while let Some(node) = node_option {
|
|
let key = &self.get_node(node).key;
|
|
if key.is_some() {
|
|
nodes.push(node);
|
|
}
|
|
node_option = self.get_node(node).parent;
|
|
}
|
|
nodes
|
|
.into_iter()
|
|
.rev()
|
|
.map(|node_index| self.get_node(node_index).key.as_ref().unwrap())
|
|
}
|
|
|
|
pub(crate) fn walk<CB1, CB2>(&self, mut visit_pre: CB1, mut visit_post: CB2)
|
|
where
|
|
CB1: FnMut(&Vec<usize>) -> VisitOutcome,
|
|
CB2: FnMut(&Vec<usize>),
|
|
{
|
|
let mut stack: Vec<(usize, Option<usize>)> = vec![];
|
|
let mut public_stack: Vec<usize> = vec![];
|
|
let root_node = self.get_node(0);
|
|
stack.push((0, root_node.child));
|
|
public_stack.push(0);
|
|
visit_pre(&public_stack);
|
|
while !stack.is_empty() {
|
|
let last = &mut stack.last_mut().unwrap();
|
|
match last.1 {
|
|
Some(child_node_id) => {
|
|
let child_node = self.get_node(child_node_id);
|
|
last.1 = child_node.next;
|
|
public_stack.push(child_node_id);
|
|
let visit_pre_outcome = visit_pre(&public_stack);
|
|
match visit_pre_outcome {
|
|
VisitOutcome::Continue => {
|
|
stack.push((child_node_id, child_node.child));
|
|
}
|
|
VisitOutcome::Skip => {
|
|
stack.push((child_node_id, None));
|
|
}
|
|
VisitOutcome::EarlyExit => return,
|
|
}
|
|
}
|
|
None => {
|
|
visit_post(&public_stack);
|
|
stack.pop();
|
|
public_stack.pop();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn tails(&self) -> &BTreeSet<usize> {
|
|
&self.tails
|
|
}
|
|
}
|