//! Forest of maps. use super::{Comparator, Forest, INNER_SIZE, Node, NodeData, NodePool, Path}; use crate::packed_option::PackedOption; #[cfg(test)] use alloc::string::String; #[cfg(test)] use core::fmt; use core::{ marker::PhantomData, mem, ops::{Bound, RangeBounds}, }; use wasmtime_core::{alloc::PanicOnOom as _, error::OutOfMemory}; /// Tag type defining forest types for a map. struct MapTypes(PhantomData<(K, V)>); impl Forest for MapTypes where K: Copy, V: Copy, { type Key = K; type Value = V; type LeafKeys = [K; INNER_SIZE - 1]; type LeafValues = [V; INNER_SIZE - 1]; fn splat_key(key: Self::Key) -> Self::LeafKeys { [key; INNER_SIZE - 1] } fn splat_value(value: Self::Value) -> Self::LeafValues { [value; INNER_SIZE - 1] } } /// Memory pool for a forest of `Map` instances. pub struct MapForest where K: Copy, V: Copy, { nodes: NodePool>, } impl MapForest where K: Copy, V: Copy, { /// Create a new empty forest. pub fn new() -> Self { Self { nodes: NodePool::new(), } } /// Clear all maps in the forest. /// /// All `Map` instances belong to this forest are invalidated and should no longer be used. pub fn clear(&mut self) { self.nodes.clear(); } } /// B-tree mapping from `K` to `V`. /// /// This is not a general-purpose replacement for `BTreeMap`. See the [module /// documentation](index.html) for more information about design tradeoffs. /// /// Maps can be cloned, but that operation should only be used as part of cloning the whole forest /// they belong to. *Cloning a map does not allocate new memory for the clone*. It creates an alias /// of the same memory. #[derive(Clone)] pub struct Map where K: Copy, V: Copy, { root: PackedOption, unused: PhantomData<(K, V)>, } impl Map where K: Copy, V: Copy, { /// Make an empty map. pub fn new() -> Self { Self { root: None.into(), unused: PhantomData, } } /// Is this an empty map? pub fn is_empty(&self) -> bool { self.root.is_none() } /// Get the value stored for `key`. pub fn get>(&self, key: K, forest: &MapForest, comp: &C) -> Option { self.root .expand() .and_then(|root| Path::default().find(key, root, &forest.nodes, comp)) } /// Look up the value stored for `key`. /// /// If it exists, return the stored key-value pair. /// /// Otherwise, return the last key-value pair with a key that is less than or equal to `key`. /// /// If no stored keys are less than or equal to `key`, return `None`. pub fn get_or_less>( &self, key: K, forest: &MapForest, comp: &C, ) -> Option<(K, V)> { self.root.expand().and_then(|root| { let mut path = Path::default(); match path.find(key, root, &forest.nodes, comp) { Some(v) => Some((key, v)), None => path.prev(root, &forest.nodes), } }) } /// Insert `key, value` into the map and return the old value stored for `key`, if any. pub fn insert>( &mut self, key: K, value: V, forest: &mut MapForest, comp: &C, ) -> Option { self.cursor_mut(forest, comp).insert(key, value) } /// Like `insert` but returns an error on allocation failure. pub fn try_insert>( &mut self, key: K, value: V, forest: &mut MapForest, comp: &C, ) -> Result, OutOfMemory> { self.cursor_mut(forest, comp).try_insert(key, value) } /// Remove `key` from the map and return the removed value for `key`, if any. pub fn remove>( &mut self, key: K, forest: &mut MapForest, comp: &C, ) -> Option { let mut c = self.cursor_mut(forest, comp); if c.goto(key).is_some() { c.remove() } else { None } } /// Remove all entries. pub fn clear(&mut self, forest: &mut MapForest) { if let Some(root) = self.root.take() { forest.nodes.free_tree(root); } } /// Retains only the elements specified by the predicate. /// /// Remove all key-value pairs where the predicate returns false. /// /// The predicate is allowed to update the values stored in the map. pub fn retain(&mut self, forest: &mut MapForest, mut predicate: F) where F: FnMut(K, &mut V) -> bool, { let mut path = Path::default(); if let Some(root) = self.root.expand() { path.first(root, &forest.nodes); } while let Some((node, entry)) = path.leaf_pos() { let keep = { let (ks, vs) = forest.nodes[node].unwrap_leaf_mut(); predicate(ks[entry], &mut vs[entry]) }; if keep { path.next(&forest.nodes); } else { self.root = path.remove(&mut forest.nodes).into(); } } } /// Create an immutable cursor for navigating this map. /// /// The cursor is initially positioned off the end of the map. pub fn cursor<'a, C: Comparator>( &'a self, forest: &'a MapForest, comp: &'a C, ) -> MapCursor<'a, K, V, C> { MapCursor::new(self, forest, comp) } /// Create a mutable cursor for navigating this map. /// /// The cursor is initially positioned off the end of the map. pub fn cursor_mut<'a, C: Comparator>( &'a mut self, forest: &'a mut MapForest, comp: &'a C, ) -> MapCursorMut<'a, K, V, C> { MapCursorMut::new(self, forest, comp) } /// Create an iterator traversing this map. The iterator type is `(K, V)`. pub fn iter<'a>(&'a self, forest: &'a MapForest) -> MapIter<'a, K, V> { MapIter { root: self.root, pool: &forest.nodes, path: Path::default(), } } /// Consume this map and its forest, yielding `(K, V)` pairs from the map. pub fn into_iter(self, forest: MapForest) -> MapIntoIter { MapIntoIter { root: self.root, pool: forest.nodes, path: Path::default(), } } /// Iterate over the entries within the given range. pub fn range<'a, R, C>( &'a self, range: R, forest: &'a MapForest, comp: &'a C, ) -> MapRange<'a, K, V, C> where R: RangeBounds, C: Comparator, { MapRange { cursor: self.cursor(forest, comp), start: copied_bound(range.start_bound()), end: copied_bound(range.end_bound()), direction: Direction::None, } } } fn copied_bound(start_bound: Bound<&K>) -> Bound where K: Copy, { match start_bound { Bound::Unbounded => Bound::Unbounded, Bound::Included(x) => Bound::Included(*x), Bound::Excluded(x) => Bound::Excluded(*x), } } impl Default for Map where K: Copy, V: Copy, { fn default() -> Self { Self::new() } } #[cfg(test)] impl Map where K: Copy + fmt::Display, V: Copy, { /// Verify consistency. fn verify>(&self, forest: &MapForest, comp: &C) where NodeData>: fmt::Display, { if let Some(root) = self.root.expand() { forest.nodes.verify_tree(root, comp); } } /// Get a text version of the path to `key`. fn tpath>(&self, key: K, forest: &MapForest, comp: &C) -> String { use alloc::string::ToString; match self.root.expand() { None => "map(empty)".to_string(), Some(root) => { let mut path = Path::default(); path.find(key, root, &forest.nodes, comp); path.to_string() } } } } struct MapCursorRaw where K: Copy, V: Copy, { path: Path>, } impl MapCursorRaw where K: Copy, V: Copy, { fn new() -> Self { Self { path: Path::default(), } } fn is_empty(&self, root: &PackedOption) -> bool { root.is_none() } fn next(&mut self, pool: &NodePool>) -> Option<(K, V)> { self.path.next(pool) } fn prev( &mut self, root: &PackedOption, pool: &NodePool>, ) -> Option<(K, V)> { root.expand().and_then(|root| self.path.prev(root, pool)) } fn key(&self, pool: &NodePool>) -> Option { self.path .leaf_pos() .and_then(|(node, entry)| pool[node].unwrap_leaf().0.get(entry).cloned()) } fn value(&self, pool: &NodePool>) -> Option { self.path .leaf_pos() .and_then(|(node, entry)| pool[node].unwrap_leaf().1.get(entry).cloned()) } fn value_mut<'a>(&self, pool: &'a mut NodePool>) -> Option<&'a mut V> { self.path .leaf_pos() .and_then(move |(node, entry)| pool[node].unwrap_leaf_mut().1.get_mut(entry)) } fn goto( &mut self, root: &PackedOption, pool: &NodePool>, elem: K, comp: &impl Comparator, ) -> Option { root.expand().and_then(|root| { let v = self.path.find(elem, root, pool, comp); if v.is_none() { self.path.normalize(pool); } v }) } fn goto_first( &mut self, root: &PackedOption, pool: &NodePool>, ) -> Option { root.map(|root| self.path.first(root, pool).1) } fn goto_end(&mut self) { self.path = Path::default(); } fn insert( &mut self, root: &mut PackedOption, pool: &mut NodePool>, key: K, value: V, comp: &impl Comparator, ) -> Option { self.try_insert(root, pool, key, value, comp).panic_on_oom() } fn try_insert( &mut self, root: &mut PackedOption, pool: &mut NodePool>, key: K, value: V, comp: &impl Comparator, ) -> Result, OutOfMemory> { match root.expand() { None => { let node = pool.alloc_node(NodeData::leaf(key, value))?; *root = node.into(); self.path.set_root_node(node); Ok(None) } Some(r) => { // TODO: Optimize the case where `self.path` is already at the correct insert pos. let old = self.path.find(key, r, pool, comp); if old.is_some() { *self.path.value_mut(pool) = value; } else { *root = self.path.insert(key, value, pool)?.into(); } Ok(old) } } } fn remove( &mut self, root: &mut PackedOption, pool: &mut NodePool>, ) -> Option { let value = self.value(pool); if value.is_some() { *root = self.path.remove(pool).into(); } value } } /// A position in a `Map` used to navigate and modify the ordered map. /// /// A cursor always points at a key-value pair in the map, or "off the end" which is a position /// after the last entry in the map. pub struct MapCursor<'a, K, V, C> where K: 'a + Copy, V: 'a + Copy, C: 'a + Comparator, { root: &'a PackedOption, pool: &'a NodePool>, comp: &'a C, raw: MapCursorRaw, } impl<'a, K, V, C> MapCursor<'a, K, V, C> where K: Copy, V: Copy, C: Comparator, { /// Create a cursor with a default (off-the-end) location. fn new(container: &'a Map, forest: &'a MapForest, comp: &'a C) -> Self { Self { root: &container.root, pool: &forest.nodes, comp, raw: MapCursorRaw::new(), } } /// Is this cursor pointing to an empty map? pub fn is_empty(&self) -> bool { self.raw.is_empty(self.root) } /// Move cursor to the next key-value pair and return it. /// /// If the cursor reaches the end, return `None` and leave the cursor at the off-the-end /// position. pub fn next(&mut self) -> Option<(K, V)> { self.raw.next(self.pool) } /// Move cursor to the previous key-value pair and return it. /// /// If the cursor is already pointing at the first entry, leave it there and return `None`. pub fn prev(&mut self) -> Option<(K, V)> { self.raw.prev(self.root, self.pool) } /// Get the current key, or `None` if the cursor is at the end. pub fn key(&self) -> Option { self.raw.key(self.pool) } /// Get the current value, or `None` if the cursor is at the end. pub fn value(&self) -> Option { self.raw.value(self.pool) } /// Move this cursor to `key`. /// /// If `key` is in the map, place the cursor at `key` and return the corresponding value. /// /// If `key` is not in the set, place the cursor at the next larger element (or the end) and /// return `None`. pub fn goto(&mut self, elem: K) -> Option { self.raw.goto(self.root, self.pool, elem, self.comp) } /// Move this cursor to the first element. pub fn goto_first(&mut self) -> Option { self.raw.goto_first(self.root, self.pool) } /// Move the cursor to the off-the-end location. pub fn goto_end(&mut self) { self.raw.goto_end(); } } /// A position in a `Map` used to navigate and modify the ordered map. /// /// A cursor always points at a key-value pair in the map, or "off the end" which is a position /// after the last entry in the map. pub struct MapCursorMut<'a, K, V, C> where K: 'a + Copy, V: 'a + Copy, C: 'a + Comparator, { root: &'a mut PackedOption, pool: &'a mut NodePool>, comp: &'a C, raw: MapCursorRaw, } impl<'a, K, V, C> MapCursorMut<'a, K, V, C> where K: Copy, V: Copy, C: Comparator, { /// Create a cursor with a default (off-the-end) location. fn new(container: &'a mut Map, forest: &'a mut MapForest, comp: &'a C) -> Self { Self { root: &mut container.root, pool: &mut forest.nodes, comp, raw: MapCursorRaw::new(), } } /// Is this cursor pointing to an empty map? pub fn is_empty(&self) -> bool { self.raw.is_empty(self.root) } /// Move cursor to the next key-value pair and return it. /// /// If the cursor reaches the end, return `None` and leave the cursor at the off-the-end /// position. pub fn next(&mut self) -> Option<(K, V)> { self.raw.next(self.pool) } /// Move cursor to the previous key-value pair and return it. /// /// If the cursor is already pointing at the first entry, leave it there and return `None`. pub fn prev(&mut self) -> Option<(K, V)> { self.raw.prev(self.root, self.pool) } /// Get the current key, or `None` if the cursor is at the end. pub fn key(&self) -> Option { self.raw.key(self.pool) } /// Get the current value, or `None` if the cursor is at the end. pub fn value(&self) -> Option { self.raw.value(self.pool) } /// Get a mutable reference to the current value, or `None` if the cursor is at the end. pub fn value_mut(&mut self) -> Option<&mut V> { self.raw.value_mut(self.pool) } /// Move this cursor to `key`. /// /// If `key` is in the map, place the cursor at `key` and return the corresponding value. /// /// If `key` is not in the set, place the cursor at the next larger element (or the end) and /// return `None`. pub fn goto(&mut self, elem: K) -> Option { self.raw.goto(self.root, self.pool, elem, self.comp) } /// Move this cursor to the first element. pub fn goto_first(&mut self) -> Option { self.raw.goto_first(self.root, self.pool) } /// Insert `(key, value))` into the map and leave the cursor at the inserted pair. /// /// If the map did not contain `key`, return `None`. /// /// If `key` is already present, replace the existing with `value` and return the old value. pub fn insert(&mut self, key: K, value: V) -> Option { self.raw.insert(self.root, self.pool, key, value, self.comp) } /// Like `insert` but returns an error on allocation failure. pub fn try_insert(&mut self, key: K, value: V) -> Result, OutOfMemory> { self.raw .try_insert(self.root, self.pool, key, value, self.comp) } /// Remove the current entry (if any) and return the mapped value. /// This advances the cursor to the next entry after the removed one. pub fn remove(&mut self) -> Option { self.raw.remove(self.root, self.pool) } } /// An iterator visiting the key-value pairs of a `Map`. pub struct MapIter<'a, K, V> where K: 'a + Copy, V: 'a + Copy, { root: PackedOption, pool: &'a NodePool>, path: Path>, } impl<'a, K, V> Iterator for MapIter<'a, K, V> where K: 'a + Copy, V: 'a + Copy, { type Item = (K, V); fn next(&mut self) -> Option { // We use `self.root` to indicate if we need to go to the first element. Reset to `None` // once we've returned the first element. This also works for an empty tree since the // `path.next()` call returns `None` when the path is empty. This also fuses the iterator. match self.root.take() { Some(root) => Some(self.path.first(root, self.pool)), None => self.path.next(self.pool), } } } /// A consuming iterator of a `Map`, yielding its key-value pairs. pub struct MapIntoIter where K: Copy, V: Copy, { root: PackedOption, pool: NodePool>, path: Path>, } impl Iterator for MapIntoIter where K: Copy, V: Copy, { type Item = (K, V); fn next(&mut self) -> Option { // We use `self.root` to indicate if we need to go to the first element. Reset to `None` // once we've returned the first element. This also works for an empty tree since the // `path.next()` call returns `None` when the path is empty. This also fuses the iterator. match self.root.take() { Some(root) => Some(self.path.first(root, &self.pool)), None => self.path.next(&self.pool), } } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum Direction { None, Next, NextBack, } /// An immutable iterator over a range of values, returned by `Map::range`. pub struct MapRange<'a, K, V, C> where K: Copy, V: Copy, C: Comparator, { cursor: MapCursor<'a, K, V, C>, start: Bound, end: Bound, /// The direction of the last call into the iterator, a.k.a. whether /// `self.cursor` is /// /// 1. `Direction::Next`: just before `self.start`, /// /// 2. `Direction::NextBack`: just after `self.end`, or /// /// 3. `Direction::None`: not initialized to any location yet. direction: Direction, } impl<'a, K, V, C> Iterator for MapRange<'a, K, V, C> where K: Copy, V: Copy, C: Comparator, { type Item = (K, V); fn next(&mut self) -> Option { let old_direction = mem::replace(&mut self.direction, Direction::Next); let key_val = (|| { if old_direction == Direction::Next { self.cursor.next() } else { match self.start { Bound::Included(k) => { self.cursor.goto(k); Some((self.cursor.key()?, self.cursor.value()?)) } Bound::Excluded(k) => { self.cursor.goto(k); if self .cursor .key() .is_some_and(|key| self.cursor.comp.cmp(k, key).is_eq()) { self.cursor.next() } else { Some((self.cursor.key()?, self.cursor.value()?)) } } Bound::Unbounded => { let val = self.cursor.goto_first()?; Some((self.cursor.key()?, val)) } } } })(); match key_val { Some((key, val)) if self.is_in_bounds(key) => { self.start = Bound::Excluded(key); Some((key, val)) } _ => { self.cursor.goto_end(); None } } } } impl<'a, K, V, C> DoubleEndedIterator for MapRange<'a, K, V, C> where K: Copy, V: Copy, C: Comparator, { fn next_back(&mut self) -> Option { let old_direction = mem::replace(&mut self.direction, Direction::NextBack); let key_val = (|| { if old_direction == Direction::NextBack { self.cursor.prev() } else { match self.end { Bound::Included(k) => match self.cursor.goto(k) { Some(_) => Some((self.cursor.key()?, self.cursor.value()?)), None => self.cursor.prev(), }, Bound::Excluded(k) => { self.cursor.goto(k); if self .cursor .key() .is_some_and(|key| self.cursor.comp.cmp(k, key).is_eq()) { self.cursor.prev() } else { Some((self.cursor.key()?, self.cursor.value()?)) } } Bound::Unbounded => { self.cursor.goto_end(); self.cursor.prev() } } } })(); match key_val { Some((key, val)) if self.is_in_bounds(key) => { self.end = Bound::Excluded(key); Some((key, val)) } _ => { self.cursor.goto_end(); None } } } } impl<'a, K, V, C> MapRange<'a, K, V, C> where K: Copy, V: Copy, C: Comparator, { fn is_in_bounds(&self, key: K) -> bool { self.is_in_start_bound(key) && self.is_in_end_bound(key) } fn is_in_start_bound(&self, key: K) -> bool { match self.start { Bound::Included(k) => self.cursor.comp.cmp(key, k).is_ge(), Bound::Excluded(k) => self.cursor.comp.cmp(key, k).is_gt(), Bound::Unbounded => true, } } fn is_in_end_bound(&self, key: K) -> bool { match self.end { Bound::Included(k) => self.cursor.comp.cmp(k, key).is_ge(), Bound::Excluded(k) => self.cursor.comp.cmp(k, key).is_gt(), Bound::Unbounded => true, } } } #[cfg(test)] impl<'a, K, V, C> MapCursorMut<'a, K, V, C> where K: Copy + fmt::Display, V: Copy + fmt::Display, C: Comparator, { fn verify(&self) { self.raw.path.verify(self.pool); self.root.map(|root| self.pool.verify_tree(root, self.comp)); } /// Get a text version of the path to the current position. fn tpath(&self) -> String { use alloc::string::ToString; self.raw.path.to_string() } } #[cfg(test)] mod tests { use super::*; use alloc::{vec, vec::Vec}; use core::mem; #[test] fn node_size() { // check that nodes are cache line sized when keys and values are 32 bits. type F = MapTypes; assert_eq!(mem::size_of::>(), 64); } #[test] fn empty() { let mut f = MapForest::::new(); f.clear(); let mut m = Map::::new(); assert!(m.is_empty()); m.clear(&mut f); assert_eq!(m.get(7, &f, &()), None); assert_eq!(m.iter(&f).next(), None); assert_eq!(m.get_or_less(7, &f, &()), None); m.retain(&mut f, |_, _| unreachable!()); let mut c = m.cursor_mut(&mut f, &()); assert!(c.is_empty()); assert_eq!(c.key(), None); assert_eq!(c.value(), None); assert_eq!(c.next(), None); assert_eq!(c.prev(), None); c.verify(); assert_eq!(c.tpath(), ""); assert_eq!(c.goto_first(), None); assert_eq!(c.tpath(), ""); } #[test] fn inserting() { let f = &mut MapForest::::new(); let mut m = Map::::new(); // The first seven values stay in a single leaf node. assert_eq!(m.insert(50, 5.0, f, &()), None); assert_eq!(m.insert(50, 5.5, f, &()), Some(5.0)); assert_eq!(m.insert(20, 2.0, f, &()), None); assert_eq!(m.insert(80, 8.0, f, &()), None); assert_eq!(m.insert(40, 4.0, f, &()), None); assert_eq!(m.insert(60, 6.0, f, &()), None); assert_eq!(m.insert(90, 9.0, f, &()), None); assert_eq!(m.insert(200, 20.0, f, &()), None); m.verify(f, &()); assert_eq!( m.iter(f).collect::>(), [ (20, 2.0), (40, 4.0), (50, 5.5), (60, 6.0), (80, 8.0), (90, 9.0), (200, 20.0), ] ); assert_eq!(m.get(0, f, &()), None); assert_eq!(m.get(20, f, &()), Some(2.0)); assert_eq!(m.get(30, f, &()), None); assert_eq!(m.get(40, f, &()), Some(4.0)); assert_eq!(m.get(50, f, &()), Some(5.5)); assert_eq!(m.get(60, f, &()), Some(6.0)); assert_eq!(m.get(70, f, &()), None); assert_eq!(m.get(80, f, &()), Some(8.0)); assert_eq!(m.get(100, f, &()), None); assert_eq!(m.get_or_less(0, f, &()), None); assert_eq!(m.get_or_less(20, f, &()), Some((20, 2.0))); assert_eq!(m.get_or_less(30, f, &()), Some((20, 2.0))); assert_eq!(m.get_or_less(40, f, &()), Some((40, 4.0))); assert_eq!(m.get_or_less(200, f, &()), Some((200, 20.0))); assert_eq!(m.get_or_less(201, f, &()), Some((200, 20.0))); { let mut c = m.cursor_mut(f, &()); assert_eq!(c.prev(), Some((200, 20.0))); assert_eq!(c.prev(), Some((90, 9.0))); assert_eq!(c.prev(), Some((80, 8.0))); assert_eq!(c.prev(), Some((60, 6.0))); assert_eq!(c.prev(), Some((50, 5.5))); assert_eq!(c.prev(), Some((40, 4.0))); assert_eq!(c.prev(), Some((20, 2.0))); assert_eq!(c.prev(), None); } // Test some removals where the node stays healthy. assert_eq!(m.tpath(50, f, &()), "node0[2]"); assert_eq!(m.tpath(80, f, &()), "node0[4]"); assert_eq!(m.tpath(200, f, &()), "node0[6]"); assert_eq!(m.remove(80, f, &()), Some(8.0)); assert_eq!(m.tpath(50, f, &()), "node0[2]"); assert_eq!(m.tpath(80, f, &()), "node0[4]"); assert_eq!(m.tpath(200, f, &()), "node0[5]"); assert_eq!(m.remove(80, f, &()), None); m.verify(f, &()); assert_eq!(m.remove(20, f, &()), Some(2.0)); assert_eq!(m.tpath(50, f, &()), "node0[1]"); assert_eq!(m.tpath(80, f, &()), "node0[3]"); assert_eq!(m.tpath(200, f, &()), "node0[4]"); assert_eq!(m.remove(20, f, &()), None); m.verify(f, &()); // [ 40 50 60 90 200 ] { let mut c = m.cursor_mut(f, &()); assert_eq!(c.goto_first(), Some(4.0)); assert_eq!(c.key(), Some(40)); assert_eq!(c.value(), Some(4.0)); assert_eq!(c.next(), Some((50, 5.5))); assert_eq!(c.next(), Some((60, 6.0))); assert_eq!(c.next(), Some((90, 9.0))); assert_eq!(c.next(), Some((200, 20.0))); c.verify(); assert_eq!(c.next(), None); c.verify(); } // Removals from the root leaf node beyond underflow. assert_eq!(m.remove(200, f, &()), Some(20.0)); assert_eq!(m.remove(40, f, &()), Some(4.0)); assert_eq!(m.remove(60, f, &()), Some(6.0)); m.verify(f, &()); assert_eq!(m.remove(50, f, &()), Some(5.5)); m.verify(f, &()); assert_eq!(m.remove(90, f, &()), Some(9.0)); m.verify(f, &()); assert!(m.is_empty()); } #[test] fn split_level0_leaf() { // Various ways of splitting a full leaf node at level 0. let f = &mut MapForest::::new(); fn full_leaf(f: &mut MapForest) -> Map { let mut m = Map::new(); for n in 1..8 { m.insert(n * 10, n as f32 * 1.1, f, &()); } m } // Insert at front of leaf. let mut m = full_leaf(f); m.insert(5, 4.2, f, &()); m.verify(f, &()); assert_eq!(m.get(5, f, &()), Some(4.2)); // Retain even entries, with altered values. m.retain(f, |k, v| { *v = (k / 10) as f32; (k % 20) == 0 }); assert_eq!( m.iter(f).collect::>(), [(20, 2.0), (40, 4.0), (60, 6.0)] ); // Insert at back of leaf. let mut m = full_leaf(f); m.insert(80, 4.2, f, &()); m.verify(f, &()); assert_eq!(m.get(80, f, &()), Some(4.2)); // Insert before middle (40). let mut m = full_leaf(f); m.insert(35, 4.2, f, &()); m.verify(f, &()); assert_eq!(m.get(35, f, &()), Some(4.2)); // Insert after middle (40). let mut m = full_leaf(f); m.insert(45, 4.2, f, &()); m.verify(f, &()); assert_eq!(m.get(45, f, &()), Some(4.2)); m.clear(f); assert!(m.is_empty()); } #[test] fn split_level1_leaf() { // Various ways of splitting a full leaf node at level 1. let f = &mut MapForest::::new(); // Return a map whose root node is a full inner node, and the leaf nodes are all full // containing: // // 110, 120, ..., 170 // 210, 220, ..., 270 // ... // 810, 820, ..., 870 fn full(f: &mut MapForest) -> Map { let mut m = Map::new(); // Start by inserting elements in order. // This should leave 8 leaf nodes with 4 elements in each. for row in 1..9 { for col in 1..5 { m.insert(row * 100 + col * 10, row as f32 + col as f32 * 0.1, f, &()); } } // Then top up the leaf nodes without splitting them. for row in 1..9 { for col in 5..8 { m.insert(row * 100 + col * 10, row as f32 + col as f32 * 0.1, f, &()); } } m } let mut m = full(f); // Verify geometry. Get get node2 as the root and leaves node0, 1, 3, ... m.verify(f, &()); assert_eq!(m.tpath(110, f, &()), "node2[0]--node0[0]"); assert_eq!(m.tpath(140, f, &()), "node2[0]--node0[3]"); assert_eq!(m.tpath(210, f, &()), "node2[1]--node1[0]"); assert_eq!(m.tpath(270, f, &()), "node2[1]--node1[6]"); assert_eq!(m.tpath(310, f, &()), "node2[2]--node3[0]"); assert_eq!(m.tpath(810, f, &()), "node2[7]--node8[0]"); assert_eq!(m.tpath(870, f, &()), "node2[7]--node8[6]"); { let mut c = m.cursor_mut(f, &()); assert_eq!(c.goto_first(), Some(1.1)); assert_eq!(c.key(), Some(110)); } // Front of first leaf. m.insert(0, 4.2, f, &()); m.verify(f, &()); assert_eq!(m.get(0, f, &()), Some(4.2)); // First leaf split 4-4 after appending to LHS. f.clear(); m = full(f); m.insert(135, 4.2, f, &()); m.verify(f, &()); assert_eq!(m.get(135, f, &()), Some(4.2)); // First leaf split 4-4 after prepending to RHS. f.clear(); m = full(f); m.insert(145, 4.2, f, &()); m.verify(f, &()); assert_eq!(m.get(145, f, &()), Some(4.2)); // First leaf split 4-4 after appending to RHS. f.clear(); m = full(f); m.insert(175, 4.2, f, &()); m.verify(f, &()); assert_eq!(m.get(175, f, &()), Some(4.2)); // Left-middle leaf split, ins LHS. f.clear(); m = full(f); m.insert(435, 4.2, f, &()); m.verify(f, &()); assert_eq!(m.get(435, f, &()), Some(4.2)); // Left-middle leaf split, ins RHS. f.clear(); m = full(f); m.insert(445, 4.2, f, &()); m.verify(f, &()); assert_eq!(m.get(445, f, &()), Some(4.2)); // Right-middle leaf split, ins LHS. f.clear(); m = full(f); m.insert(535, 4.2, f, &()); m.verify(f, &()); assert_eq!(m.get(535, f, &()), Some(4.2)); // Right-middle leaf split, ins RHS. f.clear(); m = full(f); m.insert(545, 4.2, f, &()); m.verify(f, &()); assert_eq!(m.get(545, f, &()), Some(4.2)); // Last leaf split, ins LHS. f.clear(); m = full(f); m.insert(835, 4.2, f, &()); m.verify(f, &()); assert_eq!(m.get(835, f, &()), Some(4.2)); // Last leaf split, ins RHS. f.clear(); m = full(f); m.insert(845, 4.2, f, &()); m.verify(f, &()); assert_eq!(m.get(845, f, &()), Some(4.2)); // Front of last leaf. f.clear(); m = full(f); m.insert(805, 4.2, f, &()); m.verify(f, &()); assert_eq!(m.get(805, f, &()), Some(4.2)); m.clear(f); m.verify(f, &()); } // Make a tree with two barely healthy leaf nodes: // [ 10 20 30 40 ] [ 50 60 70 80 ] fn two_leaf(f: &mut MapForest) -> Map { f.clear(); let mut m = Map::new(); for n in 1..9 { m.insert(n * 10, n as f32, f, &()); } m } #[test] fn remove_level1() { let f = &mut MapForest::::new(); let mut m = two_leaf(f); // Verify geometry. m.verify(f, &()); assert_eq!(m.tpath(10, f, &()), "node2[0]--node0[0]"); assert_eq!(m.tpath(40, f, &()), "node2[0]--node0[3]"); assert_eq!(m.tpath(49, f, &()), "node2[0]--node0[4]"); assert_eq!(m.tpath(50, f, &()), "node2[1]--node1[0]"); assert_eq!(m.tpath(80, f, &()), "node2[1]--node1[3]"); // Remove the front entry from a node that stays healthy. assert_eq!(m.insert(55, 5.5, f, &()), None); assert_eq!(m.remove(50, f, &()), Some(5.0)); m.verify(f, &()); assert_eq!(m.tpath(49, f, &()), "node2[0]--node0[4]"); assert_eq!(m.tpath(50, f, &()), "node2[0]--node0[4]"); assert_eq!(m.tpath(55, f, &()), "node2[1]--node1[0]"); // Remove the front entry from the first leaf node: No critical key to update. assert_eq!(m.insert(15, 1.5, f, &()), None); assert_eq!(m.remove(10, f, &()), Some(1.0)); m.verify(f, &()); // [ 15 20 30 40 ] [ 55 60 70 80 ] // Remove the front entry from a right-most node that underflows. // No rebalancing for the right-most node. Still need critical key update. assert_eq!(m.remove(55, f, &()), Some(5.5)); m.verify(f, &()); assert_eq!(m.tpath(55, f, &()), "node2[0]--node0[4]"); assert_eq!(m.tpath(60, f, &()), "node2[1]--node1[0]"); // [ 15 20 30 40 ] [ 60 70 80 ] // Replenish the right leaf. assert_eq!(m.insert(90, 9.0, f, &()), None); assert_eq!(m.insert(100, 10.0, f, &()), None); m.verify(f, &()); assert_eq!(m.tpath(55, f, &()), "node2[0]--node0[4]"); assert_eq!(m.tpath(60, f, &()), "node2[1]--node1[0]"); // [ 15 20 30 40 ] [ 60 70 80 90 100 ] // Removing one entry from the left leaf should trigger a rebalancing from the right // sibling. assert_eq!(m.remove(20, f, &()), Some(2.0)); m.verify(f, &()); // [ 15 30 40 60 ] [ 70 80 90 100 ] // Check that the critical key was updated correctly. assert_eq!(m.tpath(50, f, &()), "node2[0]--node0[3]"); assert_eq!(m.tpath(60, f, &()), "node2[0]--node0[3]"); assert_eq!(m.tpath(70, f, &()), "node2[1]--node1[0]"); // Remove front entry from the left-most leaf node, underflowing. // This should cause two leaf nodes to be merged and the root node to go away. assert_eq!(m.remove(15, f, &()), Some(1.5)); m.verify(f, &()); } #[test] fn remove_level1_rightmost() { let f = &mut MapForest::::new(); let mut m = two_leaf(f); // [ 10 20 30 40 ] [ 50 60 70 80 ] // Remove entries from the right leaf. This doesn't trigger a rebalancing. assert_eq!(m.remove(60, f, &()), Some(6.0)); assert_eq!(m.remove(80, f, &()), Some(8.0)); assert_eq!(m.remove(50, f, &()), Some(5.0)); m.verify(f, &()); // [ 10 20 30 40 ] [ 70 ] assert_eq!(m.tpath(50, f, &()), "node2[0]--node0[4]"); assert_eq!(m.tpath(70, f, &()), "node2[1]--node1[0]"); // Removing the last entry from the right leaf should cause a collapse. assert_eq!(m.remove(70, f, &()), Some(7.0)); m.verify(f, &()); } // Make a 3-level tree with barely healthy nodes. // 1 root, 8 inner nodes, 7*4+5=33 leaf nodes, 4 entries each. fn level3_sparse(f: &mut MapForest) -> Map { f.clear(); let mut m = Map::new(); for n in 1..133 { m.insert(n * 10, n as f32, f, &()); } m } #[test] fn level3_removes() { let f = &mut MapForest::::new(); let mut m = level3_sparse(f); m.verify(f, &()); // Check geometry. // Root: node11 // [ node2 170 node10 330 node16 490 node21 650 node26 810 node31 970 node36 1130 node41 ] // L1: node11 assert_eq!(m.tpath(0, f, &()), "node11[0]--node2[0]--node0[0]"); assert_eq!(m.tpath(10000, f, &()), "node11[7]--node41[4]--node40[4]"); // 650 is a critical key in the middle of the root. assert_eq!(m.tpath(640, f, &()), "node11[3]--node21[3]--node19[3]"); assert_eq!(m.tpath(650, f, &()), "node11[4]--node26[0]--node20[0]"); // Deleting 640 triggers a rebalance from node19 to node 20, cascading to n21 -> n26. assert_eq!(m.remove(640, f, &()), Some(64.0)); m.verify(f, &()); assert_eq!(m.tpath(650, f, &()), "node11[3]--node26[3]--node20[3]"); // 1130 is in the first leaf of the last L1 node. Deleting it triggers a rebalance node35 // -> node37, but no rebalance above where there is no right sibling. assert_eq!(m.tpath(1130, f, &()), "node11[6]--node41[0]--node35[0]"); assert_eq!(m.tpath(1140, f, &()), "node11[6]--node41[0]--node35[1]"); assert_eq!(m.remove(1130, f, &()), Some(113.0)); m.verify(f, &()); assert_eq!(m.tpath(1140, f, &()), "node11[6]--node41[0]--node37[0]"); } #[test] fn insert_many() { let f = &mut MapForest::::new(); let mut m = Map::::new(); let mm = 4096; let mut x = 0; for n in 0..mm { assert_eq!(m.insert(x, n as f32, f, &()), None); m.verify(f, &()); x = (x + n + 1) % mm; } x = 0; for n in 0..mm { assert_eq!(m.get(x, f, &()), Some(n as f32)); x = (x + n + 1) % mm; } x = 0; for n in 0..mm { assert_eq!(m.remove(x, f, &()), Some(n as f32)); m.verify(f, &()); x = (x + n + 1) % mm; } assert!(m.is_empty()); } #[test] fn immutable_cursor() { let f = &mut MapForest::::new(); let mut m = Map::::new(); for i in 100..200 { m.insert(i, i as f32, f, &()); } let mut c = m.cursor(f, &()); let v = c.goto_first().unwrap(); assert_eq!(v, 100.0); assert_eq!(c.key(), Some(100)); assert_eq!(c.value(), Some(100.0)); let (k, v) = c.next().unwrap(); assert_eq!(k, 101); assert_eq!(v, 101.0); assert_eq!(c.key(), Some(101)); assert_eq!(c.value(), Some(101.0)); let (k, v) = c.next().unwrap(); assert_eq!(k, 102); assert_eq!(v, 102.0); assert_eq!(c.key(), Some(102)); assert_eq!(c.value(), Some(102.0)); let (k, v) = c.prev().unwrap(); assert_eq!(k, 101); assert_eq!(v, 101.0); assert_eq!(c.key(), Some(101)); assert_eq!(c.value(), Some(101.0)); let v = c.goto(175).unwrap(); assert_eq!(v, 175.0); assert_eq!(c.key(), Some(175)); assert_eq!(c.value(), Some(175.0)); let (k, v) = c.next().unwrap(); assert_eq!(k, 176); assert_eq!(v, 176.0); assert_eq!(c.key(), Some(176)); assert_eq!(c.value(), Some(176.0)); let (k, v) = c.prev().unwrap(); assert_eq!(k, 175); assert_eq!(v, 175.0); assert_eq!(c.key(), Some(175)); assert_eq!(c.value(), Some(175.0)); let v = c.goto(200); assert!(v.is_none()); assert!(c.key().is_none()); assert!(c.value().is_none()); for i in (100..200).rev() { let (k, v) = c.prev().unwrap(); assert_eq!(k, i); assert_eq!(v, i as f32); assert_eq!(c.key(), Some(i)); assert_eq!(c.value(), Some(i as f32)); } assert!(c.prev().is_none()); assert_eq!(c.key(), Some(100)); assert_eq!(c.value(), Some(100.0)); for i in 101..200 { let (k, v) = c.next().unwrap(); assert_eq!(k, i); assert_eq!(v, i as f32); assert_eq!(c.key(), Some(i)); assert_eq!(c.value(), Some(i as f32)); } assert!(c.next().is_none()); assert!(c.key().is_none()); assert!(c.value().is_none()); } #[test] fn into_iter() { let mut f = MapForest::::new(); let mut m = Map::::new(); for i in 10..20 { m.insert(i, i as f32, &mut f, &()); } assert_eq!( m.into_iter(f).collect::>(), vec![ (10, 10.0), (11, 11.0), (12, 12.0), (13, 13.0), (14, 14.0), (15, 15.0), (16, 16.0), (17, 17.0), (18, 18.0), (19, 19.0), ], ); } #[test] fn range() { let mut f = MapForest::::new(); let mut m = Map::::new(); for i in 10..20 { m.insert(i, i as f32, &mut f, &()); } assert_eq!( m.range(.., &f, &()).collect::>(), vec![ (10, 10.0), (11, 11.0), (12, 12.0), (13, 13.0), (14, 14.0), (15, 15.0), (16, 16.0), (17, 17.0), (18, 18.0), (19, 19.0), ], ); assert_eq!( m.range(5..12, &f, &()).collect::>(), vec![(10, 10.0), (11, 11.0)], ); assert_eq!( m.range(18..30, &f, &()).collect::>(), vec![(18, 18.0), (19, 19.0)], ); assert_eq!( m.range(..13, &f, &()).collect::>(), vec![(10, 10.0), (11, 11.0), (12, 12.0)], ); assert_eq!( m.range(18.., &f, &()).collect::>(), vec![(18, 18.0), (19, 19.0)], ); assert_eq!( m.range(12..=15, &f, &()).collect::>(), vec![(12, 12.0), (13, 13.0), (14, 14.0), (15, 15.0)], ); // Check when the query range is outside the entry range. assert_eq!(m.range(0..5, &f, &()).collect::>(), vec![]); assert_eq!(m.range(30..40, &f, &()).collect::>(), vec![]); // Check when the query range's start and end land in between entries. for i in 30..40 { if i % 2 == 0 { m.insert(i, i as f32, &mut f, &()); } } assert_eq!( m.range(31..35, &f, &()).collect::>(), vec![(32, 32.0), (34, 34.0)], ); assert_eq!( m.range(29..33, &f, &()).collect::>(), vec![(30, 30.0), (32, 32.0)], ); assert_eq!( m.range(35..40, &f, &()).collect::>(), vec![(36, 36.0), (38, 38.0)], ); } #[test] fn range_next_back() { let mut f = MapForest::::new(); let mut m = Map::::new(); for i in 10..20 { m.insert(i, i as f32, &mut f, &()); } assert_eq!( m.range(12..16, &f, &()).rev().collect::>(), vec![(15, 15.0), (14, 14.0), (13, 13.0), (12, 12.0)], ); assert_eq!( m.range(18.., &f, &()).rev().collect::>(), vec![(19, 19.0), (18, 18.0)], ); assert_eq!( m.range(..12, &f, &()).rev().collect::>(), vec![(11, 11.0), (10, 10.0)], ); assert_eq!( m.range(11..=12, &f, &()).rev().collect::>(), vec![(12, 12.0), (11, 11.0)], ); let mut iter = m.range(13..=16, &f, &()); assert_eq!(iter.next(), Some((13, 13.0))); assert_eq!(iter.next_back(), Some((16, 16.0))); assert_eq!(iter.next(), Some((14, 14.0))); assert_eq!(iter.next_back(), Some((15, 15.0))); assert!(iter.next().is_none()); assert!(iter.next_back().is_none()); let mut iter = m.range(13..=16, &f, &()); assert_eq!(iter.next_back(), Some((16, 16.0))); assert_eq!(iter.next(), Some((13, 13.0))); assert_eq!(iter.next_back(), Some((15, 15.0))); assert_eq!(iter.next(), Some((14, 14.0))); assert!(iter.next_back().is_none()); assert!(iter.next().is_none()); } }