Path: blob/main/cranelift/bforest/src/path.rs
1692 views
//! A path from the root of a B+-tree to a leaf node.12use super::node::Removed;3use super::{Comparator, Forest, MAX_PATH, Node, NodeData, NodePool, slice_insert, slice_shift};4use core::borrow::Borrow;5use core::marker::PhantomData;67#[cfg(test)]8use core::fmt;910pub(super) struct Path<F: Forest> {11/// Number of path entries including the root and leaf nodes.12size: usize,1314/// Path of node references from the root to a leaf node.15node: [Node; MAX_PATH],1617/// Entry number in each node.18entry: [u8; MAX_PATH],1920unused: PhantomData<F>,21}2223impl<F: Forest> Default for Path<F> {24fn default() -> Self {25Self {26size: 0,27node: [Node(0); MAX_PATH],28entry: [0; MAX_PATH],29unused: PhantomData,30}31}32}3334impl<F: Forest> Path<F> {35/// Reset path by searching for `key` starting from `root`.36///37/// If `key` is in the tree, returns the corresponding value and leaved the path pointing at38/// the entry. Otherwise returns `None` and:39///40/// - A key smaller than all stored keys returns a path to the first entry of the first leaf.41/// - A key larger than all stored keys returns a path to one beyond the last element of the42/// last leaf.43/// - A key between the stored keys of adjacent leaf nodes returns a path to one beyond the44/// last entry of the first of the leaf nodes.45///46pub fn find(47&mut self,48key: F::Key,49root: Node,50pool: &NodePool<F>,51comp: &dyn Comparator<F::Key>,52) -> Option<F::Value> {53let mut node = root;54for level in 0.. {55self.size = level + 1;56self.node[level] = node;57match pool[node] {58NodeData::Inner { size, keys, tree } => {59// Invariant: `tree[i]` contains keys smaller than60// `keys[i]`, greater or equal to `keys[i-1]`.61let i = match comp.search(key, &keys[0..size.into()]) {62// We hit an existing key, so follow the >= branch.63Ok(i) => i + 1,64// Key is less than `keys[i]`, so follow the < branch.65Err(i) => i,66};67self.entry[level] = i as u8;68node = tree[i];69}70NodeData::Leaf { size, keys, vals } => {71// For a leaf we want either the found key or an insert position.72return match comp.search(key, &keys.borrow()[0..size.into()]) {73Ok(i) => {74self.entry[level] = i as u8;75Some(vals.borrow()[i])76}77Err(i) => {78self.entry[level] = i as u8;79None80}81};82}83NodeData::Free { .. } => panic!("Free {} reached from {}", node, root),84}85}86unreachable!();87}8889/// Move path to the first entry of the tree starting at `root` and return it.90pub fn first(&mut self, root: Node, pool: &NodePool<F>) -> (F::Key, F::Value) {91let mut node = root;92for level in 0.. {93self.size = level + 1;94self.node[level] = node;95self.entry[level] = 0;96match pool[node] {97NodeData::Inner { tree, .. } => node = tree[0],98NodeData::Leaf { keys, vals, .. } => return (keys.borrow()[0], vals.borrow()[0]),99NodeData::Free { .. } => panic!("Free {} reached from {}", node, root),100}101}102unreachable!();103}104105/// Move this path to the next key-value pair and return it.106pub fn next(&mut self, pool: &NodePool<F>) -> Option<(F::Key, F::Value)> {107match self.leaf_pos() {108None => return None,109Some((node, entry)) => {110let (keys, vals) = pool[node].unwrap_leaf();111if entry + 1 < keys.len() {112self.entry[self.size - 1] += 1;113return Some((keys[entry + 1], vals[entry + 1]));114}115}116}117118// The current leaf node is exhausted. Move to the next one.119let leaf_level = self.size - 1;120self.next_node(leaf_level, pool).map(|node| {121let (keys, vals) = pool[node].unwrap_leaf();122(keys[0], vals[0])123})124}125126/// Move this path to the previous key-value pair and return it.127///128/// If the path is at the off-the-end position, go to the last key-value pair.129///130/// If the path is already at the first key-value pair, leave it there and return `None`.131pub fn prev(&mut self, root: Node, pool: &NodePool<F>) -> Option<(F::Key, F::Value)> {132// We use `size == 0` as a generic off-the-end position.133if self.size == 0 {134self.goto_subtree_last(0, root, pool);135let (node, entry) = self.leaf_pos().unwrap();136let (keys, vals) = pool[node].unwrap_leaf();137return Some((keys[entry], vals[entry]));138}139140match self.leaf_pos() {141None => return None,142Some((node, entry)) => {143if entry > 0 {144self.entry[self.size - 1] -= 1;145let (keys, vals) = pool[node].unwrap_leaf();146return Some((keys[entry - 1], vals[entry - 1]));147}148}149}150151// The current leaf node is exhausted. Move to the previous one.152self.prev_leaf(pool).map(|node| {153let (keys, vals) = pool[node].unwrap_leaf();154let e = self.leaf_entry();155(keys[e], vals[e])156})157}158159/// Move path to the first entry of the next node at level, if one exists.160///161/// Returns the new node if it exists.162///163/// Reset the path to `size = 0` and return `None` if there is no next node.164fn next_node(&mut self, level: usize, pool: &NodePool<F>) -> Option<Node> {165match self.right_sibling_branch_level(level, pool) {166None => {167self.size = 0;168None169}170Some(bl) => {171let (_, bnodes) = pool[self.node[bl]].unwrap_inner();172self.entry[bl] += 1;173let mut node = bnodes[usize::from(self.entry[bl])];174175for l in bl + 1..level {176self.node[l] = node;177self.entry[l] = 0;178node = pool[node].unwrap_inner().1[0];179}180181self.node[level] = node;182self.entry[level] = 0;183Some(node)184}185}186}187188/// Move the path to the last entry of the previous leaf node, if one exists.189///190/// Returns the new leaf node if it exists.191///192/// Leave the path unchanged and returns `None` if we are already at the first leaf node.193fn prev_leaf(&mut self, pool: &NodePool<F>) -> Option<Node> {194self.left_sibling_branch_level(self.size - 1).map(|bl| {195let entry = self.entry[bl] - 1;196self.entry[bl] = entry;197let (_, bnodes) = pool[self.node[bl]].unwrap_inner();198self.goto_subtree_last(bl + 1, bnodes[usize::from(entry)], pool)199})200}201202/// Move this path to the last position for the sub-tree at `level, root`.203fn goto_subtree_last(&mut self, level: usize, root: Node, pool: &NodePool<F>) -> Node {204let mut node = root;205for l in level.. {206self.node[l] = node;207match pool[node] {208NodeData::Inner { size, ref tree, .. } => {209self.entry[l] = size;210node = tree[usize::from(size)];211}212NodeData::Leaf { size, .. } => {213self.entry[l] = size - 1;214self.size = l + 1;215break;216}217NodeData::Free { .. } => panic!("Free {} reached from {}", node, root),218}219}220node221}222223/// Set the root node and point the path at the first entry of the node.224pub fn set_root_node(&mut self, root: Node) {225self.size = 1;226self.node[0] = root;227self.entry[0] = 0;228}229230/// Get the current leaf node and entry, if any.231pub fn leaf_pos(&self) -> Option<(Node, usize)> {232let i = self.size.wrapping_sub(1);233self.node.get(i).map(|&n| (n, self.entry[i].into()))234}235236/// Get the current leaf node.237fn leaf_node(&self) -> Node {238self.node[self.size - 1]239}240241/// Get the current entry in the leaf node.242fn leaf_entry(&self) -> usize {243self.entry[self.size - 1].into()244}245246/// Is this path pointing to the first entry in the tree?247/// This corresponds to the smallest key.248fn at_first_entry(&self) -> bool {249self.entry[0..self.size].iter().all(|&i| i == 0)250}251252/// Get a mutable reference to the current value.253/// This assumes that there is a current value.254pub fn value_mut<'a>(&self, pool: &'a mut NodePool<F>) -> &'a mut F::Value {255&mut pool[self.leaf_node()].unwrap_leaf_mut().1[self.leaf_entry()]256}257258/// Insert the key-value pair at the current position.259/// The current position must be the correct insertion location for the key.260/// This function does not check for duplicate keys. Use `find` or similar for that.261/// Returns the new root node.262pub fn insert(&mut self, key: F::Key, value: F::Value, pool: &mut NodePool<F>) -> Node {263if !self.try_leaf_insert(key, value, pool) {264self.split_and_insert(key, value, pool);265}266self.node[0]267}268269/// Try to insert `key, value` at the current position, but fail and return false if the leaf270/// node is full.271fn try_leaf_insert(&self, key: F::Key, value: F::Value, pool: &mut NodePool<F>) -> bool {272let index = self.leaf_entry();273274// The case `index == 0` should only ever happen when there are no earlier leaf nodes,275// otherwise we should have appended to the previous leaf node instead. This invariant276// means that we don't need to update keys stored in inner nodes here.277debug_assert!(index > 0 || self.at_first_entry());278279pool[self.leaf_node()].try_leaf_insert(index, key, value)280}281282/// Split the current leaf node and then insert `key, value`.283/// This should only be used if `try_leaf_insert()` fails.284fn split_and_insert(&mut self, mut key: F::Key, value: F::Value, pool: &mut NodePool<F>) {285let orig_root = self.node[0];286287// Loop invariant: We need to split the node at `level` and then retry a failed insertion.288// The items to insert are either `(key, ins_node)` or `(key, value)`.289let mut ins_node = None;290let mut split;291for level in (0..self.size).rev() {292// Split the current node.293let mut node = self.node[level];294let mut entry = self.entry[level].into();295split = pool[node].split(entry);296let rhs_node = pool.alloc_node(split.rhs_data);297298// Should the path be moved to the new RHS node?299// Prefer the smaller node if we're right in the middle.300// Prefer to append to LHS all other things being equal.301//302// When inserting into an inner node (`ins_node.is_some()`), we must point to a valid303// entry in the current node since the new entry is inserted *after* the insert304// location.305if entry > split.lhs_entries306|| (entry == split.lhs_entries307&& (split.lhs_entries > split.rhs_entries || ins_node.is_some()))308{309node = rhs_node;310entry -= split.lhs_entries;311self.node[level] = node;312self.entry[level] = entry as u8;313}314315// Now that we have a not-full node, it must be possible to insert.316match ins_node {317None => {318let inserted = pool[node].try_leaf_insert(entry, key, value);319debug_assert!(inserted);320// If we inserted at the front of the new rhs_node leaf, we need to propagate321// the inserted key as the critical key instead of the previous front key.322if entry == 0 && node == rhs_node {323split.crit_key = key;324}325}326Some(n) => {327let inserted = pool[node].try_inner_insert(entry, key, n);328debug_assert!(inserted);329// The lower level was moved to the new RHS node, so make sure that is330// reflected here.331if n == self.node[level + 1] {332self.entry[level] += 1;333}334}335}336337// We are now done with the current level, but `rhs_node` must be inserted in the inner338// node above us. If we're already at level 0, the root node needs to be split.339key = split.crit_key;340ins_node = Some(rhs_node);341if level > 0 {342let pnode = &mut pool[self.node[level - 1]];343let pentry = self.entry[level - 1].into();344if pnode.try_inner_insert(pentry, key, rhs_node) {345// If this level level was moved to the new RHS node, update parent entry.346if node == rhs_node {347self.entry[level - 1] += 1;348}349return;350}351}352}353354// If we get here we have split the original root node and need to add an extra level.355let rhs_node = ins_node.expect("empty path");356let root = pool.alloc_node(NodeData::inner(orig_root, key, rhs_node));357let entry = if self.node[0] == rhs_node { 1 } else { 0 };358self.size += 1;359slice_insert(&mut self.node[0..self.size], 0, root);360slice_insert(&mut self.entry[0..self.size], 0, entry);361}362363/// Remove the key-value pair at the current position and advance the path to the next364/// key-value pair, leaving the path in a normalized state.365///366/// Return the new root node.367pub fn remove(&mut self, pool: &mut NodePool<F>) -> Option<Node> {368let e = self.leaf_entry();369match pool[self.leaf_node()].leaf_remove(e) {370Removed::Healthy => {371if e == 0 {372self.update_crit_key(pool)373}374Some(self.node[0])375}376status => self.balance_nodes(status, pool),377}378}379380/// Get the critical key for the current node at `level`.381///382/// The critical key is less than or equal to all keys in the sub-tree at `level` and greater383/// than all keys to the left of the current node at `level`.384///385/// The left-most node at any level does not have a critical key.386fn current_crit_key(&self, level: usize, pool: &NodePool<F>) -> Option<F::Key> {387// Find the level containing the critical key for the current node.388self.left_sibling_branch_level(level).map(|bl| {389let (keys, _) = pool[self.node[bl]].unwrap_inner();390keys[usize::from(self.entry[bl]) - 1]391})392}393394/// Update the critical key after removing the front entry of the leaf node.395fn update_crit_key(&mut self, pool: &mut NodePool<F>) {396// Find the inner level containing the critical key for the current leaf node.397let crit_level = match self.left_sibling_branch_level(self.size - 1) {398None => return,399Some(l) => l,400};401let crit_kidx = self.entry[crit_level] - 1;402403// Extract the new critical key from the leaf node.404let crit_key = pool[self.leaf_node()].leaf_crit_key();405let crit_node = self.node[crit_level];406407match pool[crit_node] {408NodeData::Inner {409size, ref mut keys, ..410} => {411debug_assert!(crit_kidx < size);412keys[usize::from(crit_kidx)] = crit_key;413}414_ => panic!("Expected inner node"),415}416}417418/// Given that the current leaf node is in an unhealthy (underflowed or even empty) status,419/// balance it with sibling nodes.420///421/// Return the new root node.422fn balance_nodes(&mut self, status: Removed, pool: &mut NodePool<F>) -> Option<Node> {423// The current leaf node is not in a healthy state, and its critical key may have changed424// too.425//426// Start by dealing with a changed critical key for the leaf level.427if status != Removed::Empty && self.leaf_entry() == 0 {428self.update_crit_key(pool);429}430431let leaf_level = self.size - 1;432if self.heal_level(status, leaf_level, pool) {433// Tree has become empty.434self.size = 0;435return None;436}437438// Discard the root node if it has shrunk to a single sub-tree.439let mut ns = 0;440while let NodeData::Inner {441size: 0, ref tree, ..442} = pool[self.node[ns]]443{444ns += 1;445self.node[ns] = tree[0];446}447448if ns > 0 {449for l in 0..ns {450pool.free_node(self.node[l]);451}452453// Shift the whole array instead of just 0..size because `self.size` may be cleared454// here if the path is pointing off-the-end.455slice_shift(&mut self.node, ns);456slice_shift(&mut self.entry, ns);457458if self.size > 0 {459self.size -= ns;460}461}462463// Return the root node, even when `size=0` indicating that we're at the off-the-end464// position.465Some(self.node[0])466}467468/// After removing an entry from the node at `level`, check its health and rebalance as needed.469///470/// Leave the path up to and including `level` in a normalized state where all entries are in471/// bounds.472///473/// Returns true if the tree becomes empty.474fn heal_level(&mut self, status: Removed, level: usize, pool: &mut NodePool<F>) -> bool {475match status {476Removed::Healthy => {}477Removed::Rightmost => {478// The rightmost entry was removed from the current node, so move the path so it479// points at the first entry of the next node at this level.480debug_assert_eq!(481usize::from(self.entry[level]),482pool[self.node[level]].entries()483);484self.next_node(level, pool);485}486Removed::Underflow => self.underflowed_node(level, pool),487Removed::Empty => return self.empty_node(level, pool),488}489false490}491492/// The current node at `level` has underflowed, meaning that it is below half capacity but493/// not completely empty.494///495/// Handle this by balancing entries with the right sibling node.496///497/// Leave the path up to and including `level` in a valid state that points to the same entry.498fn underflowed_node(&mut self, level: usize, pool: &mut NodePool<F>) {499// Look for a right sibling node at this level. If none exists, we allow the underflowed500// node to persist as the right-most node at its level.501if let Some((crit_key, rhs_node)) = self.right_sibling(level, pool) {502// New critical key for the updated right sibling node.503let new_ck: Option<F::Key>;504let empty;505// Make a COPY of the sibling node to avoid fighting the borrow checker.506let mut rhs = pool[rhs_node];507match pool[self.node[level]].balance(crit_key, &mut rhs) {508None => {509// Everything got moved to the RHS node.510new_ck = self.current_crit_key(level, pool);511empty = true;512}513Some(key) => {514// Entries moved from RHS node.515new_ck = Some(key);516empty = false;517}518}519// Put back the updated RHS node data.520pool[rhs_node] = rhs;521// Update the critical key for the RHS node unless it has become a left-most522// node.523if let Some(ck) = new_ck {524self.update_right_crit_key(level, ck, pool);525}526if empty {527let empty_tree = self.empty_node(level, pool);528debug_assert!(!empty_tree);529}530531// Any Removed::Rightmost state must have been cleared above by merging nodes. If the532// current entry[level] was one off the end of the node, it will now point at a proper533// entry.534debug_assert!(usize::from(self.entry[level]) < pool[self.node[level]].entries());535} else if usize::from(self.entry[level]) >= pool[self.node[level]].entries() {536// There's no right sibling at this level, so the node can't be rebalanced.537// Check if we are in an off-the-end position.538self.size = 0;539}540}541542/// The current node at `level` has become empty.543///544/// Remove the node from its parent node and leave the path in a normalized state. This means545/// that the path at this level will go through the right sibling of this node.546///547/// If the current node has no right sibling, set `self.size = 0`.548///549/// Returns true if the tree becomes empty.550fn empty_node(&mut self, level: usize, pool: &mut NodePool<F>) -> bool {551pool.free_node(self.node[level]);552if level == 0 {553// We just deleted the root node, so the tree is now empty.554return true;555}556557// Get the right sibling node before recursively removing nodes.558let rhs_node = self.right_sibling(level, pool).map(|(_, n)| n);559560// Remove the current sub-tree from the parent node.561let pl = level - 1;562let pe = self.entry[pl].into();563let status = pool[self.node[pl]].inner_remove(pe);564self.heal_level(status, pl, pool);565566// Finally update the path at this level.567match rhs_node {568// We'll leave `self.entry[level]` unchanged. It can be non-zero after moving node569// entries to the right sibling node.570Some(rhs) => self.node[level] = rhs,571// We have no right sibling, so we must have deleted the right-most572// entry. The path should be moved to the "off-the-end" position.573None => self.size = 0,574}575false576}577578/// Find the level where the right sibling to the current node at `level` branches off.579///580/// This will be an inner node with two adjacent sub-trees: In one the current node at level is581/// a right-most node, in the other, the right sibling is a left-most node.582///583/// Returns `None` if the current node is a right-most node so no right sibling exists.584fn right_sibling_branch_level(&self, level: usize, pool: &NodePool<F>) -> Option<usize> {585(0..level).rposition(|l| match pool[self.node[l]] {586NodeData::Inner { size, .. } => self.entry[l] < size,587_ => panic!("Expected inner node"),588})589}590591/// Find the level where the left sibling to the current node at `level` branches off.592fn left_sibling_branch_level(&self, level: usize) -> Option<usize> {593self.entry[0..level].iter().rposition(|&e| e != 0)594}595596/// Get the right sibling node to the current node at `level`.597/// Also return the critical key between the current node and the right sibling.598fn right_sibling(&self, level: usize, pool: &NodePool<F>) -> Option<(F::Key, Node)> {599// Find the critical level: The deepest level where two sibling subtrees contain the600// current node and its right sibling.601self.right_sibling_branch_level(level, pool).map(|bl| {602// Extract the critical key and the `bl+1` node.603let be = usize::from(self.entry[bl]);604let crit_key;605let mut node;606{607let (keys, tree) = pool[self.node[bl]].unwrap_inner();608crit_key = keys[be];609node = tree[be + 1];610}611612// Follow left-most links back down to `level`.613for _ in bl + 1..level {614node = pool[node].unwrap_inner().1[0];615}616617(crit_key, node)618})619}620621/// Update the critical key for the right sibling node at `level`.622fn update_right_crit_key(&self, level: usize, crit_key: F::Key, pool: &mut NodePool<F>) {623let bl = self624.right_sibling_branch_level(level, pool)625.expect("No right sibling exists");626match pool[self.node[bl]] {627NodeData::Inner { ref mut keys, .. } => {628keys[usize::from(self.entry[bl])] = crit_key;629}630_ => panic!("Expected inner node"),631}632}633634/// Normalize the path position such that it is either pointing at a real entry or `size=0`635/// indicating "off-the-end".636pub fn normalize(&mut self, pool: &mut NodePool<F>) {637if let Some((leaf, entry)) = self.leaf_pos() {638if entry >= pool[leaf].entries() {639let leaf_level = self.size - 1;640self.next_node(leaf_level, pool);641}642}643}644}645646#[cfg(test)]647impl<F: Forest> Path<F> {648/// Check the internal consistency of this path.649pub fn verify(&self, pool: &NodePool<F>) {650for level in 0..self.size {651match pool[self.node[level]] {652NodeData::Inner { size, tree, .. } => {653assert!(level < self.size - 1, "Expected leaf node at level {level}");654assert!(655self.entry[level] <= size,656"OOB inner entry {}/{} at level {}",657self.entry[level],658size,659level660);661assert_eq!(662self.node[level + 1],663tree[usize::from(self.entry[level])],664"Node mismatch at level {level}"665);666}667NodeData::Leaf { size, .. } => {668assert_eq!(level, self.size - 1, "Expected inner node");669assert!(670self.entry[level] <= size,671"OOB leaf entry {}/{}",672self.entry[level],673size,674);675}676NodeData::Free { .. } => {677panic!("Free {} in path", self.node[level]);678}679}680}681}682}683684#[cfg(test)]685impl<F: Forest> fmt::Display for Path<F> {686fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {687if self.size == 0 {688write!(f, "<empty path>")689} else {690write!(f, "{}[{}]", self.node[0], self.entry[0])?;691for i in 1..self.size {692write!(f, "--{}[{}]", self.node[i], self.entry[i])?;693}694Ok(())695}696}697}698699#[cfg(test)]700mod tests {701use super::*;702use core::cmp::Ordering;703704struct TC();705706impl Comparator<i32> for TC {707fn cmp(&self, a: i32, b: i32) -> Ordering {708a.cmp(&b)709}710}711712struct TF();713714impl Forest for TF {715type Key = i32;716type Value = char;717type LeafKeys = [i32; 7];718type LeafValues = [char; 7];719720fn splat_key(key: Self::Key) -> Self::LeafKeys {721[key; 7]722}723724fn splat_value(value: Self::Value) -> Self::LeafValues {725[value; 7]726}727}728729#[test]730fn search_single_leaf() {731// Testing Path::new() for trees with a single leaf node.732let mut pool = NodePool::<TF>::new();733let root = pool.alloc_node(NodeData::leaf(10, 'a'));734let mut p = Path::default();735let comp = TC();736737// Search for key less than stored key.738assert_eq!(p.find(5, root, &pool, &comp), None);739assert_eq!(p.size, 1);740assert_eq!(p.node[0], root);741assert_eq!(p.entry[0], 0);742743// Search for stored key.744assert_eq!(p.find(10, root, &pool, &comp), Some('a'));745assert_eq!(p.size, 1);746assert_eq!(p.node[0], root);747assert_eq!(p.entry[0], 0);748749// Search for key greater than stored key.750assert_eq!(p.find(15, root, &pool, &comp), None);751assert_eq!(p.size, 1);752assert_eq!(p.node[0], root);753assert_eq!(p.entry[0], 1);754755// Modify leaf node to contain two values.756match pool[root] {757NodeData::Leaf {758ref mut size,759ref mut keys,760ref mut vals,761} => {762*size = 2;763keys[1] = 20;764vals[1] = 'b';765}766_ => unreachable!(),767}768769// Search for key between stored keys.770assert_eq!(p.find(15, root, &pool, &comp), None);771assert_eq!(p.size, 1);772assert_eq!(p.node[0], root);773assert_eq!(p.entry[0], 1);774775// Search for key greater than stored keys.776assert_eq!(p.find(25, root, &pool, &comp), None);777assert_eq!(p.size, 1);778assert_eq!(p.node[0], root);779assert_eq!(p.entry[0], 2);780}781782#[test]783fn search_single_inner() {784// Testing Path::new() for trees with a single inner node and two leaves.785let mut pool = NodePool::<TF>::new();786let leaf1 = pool.alloc_node(NodeData::leaf(10, 'a'));787let leaf2 = pool.alloc_node(NodeData::leaf(20, 'b'));788let root = pool.alloc_node(NodeData::inner(leaf1, 20, leaf2));789let mut p = Path::default();790let comp = TC();791792// Search for key less than stored keys.793assert_eq!(p.find(5, root, &pool, &comp), None);794assert_eq!(p.size, 2);795assert_eq!(p.node[0], root);796assert_eq!(p.entry[0], 0);797assert_eq!(p.node[1], leaf1);798assert_eq!(p.entry[1], 0);799800assert_eq!(p.find(10, root, &pool, &comp), Some('a'));801assert_eq!(p.size, 2);802assert_eq!(p.node[0], root);803assert_eq!(p.entry[0], 0);804assert_eq!(p.node[1], leaf1);805assert_eq!(p.entry[1], 0);806807// Midway between the two leaf nodes.808assert_eq!(p.find(15, root, &pool, &comp), None);809assert_eq!(p.size, 2);810assert_eq!(p.node[0], root);811assert_eq!(p.entry[0], 0);812assert_eq!(p.node[1], leaf1);813assert_eq!(p.entry[1], 1);814815assert_eq!(p.find(20, root, &pool, &comp), Some('b'));816assert_eq!(p.size, 2);817assert_eq!(p.node[0], root);818assert_eq!(p.entry[0], 1);819assert_eq!(p.node[1], leaf2);820assert_eq!(p.entry[1], 0);821822assert_eq!(p.find(25, root, &pool, &comp), None);823assert_eq!(p.size, 2);824assert_eq!(p.node[0], root);825assert_eq!(p.entry[0], 1);826assert_eq!(p.node[1], leaf2);827assert_eq!(p.entry[1], 1);828}829}830831832