module refactor
This commit is contained in:
+251
@@ -0,0 +1,251 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::HashMap;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use super::keychecker::KeyChecker;
|
||||
use super::levtrie::DistanceCalculator;
|
||||
use super::result::Result;
|
||||
use super::trienode::TrieKey;
|
||||
use super::trienode::TrieNode;
|
||||
|
||||
pub enum VisitOutcome {
|
||||
Continue,
|
||||
Skip,
|
||||
EarlyExit,
|
||||
}
|
||||
|
||||
pub struct Trie<KEY, KEYCHECKER, PAYLOAD>
|
||||
where
|
||||
KEY: TrieKey,
|
||||
KEYCHECKER: KeyChecker<KEY>,
|
||||
{
|
||||
pub nodes: Vec<TrieNode<KEY, PAYLOAD>>,
|
||||
payload_initializer: fn() -> PAYLOAD,
|
||||
tails: BTreeSet<usize>,
|
||||
checker: PhantomData<KEYCHECKER>,
|
||||
}
|
||||
|
||||
impl<KEY, KEYCHECKER, PAYLOAD> Trie<KEY, KEYCHECKER, PAYLOAD>
|
||||
where
|
||||
KEY: TrieKey,
|
||||
KEYCHECKER: KeyChecker<KEY>,
|
||||
{
|
||||
pub fn empty(initializer: fn() -> PAYLOAD) -> Trie<KEY, KEYCHECKER, PAYLOAD> {
|
||||
Trie {
|
||||
nodes: vec![TrieNode::new0(None, initializer)],
|
||||
payload_initializer: initializer,
|
||||
tails: BTreeSet::new(),
|
||||
checker: PhantomData::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trie_from_words<T: IntoIterator, U: IntoIterator>(
|
||||
initializer: fn() -> PAYLOAD,
|
||||
wordlist: U,
|
||||
) -> Trie<KEY, KEYCHECKER, PAYLOAD>
|
||||
where
|
||||
T: IntoIterator<Item = KEY>,
|
||||
U: IntoIterator<Item = T>,
|
||||
{
|
||||
let mut result = Trie::empty(initializer);
|
||||
for word in wordlist {
|
||||
result.add(word);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn get_node_mut(&mut self, index: usize) -> &mut TrieNode<KEY, PAYLOAD> {
|
||||
&mut self.nodes[index]
|
||||
}
|
||||
|
||||
pub fn get_node(&self, index: usize) -> &TrieNode<KEY, PAYLOAD> {
|
||||
&self.nodes[index]
|
||||
}
|
||||
|
||||
pub 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, self.payload_initializer);
|
||||
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: IntoIterator>(&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;
|
||||
loop {
|
||||
match cnode {
|
||||
Some(cnode_index) => {
|
||||
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;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
loop {
|
||||
match node {
|
||||
Some(n) => {
|
||||
let current_node = self.get_node_mut(n);
|
||||
current_node.ref_count += 1;
|
||||
node = current_node.parent;
|
||||
}
|
||||
None => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
(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 = |stack: &Vec<usize>| {};
|
||||
self.walk(visit_pre, visit_post);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn lineal_descendant(&self, start: usize) -> Vec<&KEY> {
|
||||
let mut chars: Vec<&KEY> = vec![];
|
||||
let mut node_option = Some(start);
|
||||
loop {
|
||||
match node_option {
|
||||
Some(node) => {
|
||||
let key = &self.get_node(node).key;
|
||||
match key {
|
||||
Some(key) => {
|
||||
chars.push(key);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
node_option = self.get_node(node).parent;
|
||||
}
|
||||
None => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
chars.reverse();
|
||||
chars
|
||||
}
|
||||
|
||||
pub 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user