use core::{
fmt,
iter::FusedIterator,
ops::{Bound, RangeBounds, RangeInclusive},
};
use crate::{raw::minimum_unchecked, rust_nightly_apis::likely, AsBytes};
mod header;
pub use header::*;
mod inner_node_direct;
pub use inner_node_direct::*;
mod inner_node_indirect;
pub use inner_node_indirect::*;
mod inner_node_sorted;
pub use inner_node_sorted::*;
mod leaf_node;
pub use leaf_node::*;
mod pointers;
pub use pointers::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(u8)]
pub enum NodeType {
Node4 = 0b000,
Node16 = 0b001, Node48 = 0b010, Node256 = 0b011, Leaf = 0b100, }
impl NodeType {
const unsafe fn from_u8(src: u8) -> NodeType {
unsafe { core::mem::transmute::<u8, NodeType>(src) }
}
pub fn should_shrink_inner_node(self, num_children: usize) -> bool {
match self {
NodeType::Node4 => false,
NodeType::Leaf => panic!("cannot shrink leaf"),
_ => num_children < *self.capacity_range().start(),
}
}
pub const fn capacity_range(self) -> RangeInclusive<usize> {
match self {
NodeType::Node4 => 2..=4,
NodeType::Node16 => 5..=16,
NodeType::Node48 => 17..=48,
NodeType::Node256 => 49..=256,
NodeType::Leaf => 0..=0,
}
}
}
pub(crate) mod private {
pub trait Sealed {}
impl<K, V, const PREFIX_LEN: usize, const SIZE: usize> Sealed
for super::InnerNodeSorted<K, V, PREFIX_LEN, SIZE>
{
}
impl<K, V, const PREFIX_LEN: usize, const SIZE: usize> Sealed
for super::InnerNodeIndirect<K, V, PREFIX_LEN, SIZE>
{
}
impl<K, V, const PREFIX_LEN: usize> Sealed for super::InnerNodeDirect<K, V, PREFIX_LEN> {}
impl<K, V, const PREFIX_LEN: usize> Sealed for super::LeafNode<K, V, PREFIX_LEN> {}
}
pub trait Node<const PREFIX_LEN: usize>: private::Sealed {
const TYPE: NodeType;
type Key;
type Value;
}
#[derive(Debug)]
pub struct PrefixMatch {
pub matched_bytes: usize,
}
#[derive(Debug)]
pub struct AttemptOptimisticPrefixMatch {
pub matched_bytes: usize,
pub any_implicit_bytes: bool,
}
pub struct ExplicitMismatch<K, V, const PREFIX_LEN: usize> {
pub matched_bytes: usize,
pub prefix_byte: u8,
pub leaf_ptr: OptionalLeafPtr<K, V, PREFIX_LEN>,
}
impl<K, V, const PREFIX_LEN: usize> Clone for ExplicitMismatch<K, V, PREFIX_LEN> {
fn clone(&self) -> Self {
*self
}
}
impl<K, V, const PREFIX_LEN: usize> Copy for ExplicitMismatch<K, V, PREFIX_LEN> {}
impl<K, V, const PREFIX_LEN: usize> fmt::Debug for ExplicitMismatch<K, V, PREFIX_LEN> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Mismatch")
.field("matched_bytes", &self.matched_bytes)
.field("prefix_byte", &self.prefix_byte)
.field("leaf_ptr", &self.leaf_ptr)
.finish()
}
}
#[derive(Debug)]
pub struct PessimisticMismatch {
pub matched_bytes: usize,
pub prefix_byte: Option<u8>,
}
impl From<OptimisticMismatch> for PessimisticMismatch {
fn from(value: OptimisticMismatch) -> Self {
Self {
matched_bytes: value.matched_bytes,
prefix_byte: None,
}
}
}
#[derive(Debug)]
pub struct OptimisticMismatch {
pub matched_bytes: usize,
}
pub unsafe trait InnerNodeCommon<K, V, const PREFIX_LEN: usize>: Sized {
type Iter<'a>: Iterator<Item = (u8, OpaqueNodePtr<K, V, PREFIX_LEN>)>
+ DoubleEndedIterator
+ FusedIterator
where
Self: 'a;
#[inline]
fn empty() -> Self {
Self::from_header(Header::empty())
}
fn from_prefix(prefix: &[u8], prefix_len: usize) -> Self {
Self::from_header(Header::new(prefix, prefix_len))
}
fn from_header(header: Header<PREFIX_LEN>) -> Self;
fn header(&self) -> &Header<PREFIX_LEN>;
fn lookup_child(&self, key_fragment: u8) -> Option<OpaqueNodePtr<K, V, PREFIX_LEN>>;
fn write_child(&mut self, key_fragment: u8, child_pointer: OpaqueNodePtr<K, V, PREFIX_LEN>);
fn remove_child(&mut self, key_fragment: u8) -> Option<OpaqueNodePtr<K, V, PREFIX_LEN>>;
fn iter(&self) -> Self::Iter<'_>;
fn range(
&self,
bound: impl RangeBounds<u8>,
) -> impl DoubleEndedIterator<Item = (u8, OpaqueNodePtr<K, V, PREFIX_LEN>)> + FusedIterator;
#[inline]
fn optimistic_match_prefix(
&self,
truncated_key: &[u8],
) -> Result<PrefixMatch, OptimisticMismatch> {
if truncated_key.len() < self.header().prefix_len() {
Err(OptimisticMismatch {
matched_bytes: truncated_key.len(),
})
} else {
Ok(PrefixMatch {
matched_bytes: self.header().prefix_len(),
})
}
}
#[inline]
fn attempt_pessimistic_match_prefix(
&self,
truncated_key: &[u8],
) -> Result<AttemptOptimisticPrefixMatch, PessimisticMismatch> {
if PREFIX_LEN < self.header().prefix_len() {
let PrefixMatch { matched_bytes } = self.optimistic_match_prefix(truncated_key)?;
Ok(AttemptOptimisticPrefixMatch {
matched_bytes,
any_implicit_bytes: true,
})
} else {
let prefix = self.header().read_prefix();
let matched_bytes = prefix
.iter()
.zip(truncated_key)
.take_while(|(a, b)| **a == **b)
.count();
if matched_bytes < self.header().prefix_len() {
Err(PessimisticMismatch {
matched_bytes,
prefix_byte: Some(prefix[matched_bytes]),
})
} else {
Ok(AttemptOptimisticPrefixMatch {
matched_bytes,
any_implicit_bytes: false,
})
}
}
}
#[inline]
unsafe fn match_full_prefix(
&self,
key: &[u8],
current_depth: usize,
) -> Result<PrefixMatch, ExplicitMismatch<K, V, PREFIX_LEN>>
where
K: AsBytes,
{
unsafe {
core::hint::assert_unchecked(current_depth <= key.len());
}
let (prefix, leaf_ptr) = self.read_full_prefix(current_depth);
let key = &key[current_depth..];
let matched_bytes = prefix
.iter()
.zip(key)
.take_while(|(a, b)| **a == **b)
.count();
if matched_bytes < prefix.len() {
Err(ExplicitMismatch {
matched_bytes,
prefix_byte: prefix[matched_bytes],
leaf_ptr,
})
} else {
Ok(PrefixMatch { matched_bytes })
}
}
#[inline]
fn read_full_prefix<'b>(&'b self, current_depth: usize) -> NodePrefix<'b, K, V, PREFIX_LEN>
where
K: AsBytes + 'b,
V: 'b,
{
let header = &self.header();
let len = header.prefix_len();
if likely!(len <= PREFIX_LEN) {
(header.read_prefix(), None)
} else {
let (_, min_child) = self.min();
let leaf_ptr = unsafe { minimum_unchecked(min_child) };
let leaf = unsafe { leaf_ptr.as_ref() };
let leaf = leaf.key_ref().as_bytes();
unsafe {
core::hint::assert_unchecked(current_depth <= leaf.len());
core::hint::assert_unchecked(current_depth + len <= leaf.len());
core::hint::assert_unchecked(current_depth <= current_depth + len);
}
let leaf = &leaf[current_depth..(current_depth + len)];
(leaf, Some(leaf_ptr))
}
}
fn min(&self) -> (u8, OpaqueNodePtr<K, V, PREFIX_LEN>);
fn max(&self) -> (u8, OpaqueNodePtr<K, V, PREFIX_LEN>);
}
pub trait InnerNode<const PREFIX_LEN: usize>:
Node<PREFIX_LEN> + Sized + fmt::Debug + InnerNodeCommon<Self::Key, Self::Value, PREFIX_LEN>
{
type GrownNode: InnerNode<PREFIX_LEN, Key = Self::Key, Value = Self::Value>;
type ShrunkNode: InnerNode<PREFIX_LEN, Key = Self::Key, Value = Self::Value>;
fn grow(&self) -> Self::GrownNode;
fn shrink(&self) -> Self::ShrunkNode;
fn is_full(&self) -> bool {
self.header().num_children() >= *Self::TYPE.capacity_range().end()
}
}
pub type NodePrefix<'a, K, V, const PREFIX_LEN: usize> = (
&'a [u8],
Option<NodePtr<PREFIX_LEN, LeafNode<K, V, PREFIX_LEN>>>,
);
pub enum TreePath<K, V, const PREFIX_LEN: usize> {
Root,
ChildOfRoot {
parent: OpaqueNodePtr<K, V, PREFIX_LEN>,
child_key_byte: u8,
},
Normal {
grandparent: OpaqueNodePtr<K, V, PREFIX_LEN>,
parent_key_byte: u8,
parent: OpaqueNodePtr<K, V, PREFIX_LEN>,
child_key_byte: u8,
},
}
impl<K, V, const PREFIX_LEN: usize> Copy for TreePath<K, V, PREFIX_LEN> {}
impl<K, V, const PREFIX_LEN: usize> Clone for TreePath<K, V, PREFIX_LEN> {
fn clone(&self) -> Self {
*self
}
}
impl<K, V, const PREFIX_LEN: usize> fmt::Debug for TreePath<K, V, PREFIX_LEN> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Root => write!(f, "Root"),
Self::ChildOfRoot {
parent,
child_key_byte,
} => f
.debug_struct("ChildOfRoot")
.field("parent", parent)
.field("child_key_byte", child_key_byte)
.finish(),
Self::Normal {
grandparent,
parent_key_byte,
parent,
child_key_byte,
} => f
.debug_struct("Normal")
.field("grandparent", grandparent)
.field("parent_key_byte", parent_key_byte)
.field("parent", parent)
.field("child_key_byte", child_key_byte)
.finish(),
}
}
}
#[derive(Debug)]
pub struct TreePathSearch<K, V, const PREFIX_LEN: usize> {
current_grandparent: Option<(OpaqueNodePtr<K, V, PREFIX_LEN>, u8)>,
current_parent: Option<(OpaqueNodePtr<K, V, PREFIX_LEN>, u8)>,
}
impl<K, V, const PREFIX_LEN: usize> Default for TreePathSearch<K, V, PREFIX_LEN> {
fn default() -> Self {
Self {
current_grandparent: None,
current_parent: None,
}
}
}
impl<K, V, const PREFIX_LEN: usize> TreePathSearch<K, V, PREFIX_LEN> {
pub fn visit_inner_node(&mut self, inner_node: OpaqueNodePtr<K, V, PREFIX_LEN>, key_byte: u8) {
self.current_grandparent = self.current_parent;
self.current_parent = Some((inner_node, key_byte));
}
pub fn finish(self) -> TreePath<K, V, PREFIX_LEN> {
match (self.current_grandparent, self.current_parent) {
(None, None) => TreePath::Root,
(None, Some((parent, child_key_byte))) => TreePath::ChildOfRoot {
parent,
child_key_byte,
},
(Some((grandparent, parent_key_byte)), Some((parent, child_key_byte))) => {
TreePath::Normal {
grandparent,
parent_key_byte,
parent,
child_key_byte,
}
},
(Some(_), None) => {
unreachable!("Impossible for grandparent to present while parent is not")
},
}
}
}
fn assert_valid_range_bounds(bound: &impl RangeBounds<u8>) {
{
match (bound.start_bound(), bound.end_bound()) {
(Bound::Excluded(s), Bound::Excluded(e)) if s == e => {
panic!("range start and end are equal and excluded: ({s:?})")
},
(Bound::Included(s) | Bound::Excluded(s), Bound::Included(e) | Bound::Excluded(e))
if s > e =>
{
panic!("range start ({s:?}) is greater than range end ({e:?})")
},
_ => {},
}
}
}
#[cfg(test)]
mod tests {
use alloc::{boxed::Box, vec::Vec};
use core::mem;
use super::*;
use crate::rust_nightly_apis::ptr::const_addr;
#[test]
#[cfg(target_pointer_width = "64")]
fn node_sizes() {
const DEFAULT_PREFIX_LEN: usize = 16;
assert_eq!(mem::size_of::<Header<DEFAULT_PREFIX_LEN>>(), 24);
const EXPECTED_HEADER_SIZE: usize = DEFAULT_PREFIX_LEN.next_multiple_of(4) + 8;
assert_eq!(EXPECTED_HEADER_SIZE, 24);
assert_eq!(
mem::size_of::<InnerNode4<Box<[u8]>, usize, DEFAULT_PREFIX_LEN>>(),
EXPECTED_HEADER_SIZE + 40
);
assert_eq!(
mem::size_of::<InnerNode16<Box<[u8]>, usize, DEFAULT_PREFIX_LEN>>(),
EXPECTED_HEADER_SIZE + 144
);
assert_eq!(
mem::size_of::<InnerNode48<Box<[u8]>, usize, DEFAULT_PREFIX_LEN>>(),
EXPECTED_HEADER_SIZE + 640
);
assert_eq!(
mem::size_of::<InnerNodeDirect<Box<[u8]>, usize, DEFAULT_PREFIX_LEN>>(),
EXPECTED_HEADER_SIZE + 2048
);
assert_eq!(
mem::size_of::<Option<OpaqueNodePtr<Box<[u8]>, (), DEFAULT_PREFIX_LEN>>>(),
8
);
assert_eq!(
mem::size_of::<OpaqueNodePtr<Box<[u8]>, (), DEFAULT_PREFIX_LEN>>(),
8
);
}
#[test]
fn node_alignment() {
assert_eq!(mem::align_of::<InnerNode4<Box<[u8]>, u8, 16>>(), 8);
assert_eq!(mem::align_of::<InnerNode16<Box<[u8]>, u8, 16>>(), 8);
assert_eq!(mem::align_of::<InnerNode48<Box<[u8]>, u8, 16>>(), 8);
assert_eq!(mem::align_of::<InnerNodeDirect<Box<[u8]>, u8, 16>>(), 8);
assert_eq!(mem::align_of::<LeafNode<Box<[u8]>, u8, 16>>(), 8);
assert_eq!(mem::align_of::<Header<16>>(), 4);
assert_eq!(
mem::align_of::<InnerNode4<Box<[u8]>, u8, 16>>(),
mem::align_of::<OpaqueValue>()
);
assert_eq!(
mem::align_of::<InnerNode16<Box<[u8]>, u8, 16>>(),
mem::align_of::<OpaqueValue>()
);
assert_eq!(
mem::align_of::<InnerNode48<Box<[u8]>, u8, 16>>(),
mem::align_of::<OpaqueValue>()
);
assert_eq!(
mem::align_of::<InnerNodeDirect<Box<[u8]>, u8, 16>>(),
mem::align_of::<OpaqueValue>()
);
assert_eq!(
mem::align_of::<LeafNode<Box<[u8]>, u8, 16>>(),
mem::align_of::<OpaqueValue>()
);
let n4 = InnerNode4::<Box<[u8]>, (), 16>::empty();
let n16 = InnerNode4::<Box<[u8]>, (), 16>::empty();
let n48 = InnerNode4::<Box<[u8]>, (), 16>::empty();
let n256 = InnerNode4::<Box<[u8]>, (), 16>::empty();
let n4_ptr = const_addr(&n4 as *const InnerNode4<Box<[u8]>, (), 16>);
let n16_ptr = const_addr(&n16 as *const InnerNode4<Box<[u8]>, (), 16>);
let n48_ptr = const_addr(&n48 as *const InnerNode4<Box<[u8]>, (), 16>);
let n256_ptr = const_addr(&n256 as *const InnerNode4<Box<[u8]>, (), 16>);
assert!(n4_ptr.trailing_zeros() >= 3);
assert!(n16_ptr.trailing_zeros() >= 3);
assert!(n48_ptr.trailing_zeros() >= 3);
assert!(n256_ptr.trailing_zeros() >= 3);
}
pub(crate) fn inner_node_write_child_test<const PREFIX_LEN: usize>(
mut node: impl InnerNode<PREFIX_LEN, Key = Box<[u8]>, Value = ()>,
num_children: usize,
) {
let mut leaves = Vec::with_capacity(num_children);
for _ in 0..num_children {
leaves.push(LeafNode::with_no_siblings(vec![].into(), ()));
}
assert!(!node.is_full());
{
let leaf_pointers = leaves
.iter_mut()
.map(|leaf| NodePtr::from(leaf).to_opaque())
.collect::<Vec<_>>();
for (idx, leaf_pointer) in leaf_pointers.iter().copied().enumerate() {
node.write_child(u8::try_from(idx).unwrap(), leaf_pointer);
}
for (idx, leaf_pointer) in leaf_pointers.into_iter().enumerate() {
assert_eq!(
node.lookup_child(u8::try_from(idx).unwrap()),
Some(leaf_pointer)
);
}
}
assert!(node.is_full());
}
pub fn inner_node_remove_child_test<const PREFIX_LEN: usize>(
mut node: impl InnerNode<PREFIX_LEN, Key = Box<[u8]>, Value = ()>,
num_children: usize,
) {
let mut leaves = Vec::with_capacity(num_children);
for _ in 0..num_children {
leaves.push(LeafNode::with_no_siblings(vec![].into(), ()));
}
assert!(!node.is_full());
{
let leaf_pointers = leaves
.iter_mut()
.map(|leaf| NodePtr::from(leaf).to_opaque())
.collect::<Vec<_>>();
for (idx, leaf_pointer) in leaf_pointers.iter().copied().enumerate() {
node.write_child(u8::try_from(idx).unwrap(), leaf_pointer);
}
for (idx, leaf_pointer) in leaf_pointers.iter().copied().enumerate() {
assert_eq!(
node.lookup_child(u8::try_from(idx).unwrap()),
Some(leaf_pointer)
);
}
for (idx, leaf_pointer) in leaf_pointers.iter().copied().enumerate() {
assert_eq!(
node.remove_child(u8::try_from(idx).unwrap()),
Some(leaf_pointer)
);
assert_eq!(node.lookup_child(u8::try_from(idx).unwrap()), None);
}
}
assert!(!node.is_full());
}
pub(crate) fn inner_node_shrink_test<const PREFIX_LEN: usize>(
mut node: impl InnerNode<PREFIX_LEN, Key = Box<[u8]>, Value = ()>,
num_children: usize,
) {
let mut leaves = Vec::with_capacity(num_children);
for _ in 0..num_children {
leaves.push(LeafNode::with_no_siblings(vec![].into(), ()));
}
let leaf_pointers = leaves
.iter_mut()
.map(|leaf| NodePtr::from(leaf).to_opaque())
.collect::<Vec<_>>();
for (idx, leaf_pointer) in leaf_pointers.iter().copied().enumerate() {
node.write_child(u8::try_from(idx).unwrap(), leaf_pointer);
}
let shrunk_node = node.shrink();
for (idx, leaf_pointer) in leaf_pointers.into_iter().enumerate() {
assert_eq!(
shrunk_node.lookup_child(u8::try_from(idx).unwrap()),
Some(leaf_pointer)
);
}
}
pub(crate) fn inner_node_min_max_test<const PREFIX_LEN: usize>(
mut node: impl InnerNode<PREFIX_LEN, Key = Box<[u8]>, Value = ()>,
num_children: usize,
) {
assert!(
num_children >= 2,
"test harness must specify more than 1 child"
);
let mut leaves = Vec::with_capacity(num_children);
for _ in 0..num_children {
leaves.push(LeafNode::with_no_siblings(vec![].into(), ()));
}
let leaf_pointers = leaves
.iter_mut()
.map(|leaf| NodePtr::from(leaf).to_opaque())
.collect::<Vec<_>>();
for (idx, leaf_pointer) in leaf_pointers.iter().copied().enumerate() {
node.write_child(u8::try_from(idx).unwrap(), leaf_pointer);
}
assert_eq!(node.header().num_children(), num_children);
let midpoint = num_children / 2;
let interleaved = (0..midpoint).zip((midpoint..num_children).rev());
for (min_idx, max_idx) in interleaved {
let (min_key_fragment, min_leaf_node) = node.min();
assert_eq!(min_leaf_node, node.remove_child(min_key_fragment).unwrap());
let expected_min_leaf_node =
NodePtr::from(leaves.get_mut(min_idx).unwrap()).to_opaque();
assert_eq!(expected_min_leaf_node, min_leaf_node);
let (max_key_fragment, max_leaf_node) = node.max();
assert_eq!(max_leaf_node, node.remove_child(max_key_fragment).unwrap());
let expected_max_leaf_node =
NodePtr::from(leaves.get_mut(max_idx).unwrap()).to_opaque();
assert_eq!(expected_max_leaf_node, max_leaf_node);
}
assert_eq!(node.header().num_children(), 0);
}
pub(crate) type FixtureReturn<Node, const N: usize> = (
Node,
[LeafNode<Box<[u8]>, (), 16>; N],
[OpaqueNodePtr<Box<[u8]>, (), 16>; N],
);
}