cranelift_bforest/
path.rs

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