//! Stack used for mutable tree operations that records a path through the tree. use core::marker::PhantomData; use core::ops::{Index, IndexMut}; use crate::node::{MAX_POOL_SIZE, NodePos, node_layout}; use crate::{NodeRef, RangeTreeInteger}; /// Returns the worst case maximum height for a tree with pivot `I`. #[inline] pub(crate) const fn max_height() -> usize { // Get the maximum possible number of leaf nodes, assuming an empty `V`. // // `NodePool` stores offsets in a u32 and therefore the total pool size // cannot exceed `u32::MAX`. let mut nodes = MAX_POOL_SIZE / node_layout::().0.size(); let mut height = 0; // If there are multiple nodes at this height then we need another level // above it. while nodes > 1 { height += 1; // If there are less than B nodes then we just need a single root node // above it which will never get split. if nodes < I::B { break; } // Otherwise assume a worst case with all internal nodes being half-full. nodes = nodes.div_ceil(I::B / 2); } height } /// A height in the tree. /// /// This has the invariant of always being less than `max_height::()`, which /// allows safe unchecked indexing in a stack. #[derive(Clone, Copy, Debug, Default)] pub(crate) struct Height { height: usize, marker: PhantomData I>, } impl PartialEq for Height { fn eq(&self, other: &Self) -> bool { self.height == other.height } } impl Eq for Height {} impl Height { /// Returns the height for leaf nodes. pub(crate) const LEAF: Self = Self { height: 0, marker: PhantomData, }; /// Returns the maximum possible height for a tree. pub(crate) const MAX: Self = Self { height: max_height::(), marker: PhantomData, }; /// Returns one level down (towards the leaves). #[inline] pub(crate) const fn down(self) -> Option { if self.height == 0 { None } else { Some(Self { height: self.height - 1, marker: PhantomData, }) } } /// Returns one level up (towards the root) up to the given maximum height. #[inline] pub(crate) const fn up(self, max: Height) -> Option { if self.height >= max.height { None } else { Some(Self { height: self.height + 1, marker: PhantomData, }) } } } /// Stack which holds the path to a leaf node from the root of the tree. /// /// The is large enough to hold `max_height::()`, which depends on the branching /// factor and the node size. /// /// The stack is indexed with `Height` which allows unchecked indexing since /// all heights must be less than `max_height::()`. #[derive(Clone)] pub(crate) struct Stack { entries: [(NodeRef, NodePos); H], } impl Default for Stack { #[inline] fn default() -> Self { Self { // The values here don't matter and zero initialization is slightly // faster. entries: [(NodeRef::ZERO, NodePos::ZERO); H], } } } impl Index> for Stack { type Output = (NodeRef, NodePos); #[inline] fn index(&self, index: Height) -> &Self::Output { const { assert!(H == max_height::()) }; // Safety: `Height` is always `< max_height::()` unsafe { self.entries.get_unchecked(index.height) } } } impl IndexMut> for Stack { #[inline] fn index_mut(&mut self, index: Height) -> &mut Self::Output { const { assert!(H == max_height::()) }; // Safety: `Height` is always `< max_height::()` unsafe { self.entries.get_unchecked_mut(index.height) } } }