Path: blob/main/cranelift/bforest/src/node.rs
1692 views
//! B+-tree nodes.12use super::{Forest, INNER_SIZE, Node, SetValue, slice_insert, slice_shift};3use core::borrow::{Borrow, BorrowMut};4use core::fmt;56/// B+-tree node.7///8/// A B+-tree has different node types for inner nodes and leaf nodes. Inner nodes contain M node9/// references and M-1 keys while leaf nodes contain N keys and values. Values for M and N are10/// chosen such that a node is exactly 64 bytes (a cache line) when keys and values are 32 bits11/// each.12///13/// An inner node contains at least M/2 node references unless it is the right-most node at its14/// level. A leaf node contains at least N/2 keys unless it is the right-most leaf.15pub(super) enum NodeData<F: Forest> {16Inner {17/// The number of keys in this node.18/// The number of node references is always one more.19size: u8,2021/// Keys discriminating sub-trees.22///23/// The key in `keys[i]` is greater than all keys in `tree[i]` and less than or equal to24/// all keys in `tree[i+1]`.25keys: [F::Key; INNER_SIZE - 1],2627/// Sub-trees.28tree: [Node; INNER_SIZE],29},30Leaf {31/// Number of key-value pairs in this node.32size: u8,3334// Key array.35keys: F::LeafKeys,3637// Value array.38vals: F::LeafValues,39},40/// An unused node on the free list.41Free { next: Option<Node> },42}4344// Implement `Clone` and `Copy` manually, because deriving them would also require `Forest` to45// implement `Clone`.46impl<F: Forest> Copy for NodeData<F> {}47impl<F: Forest> Clone for NodeData<F> {48fn clone(&self) -> Self {49*self50}51}5253impl<F: Forest> NodeData<F> {54/// Is this a free/unused node?55pub fn is_free(&self) -> bool {56match *self {57Self::Free { .. } => true,58_ => false,59}60}6162/// Get the number of entries in this node.63///64/// This is the number of outgoing edges in an inner node, or the number of key-value pairs in65/// a leaf node.66pub fn entries(&self) -> usize {67match *self {68Self::Inner { size, .. } => usize::from(size) + 1,69Self::Leaf { size, .. } => usize::from(size),70Self::Free { .. } => panic!("freed node"),71}72}7374/// Create an inner node with a single key and two sub-trees.75pub fn inner(left: Node, key: F::Key, right: Node) -> Self {76// Splat the key and right node to the whole array.77// Saves us from inventing a default/reserved value.78let mut tree = [right; INNER_SIZE];79tree[0] = left;80Self::Inner {81size: 1,82keys: [key; INNER_SIZE - 1],83tree,84}85}8687/// Create a leaf node with a single key-value pair.88pub fn leaf(key: F::Key, value: F::Value) -> Self {89Self::Leaf {90size: 1,91keys: F::splat_key(key),92vals: F::splat_value(value),93}94}9596/// Unwrap an inner node into two slices (keys, trees).97pub fn unwrap_inner(&self) -> (&[F::Key], &[Node]) {98match *self {99Self::Inner {100size,101ref keys,102ref tree,103} => {104let size = usize::from(size);105// TODO: We could probably use `get_unchecked()` here since `size` is always in106// range.107(&keys[0..size], &tree[0..=size])108}109_ => panic!("Expected inner node"),110}111}112113/// Unwrap a leaf node into two slices (keys, values) of the same length.114pub fn unwrap_leaf(&self) -> (&[F::Key], &[F::Value]) {115match *self {116Self::Leaf {117size,118ref keys,119ref vals,120} => {121let size = usize::from(size);122let keys = keys.borrow();123let vals = vals.borrow();124// TODO: We could probably use `get_unchecked()` here since `size` is always in125// range.126(&keys[0..size], &vals[0..size])127}128_ => panic!("Expected leaf node"),129}130}131132/// Unwrap a mutable leaf node into two slices (keys, values) of the same length.133pub fn unwrap_leaf_mut(&mut self) -> (&mut [F::Key], &mut [F::Value]) {134match *self {135Self::Leaf {136size,137ref mut keys,138ref mut vals,139} => {140let size = usize::from(size);141let keys = keys.borrow_mut();142let vals = vals.borrow_mut();143// TODO: We could probably use `get_unchecked_mut()` here since `size` is always in144// range.145(&mut keys[0..size], &mut vals[0..size])146}147_ => panic!("Expected leaf node"),148}149}150151/// Get the critical key for a leaf node.152/// This is simply the first key.153pub fn leaf_crit_key(&self) -> F::Key {154match *self {155Self::Leaf { size, ref keys, .. } => {156debug_assert!(size > 0, "Empty leaf node");157keys.borrow()[0]158}159_ => panic!("Expected leaf node"),160}161}162163/// Try to insert `(key, node)` at key-position `index` in an inner node.164/// This means that `key` is inserted at `keys[i]` and `node` is inserted at `tree[i + 1]`.165/// If the node is full, this leaves the node unchanged and returns false.166pub fn try_inner_insert(&mut self, index: usize, key: F::Key, node: Node) -> bool {167match *self {168Self::Inner {169ref mut size,170ref mut keys,171ref mut tree,172} => {173let sz = usize::from(*size);174debug_assert!(sz <= keys.len());175debug_assert!(index <= sz, "Can't insert at {index} with {sz} keys");176177if let Some(ks) = keys.get_mut(0..=sz) {178*size = (sz + 1) as u8;179slice_insert(ks, index, key);180slice_insert(&mut tree[1..=sz + 1], index, node);181true182} else {183false184}185}186_ => panic!("Expected inner node"),187}188}189190/// Try to insert `key, value` at `index` in a leaf node, but fail and return false if the node191/// is full.192pub fn try_leaf_insert(&mut self, index: usize, key: F::Key, value: F::Value) -> bool {193match *self {194Self::Leaf {195ref mut size,196ref mut keys,197ref mut vals,198} => {199let sz = usize::from(*size);200let keys = keys.borrow_mut();201let vals = vals.borrow_mut();202debug_assert!(sz <= keys.len());203debug_assert!(index <= sz);204205if let Some(ks) = keys.get_mut(0..=sz) {206*size = (sz + 1) as u8;207slice_insert(ks, index, key);208slice_insert(&mut vals[0..=sz], index, value);209true210} else {211false212}213}214_ => panic!("Expected leaf node"),215}216}217218/// Split off the second half of this node.219/// It is assumed that this a completely full inner or leaf node.220///221/// The `insert_index` parameter is the position where an insertion was tried and failed. The222/// node will be split in half with a bias towards an even split after the insertion is retried.223pub fn split(&mut self, insert_index: usize) -> SplitOff<F> {224match *self {225Self::Inner {226ref mut size,227ref keys,228ref tree,229} => {230debug_assert_eq!(usize::from(*size), keys.len(), "Node not full");231232// Number of tree entries in the lhs node.233let l_ents = split_pos(tree.len(), insert_index + 1);234let r_ents = tree.len() - l_ents;235236// With INNER_SIZE=8, we get l_ents=4 and:237//238// self: [ n0 k0 n1 k1 n2 k2 n3 k3 n4 k4 n5 k5 n6 k6 n7 ]239// lhs: [ n0 k0 n1 k1 n2 k2 n3 ]240// crit_key = k3 (not present in either node)241// rhs: [ n4 k4 n5 k5 n6 k6 n7 ]242243// 1. Truncate the LHS.244*size = (l_ents - 1) as u8;245246// 2. Copy second half to `rhs_data`.247let mut r_keys = *keys;248r_keys[0..r_ents - 1].copy_from_slice(&keys[l_ents..]);249250let mut r_tree = *tree;251r_tree[0..r_ents].copy_from_slice(&tree[l_ents..]);252253SplitOff {254lhs_entries: l_ents,255rhs_entries: r_ents,256crit_key: keys[l_ents - 1],257rhs_data: Self::Inner {258size: (r_ents - 1) as u8,259keys: r_keys,260tree: r_tree,261},262}263}264Self::Leaf {265ref mut size,266ref keys,267ref vals,268} => {269let o_keys = keys.borrow();270let o_vals = vals.borrow();271debug_assert_eq!(usize::from(*size), o_keys.len(), "Node not full");272273let l_size = split_pos(o_keys.len(), insert_index);274let r_size = o_keys.len() - l_size;275276// 1. Truncate the LHS node at `l_size`.277*size = l_size as u8;278279// 2. Copy second half to `rhs_data`.280let mut r_keys = *keys;281r_keys.borrow_mut()[0..r_size].copy_from_slice(&o_keys[l_size..]);282283let mut r_vals = *vals;284r_vals.borrow_mut()[0..r_size].copy_from_slice(&o_vals[l_size..]);285286SplitOff {287lhs_entries: l_size,288rhs_entries: r_size,289crit_key: o_keys[l_size],290rhs_data: Self::Leaf {291size: r_size as u8,292keys: r_keys,293vals: r_vals,294},295}296}297_ => panic!("Expected leaf node"),298}299}300301/// Remove the sub-tree at `index` from this inner node.302///303/// Note that `index` refers to a sub-tree entry and not a key entry as it does for304/// `try_inner_insert()`. It is possible to remove the first sub-tree (which can't be inserted305/// by `try_inner_insert()`).306///307/// Return an indication of the node's health (i.e. below half capacity).308pub fn inner_remove(&mut self, index: usize) -> Removed {309match *self {310Self::Inner {311ref mut size,312ref mut keys,313ref mut tree,314} => {315let ents = usize::from(*size) + 1;316debug_assert!(ents <= tree.len());317debug_assert!(index < ents);318// Leave an invalid 0xff size when node becomes empty.319*size = ents.wrapping_sub(2) as u8;320if ents > 1 {321slice_shift(&mut keys[index.saturating_sub(1)..ents - 1], 1);322}323slice_shift(&mut tree[index..ents], 1);324Removed::new(index, ents - 1, tree.len())325}326_ => panic!("Expected inner node"),327}328}329330/// Remove the key-value pair at `index` from this leaf node.331///332/// Return an indication of the node's health (i.e. below half capacity).333pub fn leaf_remove(&mut self, index: usize) -> Removed {334match *self {335Self::Leaf {336ref mut size,337ref mut keys,338ref mut vals,339} => {340let sz = usize::from(*size);341let keys = keys.borrow_mut();342let vals = vals.borrow_mut();343*size -= 1;344slice_shift(&mut keys[index..sz], 1);345slice_shift(&mut vals[index..sz], 1);346Removed::new(index, sz - 1, keys.len())347}348_ => panic!("Expected leaf node"),349}350}351352/// Balance this node with its right sibling.353///354/// It is assumed that the current node has underflowed. Look at the right sibling node and do355/// one of two things:356///357/// 1. Move all entries to the right node, leaving this node empty, or358/// 2. Distribute entries evenly between the two nodes.359///360/// In the first case, `None` is returned. In the second case, the new critical key for the361/// right sibling node is returned.362pub fn balance(&mut self, crit_key: F::Key, rhs: &mut Self) -> Option<F::Key> {363match (self, rhs) {364(365&mut Self::Inner {366size: ref mut l_size,367keys: ref mut l_keys,368tree: ref mut l_tree,369},370&mut Self::Inner {371size: ref mut r_size,372keys: ref mut r_keys,373tree: ref mut r_tree,374},375) => {376let l_ents = usize::from(*l_size) + 1;377let r_ents = usize::from(*r_size) + 1;378let ents = l_ents + r_ents;379380if ents <= r_tree.len() {381// All entries will fit in the RHS node.382// We'll leave the LHS node empty, but first use it as a scratch space.383*l_size = 0;384// Insert `crit_key` between the two nodes.385l_keys[l_ents - 1] = crit_key;386l_keys[l_ents..ents - 1].copy_from_slice(&r_keys[0..r_ents - 1]);387r_keys[0..ents - 1].copy_from_slice(&l_keys[0..ents - 1]);388l_tree[l_ents..ents].copy_from_slice(&r_tree[0..r_ents]);389r_tree[0..ents].copy_from_slice(&l_tree[0..ents]);390*r_size = (ents - 1) as u8;391None392} else {393// The entries don't all fit in one node. Distribute some from RHS -> LHS.394// Split evenly with a bias to putting one entry in LHS.395let r_goal = ents / 2;396let l_goal = ents - r_goal;397debug_assert!(l_goal > l_ents, "Node must be underflowed");398399l_keys[l_ents - 1] = crit_key;400l_keys[l_ents..l_goal - 1].copy_from_slice(&r_keys[0..l_goal - 1 - l_ents]);401l_tree[l_ents..l_goal].copy_from_slice(&r_tree[0..l_goal - l_ents]);402*l_size = (l_goal - 1) as u8;403404let new_crit = r_keys[r_ents - r_goal - 1];405slice_shift(&mut r_keys[0..r_ents - 1], r_ents - r_goal);406slice_shift(&mut r_tree[0..r_ents], r_ents - r_goal);407*r_size = (r_goal - 1) as u8;408409Some(new_crit)410}411}412(413&mut Self::Leaf {414size: ref mut l_size,415keys: ref mut l_keys,416vals: ref mut l_vals,417},418&mut Self::Leaf {419size: ref mut r_size,420keys: ref mut r_keys,421vals: ref mut r_vals,422},423) => {424let l_ents = usize::from(*l_size);425let l_keys = l_keys.borrow_mut();426let l_vals = l_vals.borrow_mut();427let r_ents = usize::from(*r_size);428let r_keys = r_keys.borrow_mut();429let r_vals = r_vals.borrow_mut();430let ents = l_ents + r_ents;431432if ents <= r_vals.len() {433// We can fit all entries in the RHS node.434// We'll leave the LHS node empty, but first use it as a scratch space.435*l_size = 0;436l_keys[l_ents..ents].copy_from_slice(&r_keys[0..r_ents]);437r_keys[0..ents].copy_from_slice(&l_keys[0..ents]);438l_vals[l_ents..ents].copy_from_slice(&r_vals[0..r_ents]);439r_vals[0..ents].copy_from_slice(&l_vals[0..ents]);440*r_size = ents as u8;441None442} else {443// The entries don't all fit in one node. Distribute some from RHS -> LHS.444// Split evenly with a bias to putting one entry in LHS.445let r_goal = ents / 2;446let l_goal = ents - r_goal;447debug_assert!(l_goal > l_ents, "Node must be underflowed");448449l_keys[l_ents..l_goal].copy_from_slice(&r_keys[0..l_goal - l_ents]);450l_vals[l_ents..l_goal].copy_from_slice(&r_vals[0..l_goal - l_ents]);451*l_size = l_goal as u8;452453slice_shift(&mut r_keys[0..r_ents], r_ents - r_goal);454slice_shift(&mut r_vals[0..r_ents], r_ents - r_goal);455*r_size = r_goal as u8;456457Some(r_keys[0])458}459}460_ => panic!("Mismatched nodes"),461}462}463}464465/// Find the right split position for halving a full node with `len` entries to recover from a466/// failed insertion at `ins`.467///468/// If `len` is even, we should split straight down the middle regardless of `len`.469///470/// If `len` is odd, we should split the node such that the two halves are the same size after the471/// insertion is retried.472fn split_pos(len: usize, ins: usize) -> usize {473// Anticipate `len` being a compile time constant, so this all folds away when `len` is even.474if ins <= len / 2 {475len / 2476} else {477(len + 1) / 2478}479}480481/// The result of splitting off the second half of a node.482pub(super) struct SplitOff<F: Forest> {483/// The number of entries left in the original node which becomes the left-hand-side of the484/// pair. This is the number of outgoing node edges for an inner node, and the number of485/// key-value pairs for a leaf node.486pub lhs_entries: usize,487488/// The number of entries in the new RHS node.489pub rhs_entries: usize,490491/// The critical key separating the LHS and RHS nodes. All keys in the LHS sub-tree are less492/// than the critical key, and all entries in the RHS sub-tree are greater or equal to the493/// critical key.494pub crit_key: F::Key,495496/// The RHS node data containing the elements that were removed from the original node (now the497/// LHS).498pub rhs_data: NodeData<F>,499}500501/// The result of removing an entry from a node.502#[derive(Clone, Copy, Debug, PartialEq, Eq)]503pub(super) enum Removed {504/// An entry was removed, and the node is still in good shape.505Healthy,506507/// The node is in good shape after removing the rightmost element.508Rightmost,509510/// The node has too few entries now, and it should be balanced with a sibling node.511Underflow,512513/// The last entry was removed. For an inner node, this means that the `keys` array is empty514/// and there is just a single sub-tree left.515Empty,516}517518impl Removed {519/// Create a `Removed` status from a size and capacity.520fn new(removed: usize, new_size: usize, capacity: usize) -> Self {521if 2 * new_size >= capacity {522if removed == new_size {523Self::Rightmost524} else {525Self::Healthy526}527} else if new_size > 0 {528Self::Underflow529} else {530Self::Empty531}532}533}534535// Display ": value" or nothing at all for `()`.536pub(super) trait ValDisp {537fn valfmt(&self, f: &mut fmt::Formatter) -> fmt::Result;538}539540impl ValDisp for SetValue {541fn valfmt(&self, _: &mut fmt::Formatter) -> fmt::Result {542Ok(())543}544}545546impl<T: fmt::Display> ValDisp for T {547fn valfmt(&self, f: &mut fmt::Formatter) -> fmt::Result {548write!(f, ":{self}")549}550}551552impl<F> fmt::Display for NodeData<F>553where554F: Forest,555F::Key: fmt::Display,556F::Value: ValDisp,557{558fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {559match *self {560Self::Inner { size, keys, tree } => {561write!(f, "[ {}", tree[0])?;562for i in 0..usize::from(size) {563write!(f, " {} {}", keys[i], tree[i + 1])?;564}565write!(f, " ]")566}567Self::Leaf { size, keys, vals } => {568let keys = keys.borrow();569let vals = vals.borrow();570write!(f, "[")?;571for i in 0..usize::from(size) {572write!(f, " {}", keys[i])?;573vals[i].valfmt(f)?;574}575write!(f, " ]")576}577Self::Free { next: Some(n) } => write!(f, "[ free -> {n} ]"),578Self::Free { next: None } => write!(f, "[ free ]"),579}580}581}582583#[cfg(test)]584mod tests {585use super::*;586use alloc::string::ToString;587use core::mem;588589// Forest impl for a set implementation.590struct TF();591592impl Forest for TF {593type Key = char;594type Value = SetValue;595type LeafKeys = [char; 15];596type LeafValues = [SetValue; 15];597598fn splat_key(key: Self::Key) -> Self::LeafKeys {599[key; 15]600}601602fn splat_value(value: Self::Value) -> Self::LeafValues {603[value; 15]604}605}606607#[test]608fn inner() {609let n1 = Node(1);610let n2 = Node(2);611let n3 = Node(3);612let n4 = Node(4);613let mut inner = NodeData::<TF>::inner(n1, 'c', n4);614assert_eq!(mem::size_of_val(&inner), 64);615assert_eq!(inner.to_string(), "[ node1 c node4 ]");616617assert!(inner.try_inner_insert(0, 'a', n2));618assert_eq!(inner.to_string(), "[ node1 a node2 c node4 ]");619620assert!(inner.try_inner_insert(1, 'b', n3));621assert_eq!(inner.to_string(), "[ node1 a node2 b node3 c node4 ]");622623for i in 3..7 {624assert!(inner.try_inner_insert(625usize::from(i),626('a' as u8 + i) as char,627Node(i as u32 + 2),628));629}630assert_eq!(631inner.to_string(),632"[ node1 a node2 b node3 c node4 d node5 e node6 f node7 g node8 ]"633);634635// Now the node is full and insertion should fail anywhere.636assert!(!inner.try_inner_insert(0, 'x', n3));637assert!(!inner.try_inner_insert(4, 'x', n3));638assert!(!inner.try_inner_insert(7, 'x', n3));639640// Splitting should be independent of the hint because we have an even number of node641// references.642let saved = inner;643let sp = inner.split(1);644assert_eq!(sp.lhs_entries, 4);645assert_eq!(sp.rhs_entries, 4);646assert_eq!(sp.crit_key, 'd');647// The critical key is not present in either of the resulting nodes.648assert_eq!(inner.to_string(), "[ node1 a node2 b node3 c node4 ]");649assert_eq!(sp.rhs_data.to_string(), "[ node5 e node6 f node7 g node8 ]");650651assert_eq!(inner.inner_remove(0), Removed::Underflow);652assert_eq!(inner.to_string(), "[ node2 b node3 c node4 ]");653654assert_eq!(inner.inner_remove(1), Removed::Underflow);655assert_eq!(inner.to_string(), "[ node2 c node4 ]");656657assert_eq!(inner.inner_remove(1), Removed::Underflow);658assert_eq!(inner.to_string(), "[ node2 ]");659660assert_eq!(inner.inner_remove(0), Removed::Empty);661662inner = saved;663let sp = inner.split(6);664assert_eq!(sp.lhs_entries, 4);665assert_eq!(sp.rhs_entries, 4);666assert_eq!(sp.crit_key, 'd');667assert_eq!(inner.to_string(), "[ node1 a node2 b node3 c node4 ]");668assert_eq!(sp.rhs_data.to_string(), "[ node5 e node6 f node7 g node8 ]");669}670671#[test]672fn leaf() {673let mut leaf = NodeData::<TF>::leaf('d', SetValue());674assert_eq!(leaf.to_string(), "[ d ]");675676assert!(leaf.try_leaf_insert(0, 'a', SetValue()));677assert_eq!(leaf.to_string(), "[ a d ]");678assert!(leaf.try_leaf_insert(1, 'b', SetValue()));679assert!(leaf.try_leaf_insert(2, 'c', SetValue()));680assert_eq!(leaf.to_string(), "[ a b c d ]");681for i in 4..15 {682assert!(leaf.try_leaf_insert(usize::from(i), ('a' as u8 + i) as char, SetValue()));683}684assert_eq!(leaf.to_string(), "[ a b c d e f g h i j k l m n o ]");685686// Now the node is full and insertion should fail anywhere.687assert!(!leaf.try_leaf_insert(0, 'x', SetValue()));688assert!(!leaf.try_leaf_insert(8, 'x', SetValue()));689assert!(!leaf.try_leaf_insert(15, 'x', SetValue()));690691// The index given to `split` is not the split position, it's a hint for balancing the node.692let saved = leaf;693let sp = leaf.split(12);694assert_eq!(sp.lhs_entries, 8);695assert_eq!(sp.rhs_entries, 7);696assert_eq!(sp.crit_key, 'i');697assert_eq!(leaf.to_string(), "[ a b c d e f g h ]");698assert_eq!(sp.rhs_data.to_string(), "[ i j k l m n o ]");699700assert!(leaf.try_leaf_insert(8, 'i', SetValue()));701assert_eq!(leaf.leaf_remove(2), Removed::Healthy);702assert_eq!(leaf.to_string(), "[ a b d e f g h i ]");703assert_eq!(leaf.leaf_remove(7), Removed::Underflow);704assert_eq!(leaf.to_string(), "[ a b d e f g h ]");705706leaf = saved;707let sp = leaf.split(7);708assert_eq!(sp.lhs_entries, 7);709assert_eq!(sp.rhs_entries, 8);710assert_eq!(sp.crit_key, 'h');711assert_eq!(leaf.to_string(), "[ a b c d e f g ]");712assert_eq!(sp.rhs_data.to_string(), "[ h i j k l m n o ]");713}714715#[test]716fn optimal_split_pos() {717// An even split is easy.718assert_eq!(split_pos(8, 0), 4);719assert_eq!(split_pos(8, 8), 4);720721// Easy cases for odd splits.722assert_eq!(split_pos(7, 0), 3);723assert_eq!(split_pos(7, 7), 4);724725// If the insertion point is the same as the split position, we726// will append to the lhs node.727assert_eq!(split_pos(7, 3), 3);728assert_eq!(split_pos(7, 4), 4);729}730731#[test]732fn inner_balance() {733let n1 = Node(1);734let n2 = Node(2);735let n3 = Node(3);736let mut lhs = NodeData::<TF>::inner(n1, 'a', n2);737assert!(lhs.try_inner_insert(1, 'b', n3));738assert_eq!(lhs.to_string(), "[ node1 a node2 b node3 ]");739740let n11 = Node(11);741let n12 = Node(12);742let mut rhs = NodeData::<TF>::inner(n11, 'p', n12);743744for i in 1..4 {745assert!(rhs.try_inner_insert(746usize::from(i),747('p' as u8 + i) as char,748Node(i as u32 + 12),749));750}751assert_eq!(752rhs.to_string(),753"[ node11 p node12 q node13 r node14 s node15 ]"754);755756// 3+5 elements fit in RHS.757assert_eq!(lhs.balance('o', &mut rhs), None);758assert_eq!(759rhs.to_string(),760"[ node1 a node2 b node3 o node11 p node12 q node13 r node14 s node15 ]"761);762763// 2+8 elements are redistributed.764lhs = NodeData::<TF>::inner(Node(20), 'x', Node(21));765assert_eq!(lhs.balance('y', &mut rhs), Some('o'));766assert_eq!(767lhs.to_string(),768"[ node20 x node21 y node1 a node2 b node3 ]"769);770assert_eq!(771rhs.to_string(),772"[ node11 p node12 q node13 r node14 s node15 ]"773);774}775776#[test]777fn leaf_balance() {778let mut lhs = NodeData::<TF>::leaf('a', SetValue());779for i in 1..6 {780assert!(lhs.try_leaf_insert(usize::from(i), ('a' as u8 + i) as char, SetValue()));781}782assert_eq!(lhs.to_string(), "[ a b c d e f ]");783784let mut rhs = NodeData::<TF>::leaf('0', SetValue());785for i in 1..8 {786assert!(rhs.try_leaf_insert(usize::from(i), ('0' as u8 + i) as char, SetValue()));787}788assert_eq!(rhs.to_string(), "[ 0 1 2 3 4 5 6 7 ]");789790// 6+8 elements all fits in rhs.791assert_eq!(lhs.balance('0', &mut rhs), None);792assert_eq!(rhs.to_string(), "[ a b c d e f 0 1 2 3 4 5 6 7 ]");793794assert!(lhs.try_leaf_insert(0, 'x', SetValue()));795assert!(lhs.try_leaf_insert(1, 'y', SetValue()));796assert!(lhs.try_leaf_insert(2, 'z', SetValue()));797assert_eq!(lhs.to_string(), "[ x y z ]");798799// 3+14 elements need redistribution.800assert_eq!(lhs.balance('a', &mut rhs), Some('0'));801assert_eq!(lhs.to_string(), "[ x y z a b c d e f ]");802assert_eq!(rhs.to_string(), "[ 0 1 2 3 4 5 6 7 ]");803}804}805806807