use std::collections::VecDeque;
use std::fmt;
use std::hash::Hash;
use std::marker::PhantomData;
use std::sync::Arc;
use crate::key_converter::KeyToBytes;
use crate::node::TrieNode;
use crate::util::prefix_match;
use crate::Trie;
#[derive(Clone)]
pub struct PrefixView<K: Clone + Hash + Eq, V, KC: KeyToBytes<K>> {
trie: Trie<K, V, KC>,
prefix: K,
subtrie_node: Option<Arc<TrieNode<K, V>>>,
_phantom_kc: PhantomData<KC>,
}
pub struct PrefixViewIter<K: Clone + Hash + Eq, V: Clone, KC: KeyToBytes<K>> {
stack: VecDeque<Arc<TrieNode<K, V>>>,
_phantom: PhantomData<KC>,
}
pub struct PrefixViewArcIter<K: Clone + Hash + Eq, V, KC: KeyToBytes<K> + Clone> {
stack: VecDeque<Arc<TrieNode<K, V>>>,
_phantom: PhantomData<KC>,
}
impl<K: Clone + Hash + Eq, V, KC: KeyToBytes<K>> PrefixView<K, V, KC>
where
V: Clone, KC: Clone, {
pub fn new(trie: Trie<K, V, KC>, prefix: K) -> Self {
let subtrie_node = Self::find_subtrie_node(&trie, &prefix);
PrefixView {
trie,
prefix,
subtrie_node,
_phantom_kc: PhantomData,
}
}
pub fn prefix(&self) -> &K {
&self.prefix
}
pub fn trie(&self) -> &Trie<K, V, KC> {
&self.trie
}
pub fn exists(&self) -> bool {
self.subtrie_node.is_some()
}
pub fn len(&self) -> usize {
match &self.subtrie_node {
Some(node) => node.subtree_size(),
None => 0,
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn contains_key(&self, key: &K) -> bool
where
K: Hash + Eq,
{
if !Self::key_starts_with_prefix(key, &self.prefix) {
return false;
}
self.trie.contains_key(key)
}
pub fn get(&self, key: &K) -> Option<&V>
where
K: Hash + Eq,
{
if !Self::key_starts_with_prefix(key, &self.prefix) {
return None;
}
self.trie.get(key)
}
pub fn iter(&self) -> PrefixViewIter<K, V, KC>
where
V: Clone,
{
let mut stack = VecDeque::new();
if let Some(node) = &self.subtrie_node {
stack.push_back(Arc::clone(node));
}
PrefixViewIter { stack, _phantom: PhantomData }
}
pub fn iter_arc(&self) -> PrefixViewArcIter<K, V, KC> {
let mut stack = VecDeque::new();
if let Some(node) = &self.subtrie_node {
stack.push_back(Arc::clone(node));
}
PrefixViewArcIter { stack, _phantom: PhantomData }
}
fn find_subtrie_node(trie: &Trie<K, V, KC>, prefix: &K) -> Option<Arc<TrieNode<K, V>>> {
let prefix_bytes = KC::convert(prefix);
let mut current = &trie.root;
let mut remaining = &prefix_bytes[..];
while !remaining.is_empty() {
let common_len = prefix_match(remaining, ¤t.key_fragment);
if common_len < current.key_fragment.len() {
if common_len == remaining.len() {
return Some(Arc::clone(current));
}
return None;
}
remaining = &remaining[common_len..];
if remaining.is_empty() {
return Some(Arc::clone(current));
}
let next_byte = remaining[0];
match current.children.get(&next_byte) {
Some(child) => {
current = child;
remaining = &remaining[1..];
}
None => return None,
}
}
Some(Arc::clone(current))
}
fn key_starts_with_prefix(key: &K, prefix: &K) -> bool {
let key_bytes = KC::convert(key);
let prefix_bytes = KC::convert(prefix);
if key_bytes.len() < prefix_bytes.len() {
return false;
}
for (i, &prefix_byte) in prefix_bytes.iter().enumerate() {
if key_bytes[i] != prefix_byte {
return false;
}
}
true
}
}
impl<K: Clone + Hash + Eq + fmt::Debug, V: fmt::Debug, KC: KeyToBytes<K> + fmt::Debug> fmt::Debug
for PrefixView<K, V, KC>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PrefixView")
.field("prefix", &self.prefix)
.field("trie_root_ptr", &Arc::as_ptr(&self.trie.root))
.field(
"subtrie_node_ptr",
&self.subtrie_node.as_ref().map(Arc::as_ptr),
)
.finish()
}
}
impl<K: Clone + Hash + Eq, V: Hash + Eq + Clone, KC: KeyToBytes<K>> PartialEq
for PrefixView<K, V, KC>
{
fn eq(&self, other: &Self) -> bool {
match (&self.subtrie_node, &other.subtrie_node) {
(None, None) => true,
(Some(_), None) | (None, Some(_)) => false,
(Some(self_node), Some(other_node)) => {
if Arc::ptr_eq(self_node, other_node) {
return true;
}
if self_node.hash() != other_node.hash() {
return false;
}
self_node.deep_eq(other_node)
}
}
}
}
impl<K: Clone + Hash + Eq, V: Hash + Eq + Clone, KC: KeyToBytes<K>> Eq for PrefixView<K, V, KC> {}
impl<K: Clone + Hash + Eq, V: Hash + Eq + Clone, KC: KeyToBytes<K>> std::hash::Hash
for PrefixView<K, V, KC>
{
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match &self.subtrie_node {
Some(node) => node.hash().hash(state),
None => 0u64.hash(state), }
}
}
impl<K: Clone + Hash + Eq, V: Clone, KC: KeyToBytes<K> + Clone> IntoIterator
for &PrefixView<K, V, KC>
{
type Item = (K, V);
type IntoIter = PrefixViewIter<K, V, KC>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<K: Clone + Hash + Eq, V: Clone, KC: KeyToBytes<K> + Clone> Iterator
for PrefixViewIter<K, V, KC>
{
type Item = (K, V);
fn next(&mut self) -> Option<Self::Item> {
while let Some(node) = self.stack.pop_front() {
for (_, child) in node.children.iter().rev() {
self.stack.push_front(Arc::clone(child));
}
if let Some(kvp) = &node.data {
return Some(((*kvp.key).clone(), (*kvp.value).clone()));
}
}
None
}
}
impl<K: Clone + Hash + Eq, V, KC: KeyToBytes<K>> Iterator for PrefixViewArcIter<K, V, KC> {
type Item = (Arc<K>, Arc<V>);
fn next(&mut self) -> Option<Self::Item> {
while let Some(node) = self.stack.pop_front() {
for (_, child) in node.children.iter().rev() {
self.stack.push_front(Arc::clone(child));
}
if let Some(kvp) = &node.data {
return Some((Arc::clone(&kvp.key), Arc::clone(&kvp.value)));
}
}
None
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::key_converter::StrKeyConverter;
use std::collections::HashSet;
#[test]
fn test_prefix_view_creation() {
let trie = Trie::<String, i32, StrKeyConverter<String>>::new_str_key()
.insert("hello".to_string(), 1)
.insert("help".to_string(), 2)
.insert("world".to_string(), 3);
let view = trie.view_subtrie("hel".to_string());
assert!(view.exists());
assert_eq!(view.prefix(), &"hel".to_string());
assert_eq!(view.len(), 2);
assert!(!view.is_empty());
}
#[test]
fn test_prefix_view_equality() {
let trie1 = Trie::<String, u32, StrKeyConverter<String>>::new_str_key()
.insert("hello".to_string(), 1)
.insert("help".to_string(), 2);
let trie2 = Trie::<String, u32, StrKeyConverter<String>>::new_str_key()
.insert("hello".to_string(), 1)
.insert("help".to_string(), 2);
let view1 = PrefixView::new(trie1.clone(), "hel".to_string());
let view2 = PrefixView::new(trie2.clone(), "hel".to_string());
assert_eq!(view1, view2);
let view3 = PrefixView::new(trie1.clone(), "he".to_string());
assert_eq!(view1, view3);
let trie3 = Trie::<String, u32, StrKeyConverter<String>>::new_str_key()
.insert("hello".to_string(), 99) .insert("help".to_string(), 2);
let view4 = PrefixView::new(trie3, "hel".to_string());
assert_ne!(view1, view4);
}
#[test]
fn test_prefix_view_exists() {
let trie = Trie::<String, u32, StrKeyConverter<String>>::new_str_key()
.insert("hello".to_string(), 1)
.insert("help".to_string(), 2);
let view1 = PrefixView::new(trie.clone(), "hel".to_string());
assert!(view1.exists());
let view2 = PrefixView::new(trie.clone(), "xyz".to_string());
assert!(!view2.exists());
}
#[test]
fn test_prefix_view_len() {
let trie = Trie::<String, u32, StrKeyConverter<String>>::new_str_key()
.insert("hello".to_string(), 1)
.insert("help".to_string(), 2)
.insert("world".to_string(), 3);
let view1 = PrefixView::new(trie.clone(), "hel".to_string());
assert_eq!(view1.len(), 2);
let view2 = PrefixView::new(trie.clone(), "hello".to_string());
assert_eq!(view2.len(), 1);
let view3 = PrefixView::new(trie.clone(), "xyz".to_string());
assert_eq!(view3.len(), 0);
assert!(view3.is_empty());
}
#[test]
fn test_prefix_view_get() {
let trie = Trie::<String, u32, StrKeyConverter<String>>::new_str_key()
.insert("hello".to_string(), 1)
.insert("help".to_string(), 2)
.insert("world".to_string(), 3);
let view = PrefixView::new(trie.clone(), "hel".to_string());
assert_eq!(view.get(&"hello".to_string()), Some(&1));
assert_eq!(view.get(&"help".to_string()), Some(&2));
assert_eq!(view.get(&"world".to_string()), None);
assert_eq!(view.get(&"he".to_string()), None);
}
#[test]
fn test_prefix_view_contains_key() {
let trie = Trie::<String, u32, StrKeyConverter<String>>::new_str_key()
.insert("hello".to_string(), 1)
.insert("help".to_string(), 2)
.insert("world".to_string(), 3);
let view = PrefixView::new(trie.clone(), "hel".to_string());
assert!(view.contains_key(&"hello".to_string()));
assert!(view.contains_key(&"help".to_string()));
assert!(!view.contains_key(&"world".to_string()));
assert!(!view.contains_key(&"he".to_string()));
}
#[test]
fn test_key_starts_with_prefix_helper() {
let view_prefix_k_hel = "hel".to_string();
let view_prefix_k_hello = "hello".to_string();
let view_prefix_k_help = "help".to_string();
let hello_string = "hello".to_string();
let he_string = "he".to_string();
assert!(
PrefixView::<String, u32, StrKeyConverter<String>>::key_starts_with_prefix(
&hello_string,
&view_prefix_k_hel
)
);
assert!(
PrefixView::<String, u32, StrKeyConverter<String>>::key_starts_with_prefix(
&hello_string,
&view_prefix_k_hello
)
);
assert!(
!PrefixView::<String, u32, StrKeyConverter<String>>::key_starts_with_prefix(
&hello_string,
&view_prefix_k_help
)
);
assert!(
!PrefixView::<String, u32, StrKeyConverter<String>>::key_starts_with_prefix(
&he_string,
&view_prefix_k_hel
)
);
let hello_string = "hello".to_string();
let hello_key_str = "hello".to_string();
let he_string = "he".to_string();
let help_string = "help".to_string();
assert!(
PrefixView::<String, u32, StrKeyConverter<String>>::key_starts_with_prefix(
&hello_string,
&view_prefix_k_hel
)
);
assert!(
PrefixView::<String, u32, StrKeyConverter<String>>::key_starts_with_prefix(
&hello_string,
&hello_key_str
)
);
assert!(
!PrefixView::<String, u32, StrKeyConverter<String>>::key_starts_with_prefix(
&hello_string,
&help_string
)
);
assert!(
!PrefixView::<String, u32, StrKeyConverter<String>>::key_starts_with_prefix(
&he_string,
&view_prefix_k_hel
)
);
}
#[test]
fn test_prefix_view_iter() {
let trie = Trie::<String, u32, StrKeyConverter<String>>::new_str_key()
.insert("hello".to_string(), 1)
.insert("help".to_string(), 2)
.insert("world".to_string(), 3);
let view = PrefixView::new(trie.clone(), "hel".to_string());
let results: HashSet<(String, u32)> = view.iter().collect();
let expected: HashSet<(String, u32)> =
vec![("hello".to_string(), 1), ("help".to_string(), 2)]
.into_iter()
.collect();
assert_eq!(results, expected);
let arc_results: Vec<(Arc<String>, Arc<u32>)> = view.iter_arc().collect();
assert_eq!(arc_results.len(), 2);
assert!(arc_results.iter().any(|(k, v)| **k == "hello" && **v == 1));
assert!(arc_results.iter().any(|(k, v)| **k == "help" && **v == 2));
let view2 = PrefixView::new(trie.clone(), "hello".to_string());
let results2: Vec<(String, u32)> = view2.iter().collect();
assert_eq!(results2.len(), 1);
assert_eq!(results2[0], ("hello".to_string(), 1));
let view3 = PrefixView::new(trie.clone(), "xyz".to_string());
let results3: Vec<(String, u32)> = view3.iter().collect();
assert!(results3.is_empty());
}
#[test]
fn test_prefix_view_iter_order() {
let trie = Trie::<String, u32, StrKeyConverter<String>>::new_str_key()
.insert("aa".to_string(), 1)
.insert("ab".to_string(), 2)
.insert("ac".to_string(), 3)
.insert("ba".to_string(), 4);
let view = PrefixView::new(trie.clone(), "a".to_string());
let results: Vec<(String, u32)> = view.iter().collect();
assert_eq!(results.len(), 3);
assert!(results.contains(&("aa".to_string(), 1)));
assert!(results.contains(&("ab".to_string(), 2)));
assert!(results.contains(&("ac".to_string(), 3)));
assert!(!results.contains(&("ba".to_string(), 4)));
let expected_a_results = vec![
("aa".to_string(), 1),
("ab".to_string(), 2),
("ac".to_string(), 3),
];
assert_eq!(results, expected_a_results);
let arc_results: Vec<(Arc<String>, Arc<u32>)> = view.iter_arc().collect();
assert_eq!(arc_results.len(), 3);
assert_eq!(*arc_results[0].0, "aa".to_string());
assert_eq!(*arc_results[1].0, "ab".to_string());
assert_eq!(*arc_results[2].0, "ac".to_string());
}
#[test]
fn test_prefix_view_len_uses_cache() {
let trie = Trie::<String, u32, StrKeyConverter<String>>::new_str_key()
.insert("hello".to_string(), 1)
.insert("help".to_string(), 2)
.insert("world".to_string(), 3);
let view = PrefixView::new(trie.clone(), "hel".to_string());
let node = view.subtrie_node.as_ref().unwrap();
assert!(node.cached_subtree_size.get().is_none());
assert_eq!(view.len(), 2);
assert_eq!(node.cached_subtree_size.get(), Some(&2));
assert_eq!(view.len(), 2);
}
}