Skip to content

Commit 82e8246

Browse files
committed
Fix #40 (ugly code)
1 parent cb31e35 commit 82e8246

File tree

5 files changed

+212
-16
lines changed

5 files changed

+212
-16
lines changed

src/node.rs

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,16 @@ impl<K: Borrow<[u8]>, V> Branch<K, V> {
7676
self.entries.contains(index)
7777
}
7878

79+
/// Corresponds to the key-value pair at this position.
80+
#[inline]
81+
pub fn head_entry(&self) -> Option<&Leaf<K, V>> {
82+
match self.entries.get(0) {
83+
Some(Node::Leaf(leaf)) => Some(leaf),
84+
None => None,
85+
_ => unsafe { debug_unreachable!() },
86+
}
87+
}
88+
7989
#[inline]
8090
pub fn entry_mut(&mut self, index: u8) -> &mut Node<K, V> {
8191
let entry = self.entries.get_mut(index);
@@ -89,6 +99,13 @@ impl<K: Borrow<[u8]>, V> Branch<K, V> {
8999
self.entries.get(nybble_index(self.choice, key))
90100
}
91101

102+
// Get the child node corresponding to the given key.
103+
#[inline]
104+
pub fn child_with_offsetted_key(&self, key: &[u8], key_offset: usize) -> Option<&Node<K, V>> {
105+
self.entries
106+
.get(nybble_index(self.choice.checked_sub(key_offset * 2)?, key))
107+
}
108+
92109
// Mutable version of `Branch::child`.
93110
#[inline]
94111
pub fn child_mut(&mut self, key: &[u8]) -> Option<&mut Node<K, V>> {
@@ -119,6 +136,18 @@ impl<K: Borrow<[u8]>, V> Branch<K, V> {
119136
self.entries.get_or_any(nybble_index(self.choice, key))
120137
}
121138

139+
// Retrieve the node which contains the exemplar. This does not recurse and return the actual
140+
// exemplar - just the node which might be or contain it.
141+
#[inline]
142+
pub fn exemplar_with_offset(&self, key: &[u8], key_offset: usize) -> &Node<K, V> {
143+
self.entries.get_or_any(
144+
self.choice
145+
.checked_sub(key_offset * 2)
146+
.map(|choice| nybble_index(choice, key))
147+
.unwrap_or_default(),
148+
)
149+
}
150+
122151
// As `Branch::exemplar` but for mutable borrows.
123152
#[inline]
124153
pub fn exemplar_mut(&mut self, key: &[u8]) -> &mut Node<K, V> {
@@ -132,6 +161,12 @@ impl<K: Borrow<[u8]>, V> Branch<K, V> {
132161
self.exemplar(key).get_exemplar(key)
133162
}
134163

164+
#[inline]
165+
pub fn get_exemplar_with_offset(&self, key: &[u8], key_offset: usize) -> &Leaf<K, V> {
166+
self.exemplar_with_offset(key, key_offset)
167+
.get_exemplar_with_offset(key, key_offset)
168+
}
169+
135170
// Mutably borrow the exemplar for the given key, mutually recursing through
136171
// `Node::get_exemplar_mut`.
137172
#[inline]
@@ -307,6 +342,13 @@ impl<K: Borrow<[u8]>, V> Node<K, V> {
307342
}
308343
}
309344

345+
pub fn get_exemplar_with_offset(&self, key: &[u8], key_offset: usize) -> &Leaf<K, V> {
346+
match *self {
347+
Node::Leaf(ref leaf) => leaf,
348+
Node::Branch(ref branch) => branch.get_exemplar_with_offset(key, key_offset),
349+
}
350+
}
351+
310352
// Mutably borrow the exemplar for a given key.
311353
pub fn get_exemplar_mut(&mut self, key: &[u8]) -> &mut Leaf<K, V> {
312354
match *self {
@@ -320,19 +362,23 @@ impl<K: Borrow<[u8]>, V> Node<K, V> {
320362
//
321363
// PRECONDITION:
322364
// - There exists at least one node in the trie with the given prefix.
323-
pub fn get_prefix_validated<'a>(&'a self, prefix: &[u8]) -> &'a Node<K, V> {
365+
pub fn get_prefix_validated<'a>(
366+
&'a self,
367+
prefix: &[u8],
368+
prefix_offset: usize,
369+
) -> &'a Node<K, V> {
324370
match *self {
325371
Node::Leaf(..) => self,
326372
Node::Branch(ref branch) => {
327-
if branch.choice >= prefix.len() * 2 {
373+
if branch.choice >= (prefix.len() + prefix_offset) * 2 {
328374
self
329375
} else {
330-
let child_opt = branch.child(prefix);
376+
let child_opt = branch.child_with_offsetted_key(prefix, prefix_offset);
331377

332378
// unsafe: child must exist in the trie - prefix'd nodes must exist.
333379
let child = unsafe { child_opt.unwrap_unchecked() };
334380

335-
child.get_prefix_validated(prefix)
381+
child.get_prefix_validated(prefix, prefix_offset)
336382
}
337383
}
338384
}
@@ -346,7 +392,31 @@ impl<K: Borrow<[u8]>, V> Node<K, V> {
346392
Node::Branch(ref branch)
347393
if branch.get_exemplar(prefix).key_slice().starts_with(prefix) =>
348394
{
349-
Some(self.get_prefix_validated(prefix))
395+
Some(self.get_prefix_validated(prefix, 0))
396+
}
397+
398+
_ => None,
399+
}
400+
}
401+
402+
// Borrow the node which contains all and only entries with keys continuing with
403+
// `prefix`.
404+
pub fn get_prefix_with_offset<'a>(
405+
&'a self,
406+
prefix: &[u8],
407+
prefix_offset: usize,
408+
) -> Option<&'a Node<K, V>> {
409+
match *self {
410+
Node::Leaf(ref leaf) if leaf.key_slice()[prefix_offset..].starts_with(prefix) => {
411+
Some(self)
412+
}
413+
Node::Branch(ref branch)
414+
if branch
415+
.get_exemplar_with_offset(prefix, prefix_offset)
416+
.key_slice()[prefix_offset..]
417+
.starts_with(prefix) =>
418+
{
419+
Some(self.get_prefix_validated(prefix, prefix_offset))
350420
}
351421

352422
_ => None,

src/subtrie.rs

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ use crate::iter::Iter;
66
use crate::node::Node;
77

88
pub struct SubTrie<'a, K: 'a, V: 'a> {
9-
pub(crate) root: Option<&'a Node<K, V>>,
9+
/// The index of the next byte to compare.
10+
key_byte_index: usize,
11+
root: Option<&'a Node<K, V>>,
1012
}
1113

1214
impl<'a, K: fmt::Debug, V: fmt::Debug> fmt::Debug for SubTrie<'a, K, V> {
@@ -28,6 +30,17 @@ impl<'a, K: 'a, V: 'a> IntoIterator for SubTrie<'a, K, V> {
2830
}
2931

3032
impl<'a, K: 'a, V: 'a> SubTrie<'a, K, V> {
33+
pub fn new(root: Option<&'a Node<K, V>>, key_byte_index: usize) -> SubTrie<'a, K, V> {
34+
SubTrie {
35+
key_byte_index,
36+
root,
37+
}
38+
}
39+
40+
pub fn empty() -> SubTrie<'a, K, V> {
41+
SubTrie::new(None, 0)
42+
}
43+
3144
/// Returns true if the subtrie has no entries.
3245
pub fn is_empty(&self) -> bool {
3346
self.root.is_none()
@@ -49,10 +62,41 @@ impl<'a, K: Borrow<[u8]>, V> SubTrie<'a, K, V> {
4962
}
5063
}
5164

52-
pub fn subtrie<L: Borrow<[u8]>>(&self, prefix: L) -> SubTrie<'a, K, V> {
53-
SubTrie {
54-
root: self.root.and_then(|node| node.get_prefix(prefix.borrow())),
55-
}
65+
/// Takes the next step in the trie, returning a new subtrie.
66+
pub fn subtrie<L: Borrow<[u8]>>(&self, next_key_part: L) -> SubTrie<'a, K, V> {
67+
let root = match self.root {
68+
Some(node) => node,
69+
None => return SubTrie::empty(),
70+
};
71+
let node = root.get_prefix_with_offset(next_key_part.borrow(), self.key_byte_index);
72+
SubTrie::new(node, self.key_byte_index + next_key_part.borrow().len())
73+
}
74+
75+
/// Gets the value at the root of the subtrie.
76+
pub fn get_value(&self) -> Option<&'a V> {
77+
self.root
78+
.and_then(|node| match node {
79+
Node::Leaf(leaf) => Some(leaf),
80+
Node::Branch(v) => v.head_entry(),
81+
})
82+
.and_then(|leaf| {
83+
if self.key_byte_index == leaf.key.borrow().len() {
84+
Some(&leaf.val)
85+
} else {
86+
None
87+
}
88+
})
89+
}
90+
91+
/// Gets a subtrie rooted at the given prefix.
92+
/// Is slightly less efficient than `subtrie`, since it re-compares the prefix.
93+
pub fn subtrie_with_prefix<L: Borrow<[u8]>>(&self, prefix: L) -> SubTrie<'a, K, V> {
94+
let root = match self.root {
95+
Some(node) => node,
96+
None => return SubTrie::empty(),
97+
};
98+
let node = root.get_prefix(prefix.borrow());
99+
SubTrie::new(node, prefix.borrow().len())
56100
}
57101

58102
pub fn get<L: Borrow<[u8]>>(&self, key: L) -> Option<&'a V> {

src/trie.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -226,12 +226,12 @@ impl<K: Borrow<[u8]>, V> Trie<K, V> {
226226
K: Borrow<Q>,
227227
Q: Borrow<[u8]>,
228228
{
229-
SubTrie {
230-
root: self
231-
.root
232-
.as_ref()
233-
.and_then(|node| node.get_prefix(prefix.borrow())),
234-
}
229+
let root = match self.root {
230+
Some(ref node) => node,
231+
None => return SubTrie::empty(),
232+
};
233+
let node = root.get_prefix(prefix.borrow());
234+
SubTrie::new(node, prefix.borrow().len())
235235
}
236236

237237
/// Get the longest common prefix of all the nodes in the trie and the given key.

src/wrapper.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ impl Break for BString {
9090
#[derive(PartialEq, Eq, PartialOrd, Ord)]
9191
pub struct BStr(str);
9292

93+
impl BStr {
94+
#[inline]
95+
pub fn ref_str(s: &str) -> &BStr {
96+
<&BStr>::from(s)
97+
}
98+
}
99+
93100
impl fmt::Debug for BStr {
94101
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95102
self.0.fmt(f)
@@ -118,6 +125,13 @@ impl Borrow<[u8]> for BStr {
118125
}
119126
}
120127

128+
impl Borrow<[u8]> for &'_ BStr {
129+
#[inline]
130+
fn borrow(&self) -> &[u8] {
131+
self.0.as_bytes()
132+
}
133+
}
134+
121135
#[allow(clippy::derived_hash_with_manual_eq)]
122136
impl Hash for BStr {
123137
#[inline]

tests/lib.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,3 +498,71 @@ fn issue_36_node_count_after_clear() {
498498
trie.clear();
499499
assert_eq!(0, trie.count());
500500
}
501+
502+
#[test]
503+
fn issue_40_subtree_api_extension_base() {
504+
use wrapper::{BStr, BString};
505+
506+
let mut trie = Trie::<BString, u32>::new();
507+
trie.insert("abc".into(), 1);
508+
trie.insert("a".into(), 99);
509+
trie.insert("abcd".into(), 2);
510+
trie.insert("abcde".into(), 3);
511+
assert_eq!(
512+
trie.subtrie(BStr::ref_str("abc")).get(BStr::ref_str("abc")),
513+
Some(&1)
514+
);
515+
assert_eq!(
516+
trie.subtrie(BStr::ref_str("abc"))
517+
.get(BStr::ref_str("abcd")),
518+
Some(&2)
519+
);
520+
assert_eq!(
521+
trie.subtrie(BStr::ref_str("abcd"))
522+
.get(BStr::ref_str("abc")),
523+
None
524+
);
525+
assert_eq!(
526+
trie.subtrie(BStr::ref_str("abcd"))
527+
.get(BStr::ref_str("abcd")),
528+
Some(&2)
529+
);
530+
assert_eq!(
531+
trie.subtrie(BStr::ref_str("abcde"))
532+
.get(BStr::ref_str("abcde")),
533+
Some(&3)
534+
);
535+
assert_eq!(trie.subtrie(BStr::ref_str("abcde")).is_empty(), false);
536+
assert_eq!(trie.subtrie(BStr::ref_str("abcdef")).is_empty(), true);
537+
}
538+
539+
#[test]
540+
fn issue_40_subtree_api_extension_step() {
541+
use wrapper::{BStr, BString};
542+
543+
let mut trie = Trie::<BString, u32>::new();
544+
trie.insert("abc".into(), 1);
545+
trie.insert("a".into(), 99);
546+
trie.insert("abcd".into(), 2);
547+
trie.insert("abcde".into(), 3);
548+
assert_eq!(trie.subtrie(BStr::ref_str("a")).get_value(), Some(&99));
549+
assert_eq!(
550+
trie.subtrie(BStr::ref_str("a"))
551+
.subtrie(BStr::ref_str("b"))
552+
.get_value(),
553+
None
554+
);
555+
assert_eq!(
556+
trie.subtrie(BStr::ref_str("a"))
557+
.subtrie(BStr::ref_str("bcd"))
558+
.get_value(),
559+
Some(&2)
560+
);
561+
assert_eq!(
562+
trie.subtrie(BStr::ref_str("a"))
563+
.subtrie(BStr::ref_str("b"))
564+
.subtrie(BStr::ref_str("c"))
565+
.get(BStr::ref_str("abcd")),
566+
Some(&2)
567+
);
568+
}

0 commit comments

Comments
 (0)