added basic unit tests
This commit is contained in:
+48
-69
@@ -1,9 +1,9 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
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,
|
||||
@@ -16,47 +16,49 @@ where
|
||||
KEY: TrieKey,
|
||||
KEYCHECKER: KeyChecker<KEY>,
|
||||
{
|
||||
pub (crate) nodes: Vec<TrieNode<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 empty() -> Trie<KEY, KEYCHECKER> {
|
||||
Trie {
|
||||
nodes: vec![TrieNode::new0(None)],
|
||||
tails: BTreeSet::new(),
|
||||
checker: PhantomData::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trie_from_words<T: IntoIterator, U: IntoIterator>(
|
||||
wordlist: U,
|
||||
) -> Trie<KEY, KEYCHECKER>
|
||||
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::empty();
|
||||
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> {
|
||||
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> {
|
||||
pub(crate) fn get_node(&self, index: usize) -> &TrieNode<KEY> {
|
||||
&self.nodes[index]
|
||||
}
|
||||
|
||||
pub (crate) fn nodes(&self) -> usize {
|
||||
pub(crate) fn nodes(&self) -> usize {
|
||||
self.nodes.len()
|
||||
}
|
||||
|
||||
@@ -98,7 +100,7 @@ where
|
||||
result_index
|
||||
}
|
||||
|
||||
pub fn add<T: IntoIterator>(&mut self, path: T) -> (bool, usize)
|
||||
pub fn add<T>(&mut self, path: T) -> (bool, usize)
|
||||
where
|
||||
T: IntoIterator<Item = KEY>,
|
||||
{
|
||||
@@ -106,22 +108,15 @@ where
|
||||
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;
|
||||
}
|
||||
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);
|
||||
@@ -131,17 +126,10 @@ where
|
||||
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;
|
||||
}
|
||||
}
|
||||
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 {
|
||||
@@ -177,31 +165,23 @@ where
|
||||
result
|
||||
}
|
||||
|
||||
pub fn lineal_descendant(&self, start: usize) -> Vec<&KEY> {
|
||||
let mut chars: Vec<&KEY> = vec![];
|
||||
pub fn lineal_descendant(&self, start: usize) -> impl Iterator<Item = &KEY> {
|
||||
let mut nodes: Vec<usize> = 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
chars.reverse();
|
||||
chars
|
||||
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)
|
||||
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>),
|
||||
@@ -243,4 +223,3 @@ where
|
||||
&self.tails
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user