Skip to content

Commit

Permalink
feature: Add inc_search_prefix.
Browse files Browse the repository at this point in the history
Dependent on louds-rs child_to_ancestors PR.
  • Loading branch information
shanecelis committed Apr 23, 2024
1 parent 35eb638 commit d5f433c
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 3 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ categories = ["compression", "data-structures"]
edition = "2021"

[dependencies]
louds-rs = "0.6"
# louds-rs = "0.6"
louds-rs = { path = "../louds-rs" }
mem_dbg = { version = "0.1.4", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }

Expand Down
34 changes: 33 additions & 1 deletion src/inc_search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@
//!
//! This means the above code restores the time complexity of _O(m log n)_ for
//! the loop.
use crate::map::Trie;
use crate::{
map::Trie,
try_collect::{TryCollect, TryFromIterator},
};
use louds_rs::LoudsNodeNum;

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -181,6 +184,18 @@ impl<'a, Label: Ord, Value> IncSearch<'a, Label, Value> {
self.trie.value(self.node)
}

/// Return the current prefix for this search.
pub fn prefix<C, M>(&self) -> C
where
C: TryFromIterator<Label, M>,
Label: Clone,
{
let mut v: Vec<Label> = self.trie.child_to_ancestors(self.node)
.map(|node| self.trie.label(node).clone()).collect();
v.reverse();
v.into_iter().try_collect().expect("Could not collect")
}

// This isn't actually possible.
// /// Return the mutable value at current node. There should be one for any
// /// node where `answer.is_match()` is true.
Expand Down Expand Up @@ -217,24 +232,38 @@ mod search_tests {
fn inc_search() {
let trie = build_trie();
let mut search = trie.inc_search();
assert_eq!("", search.prefix::<String, _>());
assert_eq!(None, search.query(&b'z'));
assert_eq!("", search.prefix::<String, _>());
assert_eq!(Answer::PrefixAndMatch, search.query(&b'a').unwrap());
assert_eq!("a", search.prefix::<String, _>());
assert_eq!(Answer::Prefix, search.query(&b'p').unwrap());
assert_eq!("ap", search.prefix::<String, _>());
assert_eq!(Answer::PrefixAndMatch, search.query(&b'p').unwrap());
assert_eq!("app", search.prefix::<String, _>());
assert_eq!(Answer::Prefix, search.query(&b'l').unwrap());
assert_eq!("appl", search.prefix::<String, _>());
assert_eq!(Answer::Match, search.query(&b'e').unwrap());
assert_eq!("apple", search.prefix::<String, _>());
}

#[test]
fn inc_search_value() {
let trie = build_trie();
let mut search = trie.inc_search();
assert_eq!("", search.prefix::<String, _>());
assert_eq!(None, search.query(&b'z'));
assert_eq!("", search.prefix::<String, _>());
assert_eq!(Answer::PrefixAndMatch, search.query(&b'a').unwrap());
assert_eq!("a", search.prefix::<String, _>());
assert_eq!(Answer::Prefix, search.query(&b'p').unwrap());
assert_eq!("ap", search.prefix::<String, _>());
assert_eq!(Answer::PrefixAndMatch, search.query(&b'p').unwrap());
assert_eq!("app", search.prefix::<String, _>());
assert_eq!(Answer::Prefix, search.query(&b'l').unwrap());
assert_eq!("appl", search.prefix::<String, _>());
assert_eq!(Answer::Match, search.query(&b'e').unwrap());
assert_eq!("apple", search.prefix::<String, _>());
assert_eq!(Some(&2), search.value());
}

Expand All @@ -243,10 +272,13 @@ mod search_tests {
let trie = build_trie();
let mut search = trie.inc_search();
assert_eq!(Err(0), search.query_until("zoo"));
assert_eq!("", search.prefix::<String, _>());
search.reset();
assert_eq!(Err(1), search.query_until("blue"));
assert_eq!("b", search.prefix::<String, _>());
search.reset();
assert_eq!(Answer::Match, search.query_until("apple").unwrap());
assert_eq!("apple", search.prefix::<String, _>());
assert_eq!(Some(&2), search.value());
}

Expand Down
6 changes: 5 additions & 1 deletion src/map/trie.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use super::Trie;
use crate::inc_search::IncSearch;
use crate::iter::{PostfixIter, PrefixIter, SearchIter};
use crate::try_collect::{TryCollect, TryFromIterator};
use louds_rs::{ChildNodeIter, LoudsNodeNum};
use louds_rs::{ChildNodeIter, LoudsNodeNum, AncestorNodeIter};
use std::iter::FromIterator;

impl<Label: Ord, Value> Trie<Label, Value> {
Expand Down Expand Up @@ -210,6 +210,10 @@ impl<Label: Ord, Value> Trie<Label, Value> {
pub(crate) fn value_mut(&mut self, node_num: LoudsNodeNum) -> Option<&mut Value> {
self.trie_labels[(node_num.0 - 2) as usize].value.as_mut()
}

pub (crate) fn child_to_ancestors(&self, node_num: LoudsNodeNum) -> AncestorNodeIter {
self.louds.child_to_ancestors(node_num)
}
}

impl<Label, Value, C> FromIterator<(C, Value)> for Trie<Label, Value>
Expand Down

0 comments on commit d5f433c

Please sign in to comment.