1 //! A path from the root of a B+-tree to a leaf node.
2 
3 use super::node::Removed;
4 use super::{Comparator, Forest, MAX_PATH, Node, NodeData, NodePool, slice_insert, slice_shift};
5 use core::borrow::Borrow;
6 use core::marker::PhantomData;
7 use wasmtime_core::error::OutOfMemory;
8 
9 #[cfg(test)]
10 use core::fmt;
11 
12 pub(super) struct Path<F: Forest> {
13     /// Number of path entries including the root and leaf nodes.
14     size: usize,
15 
16     /// Path of node references from the root to a leaf node.
17     node: [Node; MAX_PATH],
18 
19     /// Entry number in each node.
20     entry: [u8; MAX_PATH],
21 
22     unused: PhantomData<F>,
23 }
24 
25 impl<F: Forest> Default for Path<F> {
default() -> Self26     fn default() -> Self {
27         Self {
28             size: 0,
29             node: [Node(0); MAX_PATH],
30             entry: [0; MAX_PATH],
31             unused: PhantomData,
32         }
33     }
34 }
35 
36 impl<F: Forest> Path<F> {
37     /// Reset path by searching for `key` starting from `root`.
38     ///
39     /// If `key` is in the tree, returns the corresponding value and leaved the path pointing at
40     /// the entry. Otherwise returns `None` and:
41     ///
42     /// - A key smaller than all stored keys returns a path to the first entry of the first leaf.
43     /// - A key larger than all stored keys returns a path to one beyond the last element of the
44     ///   last leaf.
45     /// - A key between the stored keys of adjacent leaf nodes returns a path to one beyond the
46     ///   last entry of the first of the leaf nodes.
47     ///
find( &mut self, key: F::Key, root: Node, pool: &NodePool<F>, comp: &dyn Comparator<F::Key>, ) -> Option<F::Value>48     pub fn find(
49         &mut self,
50         key: F::Key,
51         root: Node,
52         pool: &NodePool<F>,
53         comp: &dyn Comparator<F::Key>,
54     ) -> Option<F::Value> {
55         let mut node = root;
56         for level in 0.. {
57             self.size = level + 1;
58             self.node[level] = node;
59             match pool[node] {
60                 NodeData::Inner { size, keys, tree } => {
61                     // Invariant: `tree[i]` contains keys smaller than
62                     // `keys[i]`, greater or equal to `keys[i-1]`.
63                     let i = match comp.search(key, &keys[0..size.into()]) {
64                         // We hit an existing key, so follow the >= branch.
65                         Ok(i) => i + 1,
66                         // Key is less than `keys[i]`, so follow the < branch.
67                         Err(i) => i,
68                     };
69                     self.entry[level] = i as u8;
70                     node = tree[i];
71                 }
72                 NodeData::Leaf { size, keys, vals } => {
73                     // For a leaf we want either the found key or an insert position.
74                     return match comp.search(key, &keys.borrow()[0..size.into()]) {
75                         Ok(i) => {
76                             self.entry[level] = i as u8;
77                             Some(vals.borrow()[i])
78                         }
79                         Err(i) => {
80                             self.entry[level] = i as u8;
81                             None
82                         }
83                     };
84                 }
85                 NodeData::Free { .. } => panic!("Free {} reached from {}", node, root),
86             }
87         }
88         unreachable!();
89     }
90 
91     /// Move path to the first entry of the tree starting at `root` and return it.
first(&mut self, root: Node, pool: &NodePool<F>) -> (F::Key, F::Value)92     pub fn first(&mut self, root: Node, pool: &NodePool<F>) -> (F::Key, F::Value) {
93         let mut node = root;
94         for level in 0.. {
95             self.size = level + 1;
96             self.node[level] = node;
97             self.entry[level] = 0;
98             match pool[node] {
99                 NodeData::Inner { tree, .. } => node = tree[0],
100                 NodeData::Leaf { keys, vals, .. } => return (keys.borrow()[0], vals.borrow()[0]),
101                 NodeData::Free { .. } => panic!("Free {} reached from {}", node, root),
102             }
103         }
104         unreachable!();
105     }
106 
107     /// Move this path to the next key-value pair and return it.
next(&mut self, pool: &NodePool<F>) -> Option<(F::Key, F::Value)>108     pub fn next(&mut self, pool: &NodePool<F>) -> Option<(F::Key, F::Value)> {
109         match self.leaf_pos() {
110             None => return None,
111             Some((node, entry)) => {
112                 let (keys, vals) = pool[node].unwrap_leaf();
113                 if entry + 1 < keys.len() {
114                     self.entry[self.size - 1] += 1;
115                     return Some((keys[entry + 1], vals[entry + 1]));
116                 }
117             }
118         }
119 
120         // The current leaf node is exhausted. Move to the next one.
121         let leaf_level = self.size - 1;
122         self.next_node(leaf_level, pool).map(|node| {
123             let (keys, vals) = pool[node].unwrap_leaf();
124             (keys[0], vals[0])
125         })
126     }
127 
128     /// Move this path to the previous key-value pair and return it.
129     ///
130     /// If the path is at the off-the-end position, go to the last key-value pair.
131     ///
132     /// If the path is already at the first key-value pair, leave it there and return `None`.
prev(&mut self, root: Node, pool: &NodePool<F>) -> Option<(F::Key, F::Value)>133     pub fn prev(&mut self, root: Node, pool: &NodePool<F>) -> Option<(F::Key, F::Value)> {
134         // We use `size == 0` as a generic off-the-end position.
135         if self.size == 0 {
136             self.goto_subtree_last(0, root, pool);
137             let (node, entry) = self.leaf_pos().unwrap();
138             let (keys, vals) = pool[node].unwrap_leaf();
139             return Some((keys[entry], vals[entry]));
140         }
141 
142         match self.leaf_pos() {
143             None => return None,
144             Some((node, entry)) => {
145                 if entry > 0 {
146                     self.entry[self.size - 1] -= 1;
147                     let (keys, vals) = pool[node].unwrap_leaf();
148                     return Some((keys[entry - 1], vals[entry - 1]));
149                 }
150             }
151         }
152 
153         // The current leaf node is exhausted. Move to the previous one.
154         self.prev_leaf(pool).map(|node| {
155             let (keys, vals) = pool[node].unwrap_leaf();
156             let e = self.leaf_entry();
157             (keys[e], vals[e])
158         })
159     }
160 
161     /// Move path to the first entry of the next node at level, if one exists.
162     ///
163     /// Returns the new node if it exists.
164     ///
165     /// Reset the path to `size = 0` and return `None` if there is no next node.
next_node(&mut self, level: usize, pool: &NodePool<F>) -> Option<Node>166     fn next_node(&mut self, level: usize, pool: &NodePool<F>) -> Option<Node> {
167         match self.right_sibling_branch_level(level, pool) {
168             None => {
169                 self.size = 0;
170                 None
171             }
172             Some(bl) => {
173                 let (_, bnodes) = pool[self.node[bl]].unwrap_inner();
174                 self.entry[bl] += 1;
175                 let mut node = bnodes[usize::from(self.entry[bl])];
176 
177                 for l in bl + 1..level {
178                     self.node[l] = node;
179                     self.entry[l] = 0;
180                     node = pool[node].unwrap_inner().1[0];
181                 }
182 
183                 self.node[level] = node;
184                 self.entry[level] = 0;
185                 Some(node)
186             }
187         }
188     }
189 
190     /// Move the path to the last entry of the previous leaf node, if one exists.
191     ///
192     /// Returns the new leaf node if it exists.
193     ///
194     /// Leave the path unchanged and returns `None` if we are already at the first leaf node.
prev_leaf(&mut self, pool: &NodePool<F>) -> Option<Node>195     fn prev_leaf(&mut self, pool: &NodePool<F>) -> Option<Node> {
196         self.left_sibling_branch_level(self.size - 1).map(|bl| {
197             let entry = self.entry[bl] - 1;
198             self.entry[bl] = entry;
199             let (_, bnodes) = pool[self.node[bl]].unwrap_inner();
200             self.goto_subtree_last(bl + 1, bnodes[usize::from(entry)], pool)
201         })
202     }
203 
204     /// Move this path to the last position for the sub-tree at `level, root`.
goto_subtree_last(&mut self, level: usize, root: Node, pool: &NodePool<F>) -> Node205     fn goto_subtree_last(&mut self, level: usize, root: Node, pool: &NodePool<F>) -> Node {
206         let mut node = root;
207         for l in level.. {
208             self.node[l] = node;
209             match pool[node] {
210                 NodeData::Inner { size, ref tree, .. } => {
211                     self.entry[l] = size;
212                     node = tree[usize::from(size)];
213                 }
214                 NodeData::Leaf { size, .. } => {
215                     self.entry[l] = size - 1;
216                     self.size = l + 1;
217                     break;
218                 }
219                 NodeData::Free { .. } => panic!("Free {} reached from {}", node, root),
220             }
221         }
222         node
223     }
224 
225     /// Set the root node and point the path at the first entry of the node.
set_root_node(&mut self, root: Node)226     pub fn set_root_node(&mut self, root: Node) {
227         self.size = 1;
228         self.node[0] = root;
229         self.entry[0] = 0;
230     }
231 
232     /// Get the current leaf node and entry, if any.
leaf_pos(&self) -> Option<(Node, usize)>233     pub fn leaf_pos(&self) -> Option<(Node, usize)> {
234         let i = self.size.wrapping_sub(1);
235         self.node.get(i).map(|&n| (n, self.entry[i].into()))
236     }
237 
238     /// Get the current leaf node.
leaf_node(&self) -> Node239     fn leaf_node(&self) -> Node {
240         self.node[self.size - 1]
241     }
242 
243     /// Get the current entry in the leaf node.
leaf_entry(&self) -> usize244     fn leaf_entry(&self) -> usize {
245         self.entry[self.size - 1].into()
246     }
247 
248     /// Is this path pointing to the first entry in the tree?
249     /// This corresponds to the smallest key.
at_first_entry(&self) -> bool250     fn at_first_entry(&self) -> bool {
251         self.entry[0..self.size].iter().all(|&i| i == 0)
252     }
253 
254     /// Get a mutable reference to the current value.
255     /// This assumes that there is a current value.
value_mut<'a>(&self, pool: &'a mut NodePool<F>) -> &'a mut F::Value256     pub fn value_mut<'a>(&self, pool: &'a mut NodePool<F>) -> &'a mut F::Value {
257         &mut pool[self.leaf_node()].unwrap_leaf_mut().1[self.leaf_entry()]
258     }
259 
260     /// Insert the key-value pair at the current position.
261     /// The current position must be the correct insertion location for the key.
262     /// This function does not check for duplicate keys. Use `find` or similar for that.
263     /// Returns the new root node.
insert( &mut self, key: F::Key, value: F::Value, pool: &mut NodePool<F>, ) -> Result<Node, OutOfMemory>264     pub fn insert(
265         &mut self,
266         key: F::Key,
267         value: F::Value,
268         pool: &mut NodePool<F>,
269     ) -> Result<Node, OutOfMemory> {
270         if !self.try_leaf_insert(key, value, pool) {
271             self.split_and_insert(key, value, pool)?;
272         }
273         Ok(self.node[0])
274     }
275 
276     /// Try to insert `key, value` at the current position, but fail and return false if the leaf
277     /// node is full.
try_leaf_insert(&self, key: F::Key, value: F::Value, pool: &mut NodePool<F>) -> bool278     fn try_leaf_insert(&self, key: F::Key, value: F::Value, pool: &mut NodePool<F>) -> bool {
279         let index = self.leaf_entry();
280 
281         // The case `index == 0` should only ever happen when there are no earlier leaf nodes,
282         // otherwise we should have appended to the previous leaf node instead. This invariant
283         // means that we don't need to update keys stored in inner nodes here.
284         debug_assert!(index > 0 || self.at_first_entry());
285 
286         pool[self.leaf_node()].try_leaf_insert(index, key, value)
287     }
288 
289     /// Split the current leaf node and then insert `key, value`.
290     /// This should only be used if `try_leaf_insert()` fails.
split_and_insert( &mut self, mut key: F::Key, value: F::Value, pool: &mut NodePool<F>, ) -> Result<(), OutOfMemory>291     fn split_and_insert(
292         &mut self,
293         mut key: F::Key,
294         value: F::Value,
295         pool: &mut NodePool<F>,
296     ) -> Result<(), OutOfMemory> {
297         let orig_root = self.node[0];
298 
299         // Loop invariant: We need to split the node at `level` and then retry a failed insertion.
300         // The items to insert are either `(key, ins_node)` or `(key, value)`.
301         let mut ins_node = None;
302         let mut split;
303         for level in (0..self.size).rev() {
304             // Split the current node.
305             let mut node = self.node[level];
306             let mut entry = self.entry[level].into();
307             split = pool[node].split(entry);
308             let rhs_node = pool.alloc_node(split.rhs_data)?;
309 
310             // Should the path be moved to the new RHS node?
311             // Prefer the smaller node if we're right in the middle.
312             // Prefer to append to LHS all other things being equal.
313             //
314             // When inserting into an inner node (`ins_node.is_some()`), we must point to a valid
315             // entry in the current node since the new entry is inserted *after* the insert
316             // location.
317             if entry > split.lhs_entries
318                 || (entry == split.lhs_entries
319                     && (split.lhs_entries > split.rhs_entries || ins_node.is_some()))
320             {
321                 node = rhs_node;
322                 entry -= split.lhs_entries;
323                 self.node[level] = node;
324                 self.entry[level] = entry as u8;
325             }
326 
327             // Now that we have a not-full node, it must be possible to insert.
328             match ins_node {
329                 None => {
330                     let inserted = pool[node].try_leaf_insert(entry, key, value);
331                     debug_assert!(inserted);
332                     // If we inserted at the front of the new rhs_node leaf, we need to propagate
333                     // the inserted key as the critical key instead of the previous front key.
334                     if entry == 0 && node == rhs_node {
335                         split.crit_key = key;
336                     }
337                 }
338                 Some(n) => {
339                     let inserted = pool[node].try_inner_insert(entry, key, n);
340                     debug_assert!(inserted);
341                     // The lower level was moved to the new RHS node, so make sure that is
342                     // reflected here.
343                     if n == self.node[level + 1] {
344                         self.entry[level] += 1;
345                     }
346                 }
347             }
348 
349             // We are now done with the current level, but `rhs_node` must be inserted in the inner
350             // node above us. If we're already at level 0, the root node needs to be split.
351             key = split.crit_key;
352             ins_node = Some(rhs_node);
353             if level > 0 {
354                 let pnode = &mut pool[self.node[level - 1]];
355                 let pentry = self.entry[level - 1].into();
356                 if pnode.try_inner_insert(pentry, key, rhs_node) {
357                     // If this level level was moved to the new RHS node, update parent entry.
358                     if node == rhs_node {
359                         self.entry[level - 1] += 1;
360                     }
361                     return Ok(());
362                 }
363             }
364         }
365 
366         // If we get here we have split the original root node and need to add an extra level.
367         let rhs_node = ins_node.expect("empty path");
368         let root = pool.alloc_node(NodeData::inner(orig_root, key, rhs_node))?;
369         let entry = if self.node[0] == rhs_node { 1 } else { 0 };
370         self.size += 1;
371         slice_insert(&mut self.node[0..self.size], 0, root);
372         slice_insert(&mut self.entry[0..self.size], 0, entry);
373         Ok(())
374     }
375 
376     /// Remove the key-value pair at the current position and advance the path to the next
377     /// key-value pair, leaving the path in a normalized state.
378     ///
379     /// Return the new root node.
remove(&mut self, pool: &mut NodePool<F>) -> Option<Node>380     pub fn remove(&mut self, pool: &mut NodePool<F>) -> Option<Node> {
381         let e = self.leaf_entry();
382         match pool[self.leaf_node()].leaf_remove(e) {
383             Removed::Healthy => {
384                 if e == 0 {
385                     self.update_crit_key(pool)
386                 }
387                 Some(self.node[0])
388             }
389             status => self.balance_nodes(status, pool),
390         }
391     }
392 
393     /// Get the critical key for the current node at `level`.
394     ///
395     /// The critical key is less than or equal to all keys in the sub-tree at `level` and greater
396     /// than all keys to the left of the current node at `level`.
397     ///
398     /// The left-most node at any level does not have a critical key.
current_crit_key(&self, level: usize, pool: &NodePool<F>) -> Option<F::Key>399     fn current_crit_key(&self, level: usize, pool: &NodePool<F>) -> Option<F::Key> {
400         // Find the level containing the critical key for the current node.
401         self.left_sibling_branch_level(level).map(|bl| {
402             let (keys, _) = pool[self.node[bl]].unwrap_inner();
403             keys[usize::from(self.entry[bl]) - 1]
404         })
405     }
406 
407     /// Update the critical key after removing the front entry of the leaf node.
update_crit_key(&mut self, pool: &mut NodePool<F>)408     fn update_crit_key(&mut self, pool: &mut NodePool<F>) {
409         // Find the inner level containing the critical key for the current leaf node.
410         let crit_level = match self.left_sibling_branch_level(self.size - 1) {
411             None => return,
412             Some(l) => l,
413         };
414         let crit_kidx = self.entry[crit_level] - 1;
415 
416         // Extract the new critical key from the leaf node.
417         let crit_key = pool[self.leaf_node()].leaf_crit_key();
418         let crit_node = self.node[crit_level];
419 
420         match pool[crit_node] {
421             NodeData::Inner {
422                 size, ref mut keys, ..
423             } => {
424                 debug_assert!(crit_kidx < size);
425                 keys[usize::from(crit_kidx)] = crit_key;
426             }
427             _ => panic!("Expected inner node"),
428         }
429     }
430 
431     /// Given that the current leaf node is in an unhealthy (underflowed or even empty) status,
432     /// balance it with sibling nodes.
433     ///
434     /// Return the new root node.
balance_nodes(&mut self, status: Removed, pool: &mut NodePool<F>) -> Option<Node>435     fn balance_nodes(&mut self, status: Removed, pool: &mut NodePool<F>) -> Option<Node> {
436         // The current leaf node is not in a healthy state, and its critical key may have changed
437         // too.
438         //
439         // Start by dealing with a changed critical key for the leaf level.
440         if status != Removed::Empty && self.leaf_entry() == 0 {
441             self.update_crit_key(pool);
442         }
443 
444         let leaf_level = self.size - 1;
445         if self.heal_level(status, leaf_level, pool) {
446             // Tree has become empty.
447             self.size = 0;
448             return None;
449         }
450 
451         // Discard the root node if it has shrunk to a single sub-tree.
452         let mut ns = 0;
453         while let NodeData::Inner {
454             size: 0, ref tree, ..
455         } = pool[self.node[ns]]
456         {
457             ns += 1;
458             self.node[ns] = tree[0];
459         }
460 
461         if ns > 0 {
462             for l in 0..ns {
463                 pool.free_node(self.node[l]);
464             }
465 
466             // Shift the whole array instead of just 0..size because `self.size` may be cleared
467             // here if the path is pointing off-the-end.
468             slice_shift(&mut self.node, ns);
469             slice_shift(&mut self.entry, ns);
470 
471             if self.size > 0 {
472                 self.size -= ns;
473             }
474         }
475 
476         // Return the root node, even when `size=0` indicating that we're at the off-the-end
477         // position.
478         Some(self.node[0])
479     }
480 
481     /// After removing an entry from the node at `level`, check its health and rebalance as needed.
482     ///
483     /// Leave the path up to and including `level` in a normalized state where all entries are in
484     /// bounds.
485     ///
486     /// Returns true if the tree becomes empty.
heal_level(&mut self, status: Removed, level: usize, pool: &mut NodePool<F>) -> bool487     fn heal_level(&mut self, status: Removed, level: usize, pool: &mut NodePool<F>) -> bool {
488         match status {
489             Removed::Healthy => {}
490             Removed::Rightmost => {
491                 // The rightmost entry was removed from the current node, so move the path so it
492                 // points at the first entry of the next node at this level.
493                 debug_assert_eq!(
494                     usize::from(self.entry[level]),
495                     pool[self.node[level]].entries()
496                 );
497                 self.next_node(level, pool);
498             }
499             Removed::Underflow => self.underflowed_node(level, pool),
500             Removed::Empty => return self.empty_node(level, pool),
501         }
502         false
503     }
504 
505     /// The current node at `level` has underflowed, meaning that it is below half capacity but
506     /// not completely empty.
507     ///
508     /// Handle this by balancing entries with the right sibling node.
509     ///
510     /// Leave the path up to and including `level` in a valid state that points to the same entry.
underflowed_node(&mut self, level: usize, pool: &mut NodePool<F>)511     fn underflowed_node(&mut self, level: usize, pool: &mut NodePool<F>) {
512         // Look for a right sibling node at this level. If none exists, we allow the underflowed
513         // node to persist as the right-most node at its level.
514         if let Some((crit_key, rhs_node)) = self.right_sibling(level, pool) {
515             // New critical key for the updated right sibling node.
516             let new_ck: Option<F::Key>;
517             let empty;
518             // Make a COPY of the sibling node to avoid fighting the borrow checker.
519             let mut rhs = pool[rhs_node];
520             match pool[self.node[level]].balance(crit_key, &mut rhs) {
521                 None => {
522                     // Everything got moved to the RHS node.
523                     new_ck = self.current_crit_key(level, pool);
524                     empty = true;
525                 }
526                 Some(key) => {
527                     // Entries moved from RHS node.
528                     new_ck = Some(key);
529                     empty = false;
530                 }
531             }
532             // Put back the updated RHS node data.
533             pool[rhs_node] = rhs;
534             // Update the critical key for the RHS node unless it has become a left-most
535             // node.
536             if let Some(ck) = new_ck {
537                 self.update_right_crit_key(level, ck, pool);
538             }
539             if empty {
540                 let empty_tree = self.empty_node(level, pool);
541                 debug_assert!(!empty_tree);
542             }
543 
544             // Any Removed::Rightmost state must have been cleared above by merging nodes. If the
545             // current entry[level] was one off the end of the node, it will now point at a proper
546             // entry.
547             debug_assert!(usize::from(self.entry[level]) < pool[self.node[level]].entries());
548         } else if usize::from(self.entry[level]) >= pool[self.node[level]].entries() {
549             // There's no right sibling at this level, so the node can't be rebalanced.
550             // Check if we are in an off-the-end position.
551             self.size = 0;
552         }
553     }
554 
555     /// The current node at `level` has become empty.
556     ///
557     /// Remove the node from its parent node and leave the path in a normalized state. This means
558     /// that the path at this level will go through the right sibling of this node.
559     ///
560     /// If the current node has no right sibling, set `self.size = 0`.
561     ///
562     /// Returns true if the tree becomes empty.
empty_node(&mut self, level: usize, pool: &mut NodePool<F>) -> bool563     fn empty_node(&mut self, level: usize, pool: &mut NodePool<F>) -> bool {
564         pool.free_node(self.node[level]);
565         if level == 0 {
566             // We just deleted the root node, so the tree is now empty.
567             return true;
568         }
569 
570         // Get the right sibling node before recursively removing nodes.
571         let rhs_node = self.right_sibling(level, pool).map(|(_, n)| n);
572 
573         // Remove the current sub-tree from the parent node.
574         let pl = level - 1;
575         let pe = self.entry[pl].into();
576         let status = pool[self.node[pl]].inner_remove(pe);
577         self.heal_level(status, pl, pool);
578 
579         // Finally update the path at this level.
580         match rhs_node {
581             // We'll leave `self.entry[level]` unchanged. It can be non-zero after moving node
582             // entries to the right sibling node.
583             Some(rhs) => self.node[level] = rhs,
584             // We have no right sibling, so we must have deleted the right-most
585             // entry. The path should be moved to the "off-the-end" position.
586             None => self.size = 0,
587         }
588         false
589     }
590 
591     /// Find the level where the right sibling to the current node at `level` branches off.
592     ///
593     /// This will be an inner node with two adjacent sub-trees: In one the current node at level is
594     /// a right-most node, in the other, the right sibling is a left-most node.
595     ///
596     /// Returns `None` if the current node is a right-most node so no right sibling exists.
right_sibling_branch_level(&self, level: usize, pool: &NodePool<F>) -> Option<usize>597     fn right_sibling_branch_level(&self, level: usize, pool: &NodePool<F>) -> Option<usize> {
598         (0..level).rposition(|l| match pool[self.node[l]] {
599             NodeData::Inner { size, .. } => self.entry[l] < size,
600             _ => panic!("Expected inner node"),
601         })
602     }
603 
604     /// Find the level where the left sibling to the current node at `level` branches off.
left_sibling_branch_level(&self, level: usize) -> Option<usize>605     fn left_sibling_branch_level(&self, level: usize) -> Option<usize> {
606         self.entry[0..level].iter().rposition(|&e| e != 0)
607     }
608 
609     /// Get the right sibling node to the current node at `level`.
610     /// Also return the critical key between the current node and the right sibling.
right_sibling(&self, level: usize, pool: &NodePool<F>) -> Option<(F::Key, Node)>611     fn right_sibling(&self, level: usize, pool: &NodePool<F>) -> Option<(F::Key, Node)> {
612         // Find the critical level: The deepest level where two sibling subtrees contain the
613         // current node and its right sibling.
614         self.right_sibling_branch_level(level, pool).map(|bl| {
615             // Extract the critical key and the `bl+1` node.
616             let be = usize::from(self.entry[bl]);
617             let crit_key;
618             let mut node;
619             {
620                 let (keys, tree) = pool[self.node[bl]].unwrap_inner();
621                 crit_key = keys[be];
622                 node = tree[be + 1];
623             }
624 
625             // Follow left-most links back down to `level`.
626             for _ in bl + 1..level {
627                 node = pool[node].unwrap_inner().1[0];
628             }
629 
630             (crit_key, node)
631         })
632     }
633 
634     /// Update the critical key for the right sibling node at `level`.
update_right_crit_key(&self, level: usize, crit_key: F::Key, pool: &mut NodePool<F>)635     fn update_right_crit_key(&self, level: usize, crit_key: F::Key, pool: &mut NodePool<F>) {
636         let bl = self
637             .right_sibling_branch_level(level, pool)
638             .expect("No right sibling exists");
639         match pool[self.node[bl]] {
640             NodeData::Inner { ref mut keys, .. } => {
641                 keys[usize::from(self.entry[bl])] = crit_key;
642             }
643             _ => panic!("Expected inner node"),
644         }
645     }
646 
647     /// Normalize the path position such that it is either pointing at a real entry or `size=0`
648     /// indicating "off-the-end".
normalize(&mut self, pool: &NodePool<F>)649     pub fn normalize(&mut self, pool: &NodePool<F>) {
650         if let Some((leaf, entry)) = self.leaf_pos() {
651             if entry >= pool[leaf].entries() {
652                 let leaf_level = self.size - 1;
653                 self.next_node(leaf_level, pool);
654             }
655         }
656     }
657 }
658 
659 #[cfg(test)]
660 impl<F: Forest> Path<F> {
661     /// Check the internal consistency of this path.
verify(&self, pool: &NodePool<F>)662     pub fn verify(&self, pool: &NodePool<F>) {
663         for level in 0..self.size {
664             match pool[self.node[level]] {
665                 NodeData::Inner { size, tree, .. } => {
666                     assert!(level < self.size - 1, "Expected leaf node at level {level}");
667                     assert!(
668                         self.entry[level] <= size,
669                         "OOB inner entry {}/{} at level {}",
670                         self.entry[level],
671                         size,
672                         level
673                     );
674                     assert_eq!(
675                         self.node[level + 1],
676                         tree[usize::from(self.entry[level])],
677                         "Node mismatch at level {level}"
678                     );
679                 }
680                 NodeData::Leaf { size, .. } => {
681                     assert_eq!(level, self.size - 1, "Expected inner node");
682                     assert!(
683                         self.entry[level] <= size,
684                         "OOB leaf entry {}/{}",
685                         self.entry[level],
686                         size,
687                     );
688                 }
689                 NodeData::Free { .. } => {
690                     panic!("Free {} in path", self.node[level]);
691                 }
692             }
693         }
694     }
695 }
696 
697 #[cfg(test)]
698 impl<F: Forest> fmt::Display for Path<F> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result699     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
700         if self.size == 0 {
701             write!(f, "<empty path>")
702         } else {
703             write!(f, "{}[{}]", self.node[0], self.entry[0])?;
704             for i in 1..self.size {
705                 write!(f, "--{}[{}]", self.node[i], self.entry[i])?;
706             }
707             Ok(())
708         }
709     }
710 }
711 
712 #[cfg(test)]
713 mod tests {
714     use wasmtime_core::alloc::PanicOnOom;
715 
716     use super::*;
717     use core::cmp::Ordering;
718 
719     struct TC();
720 
721     impl Comparator<i32> for TC {
cmp(&self, a: i32, b: i32) -> Ordering722         fn cmp(&self, a: i32, b: i32) -> Ordering {
723             a.cmp(&b)
724         }
725     }
726 
727     struct TF();
728 
729     impl Forest for TF {
730         type Key = i32;
731         type Value = char;
732         type LeafKeys = [i32; 7];
733         type LeafValues = [char; 7];
734 
splat_key(key: Self::Key) -> Self::LeafKeys735         fn splat_key(key: Self::Key) -> Self::LeafKeys {
736             [key; 7]
737         }
738 
splat_value(value: Self::Value) -> Self::LeafValues739         fn splat_value(value: Self::Value) -> Self::LeafValues {
740             [value; 7]
741         }
742     }
743 
744     #[test]
search_single_leaf()745     fn search_single_leaf() {
746         // Testing Path::new() for trees with a single leaf node.
747         let mut pool = NodePool::<TF>::new();
748         let root = pool.alloc_node(NodeData::leaf(10, 'a')).panic_on_oom();
749         let mut p = Path::default();
750         let comp = TC();
751 
752         // Search for key less than stored key.
753         assert_eq!(p.find(5, root, &pool, &comp), None);
754         assert_eq!(p.size, 1);
755         assert_eq!(p.node[0], root);
756         assert_eq!(p.entry[0], 0);
757 
758         // Search for stored key.
759         assert_eq!(p.find(10, root, &pool, &comp), Some('a'));
760         assert_eq!(p.size, 1);
761         assert_eq!(p.node[0], root);
762         assert_eq!(p.entry[0], 0);
763 
764         // Search for key greater than stored key.
765         assert_eq!(p.find(15, root, &pool, &comp), None);
766         assert_eq!(p.size, 1);
767         assert_eq!(p.node[0], root);
768         assert_eq!(p.entry[0], 1);
769 
770         // Modify leaf node to contain two values.
771         match pool[root] {
772             NodeData::Leaf {
773                 ref mut size,
774                 ref mut keys,
775                 ref mut vals,
776             } => {
777                 *size = 2;
778                 keys[1] = 20;
779                 vals[1] = 'b';
780             }
781             _ => unreachable!(),
782         }
783 
784         // Search for key between stored keys.
785         assert_eq!(p.find(15, root, &pool, &comp), None);
786         assert_eq!(p.size, 1);
787         assert_eq!(p.node[0], root);
788         assert_eq!(p.entry[0], 1);
789 
790         // Search for key greater than stored keys.
791         assert_eq!(p.find(25, root, &pool, &comp), None);
792         assert_eq!(p.size, 1);
793         assert_eq!(p.node[0], root);
794         assert_eq!(p.entry[0], 2);
795     }
796 
797     #[test]
search_single_inner()798     fn search_single_inner() {
799         // Testing Path::new() for trees with a single inner node and two leaves.
800         let mut pool = NodePool::<TF>::new();
801         let leaf1 = pool.alloc_node(NodeData::leaf(10, 'a')).panic_on_oom();
802         let leaf2 = pool.alloc_node(NodeData::leaf(20, 'b')).panic_on_oom();
803         let root = pool
804             .alloc_node(NodeData::inner(leaf1, 20, leaf2))
805             .panic_on_oom();
806         let mut p = Path::default();
807         let comp = TC();
808 
809         // Search for key less than stored keys.
810         assert_eq!(p.find(5, root, &pool, &comp), None);
811         assert_eq!(p.size, 2);
812         assert_eq!(p.node[0], root);
813         assert_eq!(p.entry[0], 0);
814         assert_eq!(p.node[1], leaf1);
815         assert_eq!(p.entry[1], 0);
816 
817         assert_eq!(p.find(10, root, &pool, &comp), Some('a'));
818         assert_eq!(p.size, 2);
819         assert_eq!(p.node[0], root);
820         assert_eq!(p.entry[0], 0);
821         assert_eq!(p.node[1], leaf1);
822         assert_eq!(p.entry[1], 0);
823 
824         // Midway between the two leaf nodes.
825         assert_eq!(p.find(15, root, &pool, &comp), None);
826         assert_eq!(p.size, 2);
827         assert_eq!(p.node[0], root);
828         assert_eq!(p.entry[0], 0);
829         assert_eq!(p.node[1], leaf1);
830         assert_eq!(p.entry[1], 1);
831 
832         assert_eq!(p.find(20, root, &pool, &comp), Some('b'));
833         assert_eq!(p.size, 2);
834         assert_eq!(p.node[0], root);
835         assert_eq!(p.entry[0], 1);
836         assert_eq!(p.node[1], leaf2);
837         assert_eq!(p.entry[1], 0);
838 
839         assert_eq!(p.find(25, root, &pool, &comp), None);
840         assert_eq!(p.size, 2);
841         assert_eq!(p.node[0], root);
842         assert_eq!(p.entry[0], 1);
843         assert_eq!(p.node[1], leaf2);
844         assert_eq!(p.entry[1], 1);
845     }
846 }
847