diff --git a/src/map.rs b/src/map.rs index c9d7983..11143c2 100644 --- a/src/map.rs +++ b/src/map.rs @@ -219,6 +219,32 @@ impl GenericPatriciaMap { Some((K::Borrowed::from_bytes(key), value)) } + /// Returns the longest common prefix length of `key` and the keys in this map. + /// + /// Unlike `get_longest_common_prefix()`, this method does not check if there is a key that matches the prefix in this map. + /// + /// # Examples + /// + /// ``` + /// use patricia_tree::PatriciaMap; + /// + /// let mut map = PatriciaMap::new(); + /// map.insert("foo", 1); + /// map.insert("foobar", 2); + /// assert_eq!(map.longest_common_prefix_len("fo"), 2); + /// assert_eq!(map.longest_common_prefix_len("foo"), 3); + /// assert_eq!(map.longest_common_prefix_len("fooba"), 5); + /// assert_eq!(map.longest_common_prefix_len("foobar"), 6); + /// assert_eq!(map.longest_common_prefix_len("foobarbaz"), 6); + /// assert_eq!(map.longest_common_prefix_len("foba"), 2); + /// ``` + pub fn longest_common_prefix_len(&self, key: &Q) -> usize + where + Q: ?Sized + AsRef, + { + self.tree.longest_common_prefix_len(key.as_ref()) + } + /// Inserts a key-value pair into this map. /// /// If the map did not have this key present, `None` is returned. diff --git a/src/node.rs b/src/node.rs index d28164b..56e622f 100644 --- a/src/node.rs +++ b/src/node.rs @@ -438,7 +438,29 @@ impl Node { None } } - + pub(crate) fn longest_common_prefix_len( + &self, + key: &K, + offset: usize, + ) -> usize { + let (next, common_prefix_len) = key.strip_common_prefix_and_len(self.label()); + let next_offset = offset + common_prefix_len; + if common_prefix_len == self.label().len() { + if next.is_empty() { + next_offset + } else { + self.child() + .map(|child| child.longest_common_prefix_len(next, next_offset)) + .unwrap_or(next_offset) + } + } else if common_prefix_len == 0 && key.cmp_first_item(self.label()).is_ge() { + self.sibling() + .map(|sibling| sibling.longest_common_prefix_len(next, offset)) + .unwrap_or(next_offset) + } else { + next_offset + } + } pub(crate) fn get_longest_common_prefix( &self, key: &K, diff --git a/src/set.rs b/src/set.rs index 9895637..b65877c 100644 --- a/src/set.rs +++ b/src/set.rs @@ -143,6 +143,32 @@ impl GenericPatriciaSet { self.map.get_longest_common_prefix(value).map(|x| x.0) } + /// Returns the longest common prefix length of `value` and the elements in this set. + /// + /// Unlike `get_longest_common_prefix()`, this method does not check if there is a element that matches the prefix in this set. + /// + /// # Examples + /// + /// ``` + /// use patricia_tree::PatriciaSet; + /// + /// let mut set = PatriciaSet::new(); + /// set.insert("foo"); + /// set.insert("foobar"); + /// assert_eq!(set.longest_common_prefix_len("fo"), 2); + /// assert_eq!(set.longest_common_prefix_len("foo"), 3); + /// assert_eq!(set.longest_common_prefix_len("fooba"), 5); + /// assert_eq!(set.longest_common_prefix_len("foobar"), 6); + /// assert_eq!(set.longest_common_prefix_len("foobarbaz"), 6); + /// assert_eq!(set.longest_common_prefix_len("foba"), 2); + /// ``` + pub fn longest_common_prefix_len(&self, value: &U) -> usize + where + U: ?Sized + AsRef, + { + self.map.longest_common_prefix_len(value) + } + /// Adds a value to this set. /// /// If the set did not have this value present, `true` is returned. diff --git a/src/tree.rs b/src/tree.rs index cf1457b..1600fed 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -38,6 +38,9 @@ impl PatriciaTree { pub fn get_mut(&mut self, key: &K) -> Option<&mut V> { self.root.get_mut(key) } + pub fn longest_common_prefix_len(&self, key: &K) -> usize { + self.root.longest_common_prefix_len(key, 0) + } pub fn get_longest_common_prefix<'a, K: ?Sized + BorrowedBytes>( &self, key: &'a K,