#![allow(clippy::type_complexity)]
#![deny(unsafe_op_in_unsafe_fn)]
#![warn(clippy::undocumented_unsafe_blocks)]
use core::ptr;
use std::borrow::Borrow;
use std::fmt;
use std::ops::Bound;
pub mod alloc;
pub mod atomic_slot;
pub mod error;
pub(crate) mod inline_vec;
pub mod iter;
pub mod latch;
pub mod optimistic;
pub(crate) mod sync;
use sync::epoch::{self as epoch, Atomic, Owned};
use sync::{AtomicUsize, Ordering};
use atomic_slot::{AtomicLen, SlotArray};
use inline_vec::InlineVec;
use latch::{ExclusiveGuard, HybridGuard, HybridLatch, OptimisticGuard, SharedGuard};
pub use optimistic::OptimisticRead;
mod prefetch {
#[inline(always)]
#[allow(unused_variables)]
pub fn read_data<T>(ptr: *const T) {
#[cfg(target_arch = "x86_64")]
unsafe {
core::arch::x86_64::_mm_prefetch::<{ core::arch::x86_64::_MM_HINT_T0 }>(
ptr as *const i8,
);
}
}
}
const INNER_CAPACITY: usize = 64;
const LEAF_CAPACITY: usize = 64;
pub type Tree<K, V> = GenericTree<K, V, INNER_CAPACITY, LEAF_CAPACITY>;
pub struct GenericTree<K: OptimisticRead, V: OptimisticRead, const IC: usize, const LC: usize> {
root: HybridLatch<Atomic<HybridLatch<Node<K, V, IC, LC>>>>,
height: AtomicUsize,
}
impl<K: Clone + Ord + OptimisticRead, V: OptimisticRead, const IC: usize, const LC: usize> Default
for GenericTree<K, V, IC, LC>
{
fn default() -> Self {
Self::new()
}
}
pub(crate) enum ParentHandler<
'r,
'p,
K: OptimisticRead,
V: OptimisticRead,
const IC: usize,
const LC: usize,
> {
Root {
tree_guard: OptimisticGuard<'r, Atomic<HybridLatch<Node<K, V, IC, LC>>>>,
},
Parent {
parent_guard: OptimisticGuard<'p, Node<K, V, IC, LC>>,
pos: u16,
},
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub(crate) enum Direction {
Forward,
Reverse,
}
impl<K: Clone + Ord + OptimisticRead, V: OptimisticRead, const IC: usize, const LC: usize>
GenericTree<K, V, IC, LC>
{
pub fn new() -> Self {
GenericTree {
root: HybridLatch::new(Atomic::new(HybridLatch::new(Node::Leaf(LeafNode {
len: AtomicLen::new(0),
keys: SlotArray::new(),
values: SlotArray::new(),
lower_fence: None,
upper_fence: None,
sample_key: None,
})))),
height: AtomicUsize::new(1),
}
}
pub fn height(&self) -> usize {
self.height.load(Ordering::Relaxed)
}
pub(crate) fn find_parent<'t>(
&'t self,
needle: &impl HybridGuard<Node<K, V, IC, LC>>,
eg: &'t epoch::Guard,
) -> error::Result<ParentHandler<'t, 't, K, V, IC, LC>>
where
K: Ord,
{
let tree_guard = self.root.optimistic_or_spin();
let root_latch = unsafe { tree_guard.load(Ordering::Acquire, eg).deref() };
let root_latch_ptr = root_latch as *const _;
let root_guard = root_latch.optimistic_or_spin();
if std::ptr::eq(needle.latch(), root_latch_ptr) {
tree_guard.recheck()?;
return Ok(ParentHandler::Root {
tree_guard,
});
}
let search_key = match needle.inner().sample_key().cloned() {
Some(key) => key,
None => {
needle.recheck()?;
return Err(error::Error::Reclaimed);
}
};
let mut t_guard = Some(tree_guard);
let mut p_guard: Option<OptimisticGuard<'_, Node<K, V, IC, LC>>> = None;
let mut target_guard = root_guard;
let mut pos = 0u16;
let parent_guard = loop {
let (c_swip, c_pos) = match *target_guard {
Node::Internal(ref internal) => {
let (c_pos, _) = internal.lower_bound(&search_key);
let swip = internal.edge_at(c_pos)?;
(swip, c_pos)
}
Node::Leaf(ref _leaf) => {
break p_guard.expect("must have parent");
}
};
let c_latch = unsafe { c_swip.load(Ordering::Acquire, eg).deref() };
let c_latch_ptr = c_latch as *const _;
if std::ptr::eq(needle.latch(), c_latch_ptr) {
target_guard.recheck()?;
if let Some(tree_guard) = t_guard.take() {
tree_guard.recheck()?;
}
pos = c_pos; break target_guard;
}
let guard = Self::lock_coupling(&target_guard, c_swip, eg)?;
p_guard = Some(target_guard);
pos = c_pos;
target_guard = guard;
if let Some(tree_guard) = t_guard.take() {
tree_guard.recheck()?;
}
};
Ok(ParentHandler::Parent {
parent_guard,
pos,
})
}
pub(crate) fn find_nearest_leaf<'t, 'g>(
&'t self,
needle: &OptimisticGuard<'g, Node<K, V, IC, LC>>,
direction: Direction,
eg: &'t epoch::Guard,
) -> error::Result<
Option<(
OptimisticGuard<'t, Node<K, V, IC, LC>>,
(OptimisticGuard<'t, Node<K, V, IC, LC>>, u16),
)>,
>
where
K: Ord,
{
let tree_guard = self.root.optimistic_or_spin();
let root_latch = unsafe { tree_guard.load(Ordering::Acquire, eg).deref() };
let root_latch_ptr = root_latch as *const _;
let root_guard = root_latch.optimistic_or_spin();
if std::ptr::eq(needle.latch(), root_latch_ptr) {
root_guard.recheck()?;
tree_guard.recheck()?;
return error::Result::Ok(None);
}
let (parent_guard, pos) = match self.find_parent(needle, eg)? {
ParentHandler::Root {
tree_guard: _,
} => {
return error::Result::Ok(None);
}
ParentHandler::Parent {
parent_guard,
pos,
} => (parent_guard, pos),
};
let within_bounds = match direction {
Direction::Forward => pos < parent_guard.as_internal().len.load(),
Direction::Reverse => pos > 0,
};
if within_bounds {
let lookup_pos = match direction {
Direction::Forward => pos + 1,
Direction::Reverse => pos - 1,
};
let swip = parent_guard.as_internal().edge_at(lookup_pos)?;
let guard = GenericTree::lock_coupling(&parent_guard, swip, eg)?;
if guard.is_leaf() {
guard.recheck()?;
error::Result::Ok(Some((guard, (parent_guard, lookup_pos))))
} else {
let (leaf, parent_opt) =
self.find_leaf_and_parent_from_node(guard, direction, eg)?;
error::Result::Ok(Some((leaf, parent_opt.expect("must have parent here"))))
}
} else {
let mut target_guard = parent_guard;
loop {
let (parent_guard, pos) = match self.find_parent(&target_guard, eg)? {
ParentHandler::Root {
tree_guard: _,
} => {
return error::Result::Ok(None);
}
ParentHandler::Parent {
parent_guard,
pos,
} => (parent_guard, pos),
};
let within_bounds = match direction {
Direction::Forward => pos < parent_guard.as_internal().len.load(),
Direction::Reverse => pos > 0,
};
if within_bounds {
let lookup_pos = match direction {
Direction::Forward => pos + 1,
Direction::Reverse => pos - 1,
};
let swip = parent_guard.as_internal().edge_at(lookup_pos)?;
let guard = GenericTree::lock_coupling(&parent_guard, swip, eg)?;
if guard.is_leaf() {
guard.recheck()?;
return error::Result::Ok(Some((guard, (parent_guard, lookup_pos))));
} else {
let (leaf, parent_opt) =
self.find_leaf_and_parent_from_node(guard, direction, eg)?;
return error::Result::Ok(Some((
leaf,
parent_opt.expect("must have parent here"),
)));
}
} else {
target_guard = parent_guard;
continue;
}
}
}
}
pub(crate) fn lock_coupling<'e>(
p_guard: &OptimisticGuard<'e, Node<K, V, IC, LC>>,
swip: &Atomic<HybridLatch<Node<K, V, IC, LC>>>,
eg: &'e epoch::Guard,
) -> error::Result<OptimisticGuard<'e, Node<K, V, IC, LC>>> {
let c_latch = unsafe { swip.load(Ordering::Acquire, eg).deref() };
let c_guard = c_latch.optimistic_or_spin();
p_guard.recheck()?;
Ok(c_guard)
}
fn lock_coupling_shared<'e>(
p_guard: &OptimisticGuard<'e, Node<K, V, IC, LC>>,
swip: &Atomic<HybridLatch<Node<K, V, IC, LC>>>,
eg: &'e epoch::Guard,
) -> error::Result<SharedGuard<'e, Node<K, V, IC, LC>>> {
let c_latch = unsafe { swip.load(Ordering::Acquire, eg).deref() };
let c_guard = c_latch.shared();
p_guard.recheck()?;
Ok(c_guard)
}
fn lock_coupling_exclusive<'e>(
p_guard: &OptimisticGuard<'e, Node<K, V, IC, LC>>,
swip: &Atomic<HybridLatch<Node<K, V, IC, LC>>>,
eg: &'e epoch::Guard,
) -> error::Result<ExclusiveGuard<'e, Node<K, V, IC, LC>>> {
let c_latch = unsafe { swip.load(Ordering::Acquire, eg).deref() };
let c_guard = c_latch.exclusive();
p_guard.recheck()?;
Ok(c_guard)
}
fn find_leaf_and_parent_from_node<'e>(
&self,
needle: OptimisticGuard<'e, Node<K, V, IC, LC>>,
direction: Direction,
eg: &'e epoch::Guard,
) -> error::Result<(
OptimisticGuard<'e, Node<K, V, IC, LC>>,
Option<(OptimisticGuard<'e, Node<K, V, IC, LC>>, u16)>,
)> {
let mut p_guard = None;
let mut target_guard = needle;
let leaf_guard = loop {
let (c_swip, pos) = match *target_guard {
Node::Internal(ref internal) => {
let pos = match direction {
Direction::Forward => 0,
Direction::Reverse => internal.len.load(),
};
let swip = internal.edge_at(pos)?;
(swip, pos)
}
Node::Leaf(ref _leaf) => {
break target_guard;
}
};
let guard = GenericTree::lock_coupling(&target_guard, c_swip, eg)?;
p_guard = Some((target_guard, pos));
target_guard = guard;
};
leaf_guard.recheck()?;
Ok((leaf_guard, p_guard))
}
fn find_first_leaf_and_parent<'e>(
&self,
eg: &'e epoch::Guard,
) -> error::Result<(
OptimisticGuard<'e, Node<K, V, IC, LC>>,
Option<(OptimisticGuard<'e, Node<K, V, IC, LC>>, u16)>,
)> {
let tree_guard = self.root.optimistic_or_spin();
let root_latch = unsafe { tree_guard.load(Ordering::Acquire, eg).deref() };
let root_guard = root_latch.optimistic_or_spin();
tree_guard.recheck()?;
self.find_leaf_and_parent_from_node(root_guard, Direction::Forward, eg)
}
fn find_last_leaf_and_parent<'e>(
&self,
eg: &'e epoch::Guard,
) -> error::Result<(
OptimisticGuard<'e, Node<K, V, IC, LC>>,
Option<(OptimisticGuard<'e, Node<K, V, IC, LC>>, u16)>,
)> {
let tree_guard = self.root.optimistic_or_spin();
let root_latch = unsafe { tree_guard.load(Ordering::Acquire, eg).deref() };
let root_guard = root_latch.optimistic_or_spin();
tree_guard.recheck()?;
self.find_leaf_and_parent_from_node(root_guard, Direction::Reverse, eg)
}
fn find_leaf_and_parent<'e, Q>(
&self,
key: &Q,
eg: &'e epoch::Guard,
) -> error::Result<(
OptimisticGuard<'e, Node<K, V, IC, LC>>,
Option<(OptimisticGuard<'e, Node<K, V, IC, LC>>, u16)>,
)>
where
K: Borrow<Q> + Ord,
Q: ?Sized + Ord,
{
let tree_guard = self.root.optimistic_or_spin();
let root_latch = unsafe { tree_guard.load(Ordering::Acquire, eg).deref() };
let root_guard = root_latch.optimistic_or_spin();
tree_guard.recheck()?;
let mut t_guard = Some(tree_guard);
let mut p_guard = None;
let mut target_guard = root_guard;
let leaf_guard = loop {
let (c_swip, pos) = match *target_guard {
Node::Internal(ref internal) => {
let (pos, _) = internal.lower_bound(key);
let swip = internal.edge_at(pos)?;
(swip, pos)
}
Node::Leaf(ref _leaf) => {
break target_guard;
}
};
let guard = GenericTree::lock_coupling(&target_guard, c_swip, eg)?;
p_guard = Some((target_guard, pos));
target_guard = guard;
if let Some(tree_guard) = t_guard.take() {
tree_guard.recheck()?;
}
};
Ok((leaf_guard, p_guard))
}
#[allow(dead_code)]
fn find_leaf<'e, Q>(
&self,
key: &Q,
eg: &'e epoch::Guard,
) -> error::Result<OptimisticGuard<'e, Node<K, V, IC, LC>>>
where
K: Borrow<Q> + Ord,
Q: ?Sized + Ord,
{
self.find_leaf_and_parent(key, eg).map(|(leaf, _)| leaf)
}
pub(crate) fn find_shared_leaf_and_optimistic_parent<'e, Q>(
&self,
key: &Q,
eg: &'e epoch::Guard,
) -> (SharedGuard<'e, Node<K, V, IC, LC>>, Option<(OptimisticGuard<'e, Node<K, V, IC, LC>>, u16)>)
where
K: Borrow<Q> + Ord,
Q: ?Sized + Ord,
{
loop {
let perform = || {
let tree_guard = self.root.optimistic_or_spin();
let root_latch = unsafe { tree_guard.load(Ordering::Acquire, eg).deref() };
let root_guard = root_latch.optimistic_or_spin();
tree_guard.recheck()?;
let mut t_guard = Some(tree_guard);
let mut p_guard = None;
let mut target_guard = root_guard;
let mut level = 1u16;
let leaf_guard = loop {
let (c_swip, pos) = match *target_guard {
Node::Internal(ref internal) => {
let (pos, _) = internal.lower_bound(key);
let swip = internal.edge_at(pos)?;
(swip, pos)
}
Node::Leaf(ref _leaf) => {
if let Some(tree_guard) = t_guard.take() {
tree_guard.recheck()?;
}
if p_guard.is_none() {
break target_guard.to_shared()?;
} else {
unreachable!(
"tree structure corruption: encountered leaf at internal level during traversal"
)
}
}
};
if (level + 1) as usize == self.height.load(Ordering::Relaxed) {
if let Some(tree_guard) = t_guard.take() {
tree_guard.recheck()?;
}
let guard = Self::lock_coupling_shared(&target_guard, c_swip, eg)?;
p_guard = Some((target_guard, pos));
break guard;
} else {
let guard = GenericTree::lock_coupling(&target_guard, c_swip, eg)?;
p_guard = Some((target_guard, pos));
target_guard = guard;
if let Some(tree_guard) = t_guard.take() {
tree_guard.recheck()?;
}
level += 1;
}
};
error::Result::Ok((leaf_guard, p_guard))
};
match perform() {
Ok(tup) => {
return tup;
}
Err(_) => {
continue;
}
}
}
}
#[inline]
pub(crate) fn find_optimistic_leaf<'e, Q>(
&self,
key: &Q,
eg: &'e epoch::Guard,
) -> error::Result<OptimisticGuard<'e, Node<K, V, IC, LC>>>
where
K: Borrow<Q> + Ord + OptimisticRead,
Q: ?Sized + Ord,
{
let tree_guard = self.root.optimistic_or_spin();
let root_latch = unsafe { tree_guard.load(Ordering::Acquire, eg).deref() };
let root_guard = root_latch.optimistic_or_spin();
tree_guard.recheck()?;
let mut t_guard = Some(tree_guard);
let mut target_guard = root_guard;
loop {
let target_ptr = target_guard.as_ptr();
let kind = unsafe { Node::variant_raw(target_ptr) };
let c_swip_ptr = match kind {
NodeKindRaw::Internal(internal_ptr) => {
let (pos, _) = unsafe { InternalNode::lower_bound_raw(internal_ptr, key) };
unsafe { InternalNode::edge_at_raw(internal_ptr, pos)? }
}
NodeKindRaw::Leaf(_) => {
if let Some(tree_guard) = t_guard.take() {
tree_guard.recheck()?;
}
target_guard.recheck()?;
return Ok(target_guard);
}
};
let c_swip = unsafe { &*c_swip_ptr };
let prefetch_target = c_swip.load(Ordering::Relaxed, eg).as_raw();
prefetch::read_data(prefetch_target);
let guard = GenericTree::lock_coupling(&target_guard, c_swip, eg)?;
target_guard = guard;
if let Some(tree_guard) = t_guard.take() {
tree_guard.recheck()?;
}
}
}
pub(crate) fn find_first_shared_leaf_and_optimistic_parent<'e>(
&self,
eg: &'e epoch::Guard,
) -> (SharedGuard<'e, Node<K, V, IC, LC>>, Option<(OptimisticGuard<'e, Node<K, V, IC, LC>>, u16)>)
{
loop {
let perform = || {
let (leaf, parent_opt) = self.find_first_leaf_and_parent(eg)?;
let shared_leaf = leaf.to_shared()?;
error::Result::Ok((shared_leaf, parent_opt))
};
match perform() {
Ok(tup) => {
return tup;
}
Err(_) => {
continue;
}
}
}
}
pub(crate) fn find_last_shared_leaf_and_optimistic_parent<'e>(
&self,
eg: &'e epoch::Guard,
) -> (SharedGuard<'e, Node<K, V, IC, LC>>, Option<(OptimisticGuard<'e, Node<K, V, IC, LC>>, u16)>)
{
loop {
let perform = || {
let (leaf, parent_opt) = self.find_last_leaf_and_parent(eg)?;
let shared_leaf = leaf.to_shared()?;
error::Result::Ok((shared_leaf, parent_opt))
};
match perform() {
Ok(tup) => {
return tup;
}
Err(_) => {
continue;
}
}
}
}
pub(crate) fn find_exclusive_leaf_and_optimistic_parent<'e, Q>(
&self,
key: &Q,
eg: &'e epoch::Guard,
) -> (
ExclusiveGuard<'e, Node<K, V, IC, LC>>,
Option<(OptimisticGuard<'e, Node<K, V, IC, LC>>, u16)>,
)
where
K: Borrow<Q> + Ord,
Q: ?Sized + Ord,
{
loop {
let perform = || {
let tree_guard = self.root.optimistic_or_spin();
let root_latch = unsafe { tree_guard.load(Ordering::Acquire, eg).deref() };
let root_guard = root_latch.optimistic_or_spin();
tree_guard.recheck()?;
let mut t_guard = Some(tree_guard);
let mut p_guard = None;
let mut target_guard = root_guard;
let mut level = 1u16;
let leaf_guard = loop {
let (c_swip, pos) = match *target_guard {
Node::Internal(ref internal) => {
let (pos, _) = internal.lower_bound(key);
let swip = internal.edge_at(pos)?;
(swip, pos)
}
Node::Leaf(ref _leaf) => {
if let Some(tree_guard) = t_guard.take() {
tree_guard.recheck()?;
}
if p_guard.is_none() {
break target_guard.to_exclusive()?;
} else {
unreachable!(
"tree structure corruption: encountered leaf at internal level during traversal"
)
}
}
};
if (level + 1) as usize == self.height.load(Ordering::Relaxed) {
if let Some(tree_guard) = t_guard.take() {
tree_guard.recheck()?;
}
let guard = Self::lock_coupling_exclusive(&target_guard, c_swip, eg)?;
p_guard = Some((target_guard, pos));
break guard;
} else {
let guard = GenericTree::lock_coupling(&target_guard, c_swip, eg)?;
p_guard = Some((target_guard, pos));
target_guard = guard;
if let Some(tree_guard) = t_guard.take() {
tree_guard.recheck()?;
}
level += 1;
}
};
error::Result::Ok((leaf_guard, p_guard))
};
match perform() {
Ok(tup) => {
return tup;
}
Err(_) => {
continue;
}
}
}
}
#[allow(dead_code)]
pub(crate) fn find_exact_exclusive_leaf_and_optimistic_parent<'e, Q>(
&self,
key: &Q,
eg: &'e epoch::Guard,
) -> Option<(
(ExclusiveGuard<'e, Node<K, V, IC, LC>>, u16),
Option<(OptimisticGuard<'e, Node<K, V, IC, LC>>, u16)>,
)>
where
K: Borrow<Q> + Ord,
Q: ?Sized + Ord,
{
loop {
let perform = || {
let (leaf, parent_opt) = self.find_leaf_and_parent(key, eg)?;
let (pos, exact) = leaf.as_leaf().lower_bound(key);
if exact {
let exclusive_leaf = leaf.to_exclusive()?;
error::Result::Ok(Some(((exclusive_leaf, pos), parent_opt)))
} else {
leaf.recheck()?;
error::Result::Ok(None)
}
};
match perform() {
Ok(opt) => {
return opt;
}
Err(_) => {
continue;
}
}
}
}
pub(crate) fn find_first_exclusive_leaf_and_optimistic_parent<'e>(
&self,
eg: &'e epoch::Guard,
) -> (
ExclusiveGuard<'e, Node<K, V, IC, LC>>,
Option<(OptimisticGuard<'e, Node<K, V, IC, LC>>, u16)>,
) {
loop {
let perform = || {
let (leaf, parent_opt) = self.find_first_leaf_and_parent(eg)?;
let exclusive_leaf = leaf.to_exclusive()?;
error::Result::Ok((exclusive_leaf, parent_opt))
};
match perform() {
Ok(tup) => {
return tup;
}
Err(_) => {
continue;
}
}
}
}
pub(crate) fn find_last_exclusive_leaf_and_optimistic_parent<'e>(
&self,
eg: &'e epoch::Guard,
) -> (
ExclusiveGuard<'e, Node<K, V, IC, LC>>,
Option<(OptimisticGuard<'e, Node<K, V, IC, LC>>, u16)>,
) {
loop {
let perform = || {
let (leaf, parent_opt) = self.find_last_leaf_and_parent(eg)?;
let exclusive_leaf = leaf.to_exclusive()?;
error::Result::Ok((exclusive_leaf, parent_opt))
};
match perform() {
Ok(tup) => {
return tup;
}
Err(_) => {
continue;
}
}
}
}
pub fn lookup<Q, R, F>(&self, key: &Q, f: F) -> Option<R>
where
K: Borrow<Q> + Ord,
Q: ?Sized + Ord,
F: Fn(&V) -> R,
{
let eg = &epoch::pin();
let (guard, _parent) = self.find_shared_leaf_and_optimistic_parent(key, eg);
if let Node::Leaf(ref leaf) = *guard {
let (pos, exact) = leaf.lower_bound(key);
if exact {
leaf.value_at(pos).ok().map(|v| f(&v))
} else {
None
}
} else {
unreachable!(
"find_shared_leaf_and_optimistic_parent returned non-leaf node - tree traversal invariant violated"
)
}
}
pub fn contains_key<Q>(&self, key: &Q) -> bool
where
K: Borrow<Q> + Ord,
Q: ?Sized + Ord,
{
self.lookup(key, |_| ()).is_some()
}
pub fn contains_key_optimistic<Q>(&self, key: &Q) -> bool
where
K: Borrow<Q> + Ord + OptimisticRead,
Q: ?Sized + Ord,
{
let eg = &epoch::pin();
loop {
let perform = || -> error::Result<bool> {
let leaf_guard = self.find_optimistic_leaf(key, eg)?;
let node_ptr = leaf_guard.as_ptr();
let leaf_ptr = match unsafe { Node::variant_raw(node_ptr) } {
NodeKindRaw::Leaf(l) => l,
NodeKindRaw::Internal(_) => {
std::hint::cold_path();
return Err(error::Error::Unwind);
}
};
let (_, exact) = unsafe { LeafNode::lower_bound_raw(leaf_ptr, key) };
leaf_guard.recheck()?;
Ok(exact)
};
match perform() {
Ok(result) => return result,
Err(_) => {
std::hint::cold_path();
continue;
}
}
}
}
pub fn lookup_optimistic<Q, R, F>(&self, key: &Q, f: F) -> Option<R>
where
K: Borrow<Q> + Ord + OptimisticRead,
Q: ?Sized + Ord,
V: OptimisticRead,
F: Fn(&V) -> R,
{
let eg = &epoch::pin();
loop {
let perform = || -> error::Result<Option<R>> {
let leaf_guard = self.find_optimistic_leaf(key, eg)?;
let node_ptr = leaf_guard.as_ptr();
let leaf_ptr = match unsafe { Node::variant_raw(node_ptr) } {
NodeKindRaw::Leaf(l) => l,
NodeKindRaw::Internal(_) => {
std::hint::cold_path();
return Err(error::Error::Unwind);
}
};
let (pos, exact) = unsafe { LeafNode::lower_bound_raw(leaf_ptr, key) };
if !exact {
leaf_guard.recheck()?;
return Ok(None);
}
if (pos as usize) >= LC {
return Err(error::Error::Unwind);
}
let values_ptr: *const SlotArray<V::Slot, LC> =
unsafe { ptr::addr_of!((*leaf_ptr).values) };
let snapshot: V = match unsafe { SlotArray::try_load_raw(values_ptr, pos as usize) }
{
Some(v) => v,
None => {
std::hint::cold_path();
return Err(error::Error::Unwind);
}
};
if let Err(err) = leaf_guard.recheck() {
core::mem::forget(snapshot);
return Err(err);
}
let result = f(&snapshot);
drop(snapshot);
Ok(Some(result))
};
match perform() {
Ok(result) => return result,
Err(_) => {
std::hint::cold_path();
continue;
}
}
}
}
pub fn get<Q>(&self, key: &Q) -> Option<V>
where
K: Borrow<Q> + Ord,
Q: ?Sized + Ord,
V: Clone,
{
self.lookup(key, |v| v.clone())
}
pub fn get_optimistic<Q>(&self, key: &Q) -> Option<V>
where
K: Borrow<Q> + Ord + OptimisticRead,
Q: ?Sized + Ord,
V: OptimisticRead + Clone,
{
self.lookup_optimistic(key, |v| v.clone())
}
pub fn first<R, F>(&self, f: F) -> Option<R>
where
K: Ord,
F: Fn(&K, &V) -> R,
{
let mut iter = self.raw_iter();
iter.seek_to_first();
iter.next().map(|(k, v)| f(k, v))
}
pub fn last<R, F>(&self, f: F) -> Option<R>
where
K: Ord,
F: Fn(&K, &V) -> R,
{
let mut iter = self.raw_iter();
iter.seek_to_last();
iter.prev().map(|(k, v)| f(k, v))
}
pub fn pop_first(&self) -> Option<(K, V)>
where
K: Clone + Ord,
{
self.first(|k, _| k.clone()).and_then(|k| self.remove_entry(&k))
}
pub fn pop_last(&self) -> Option<(K, V)>
where
K: Clone + Ord,
{
self.last(|k, _| k.clone()).and_then(|k| self.remove_entry(&k))
}
pub fn remove<Q>(&self, key: &Q) -> Option<V>
where
K: Borrow<Q> + Ord,
Q: ?Sized + Ord,
{
self.remove_entry(key).map(|(_, v)| v)
}
pub fn remove_defer<Q>(&self, key: &Q) -> bool
where
K: Borrow<Q> + Ord + OptimisticRead + Send + 'static,
Q: ?Sized + Ord,
V: OptimisticRead + Send + 'static,
{
let eg = epoch::pin();
let removed = self.remove_entry(key);
if let Some((k, v)) = removed {
optimistic::drop_or_defer(k, &eg);
optimistic::drop_or_defer(v, &eg);
drop(eg);
true
} else {
drop(eg);
false
}
}
pub fn remove_entry<Q>(&self, key: &Q) -> Option<(K, V)>
where
K: Borrow<Q> + Ord,
Q: ?Sized + Ord,
{
let eg = epoch::pin();
let result = if let Some(((guard, pos), _parent_opt)) =
self.find_exact_exclusive_leaf_and_optimistic_parent(key, &eg)
{
let kv = unsafe {
let node_ptr = guard.as_mut_ptr();
let leaf_ptr = Node::as_leaf_ptr_mut(node_ptr);
LeafNode::remove_at_raw(leaf_ptr, pos, &eg)
};
if guard.is_underfull() {
let guard = guard.unlock();
let _ = self.try_merge(&guard, &eg);
}
Some(kv)
} else {
None
};
drop(eg);
result
}
pub fn insert(&self, key: K, value: V) -> Option<V>
where
K: Ord,
V: Clone,
{
let mut iter = self.raw_iter_mut();
iter.insert(key, value)
}
pub fn insert_defer(&self, key: K, value: V) -> bool
where
K: Ord + OptimisticRead,
V: OptimisticRead + Clone + Send + 'static,
{
let eg = epoch::pin();
let displaced = {
let mut iter = self.raw_iter_mut();
iter.insert(key, value)
};
if let Some(old_v) = displaced {
optimistic::drop_or_defer(old_v, &eg);
drop(eg);
true
} else {
drop(eg);
false
}
}
pub fn get_or_insert(&self, key: K, default: V) -> V
where
K: Ord,
V: Clone,
{
self.get_or_insert_with(key, || default)
}
pub fn get_or_insert_with<F>(&self, key: K, f: F) -> V
where
K: Ord,
V: Clone,
F: FnOnce() -> V,
{
let mut iter = self.raw_iter_mut();
if iter.seek_exact(&key) {
let (_k, v) = iter.next().expect("seek_exact returned true");
v.clone()
} else {
let value = f();
let result = value.clone();
iter.insert(key, value);
result
}
}
pub fn clear(&self)
where
K: Ord,
{
let eg = epoch::pin();
let mut tree_guard = self.root.exclusive();
let old_root = tree_guard.load(Ordering::Acquire, &eg);
if !old_root.is_null() {
unsafe { eg.defer_destroy(old_root) };
}
let new_root = Owned::new(HybridLatch::new(Node::Leaf(LeafNode::new())));
*tree_guard = Atomic::from(new_root);
self.height.store(1, Ordering::Release);
}
pub(crate) fn try_split<'t, 'g, 'e>(
&'t self,
needle: &OptimisticGuard<'g, Node<K, V, IC, LC>>,
eg: &'e epoch::Guard,
) -> error::Result<()>
where
K: Ord,
{
let parent_handler = self.find_parent(needle, eg)?;
match parent_handler {
ParentHandler::Root {
tree_guard,
} => {
let mut tree_guard_x = tree_guard.to_exclusive()?;
let root_latch = unsafe { tree_guard_x.load(Ordering::Acquire, eg).deref() };
let mut root_guard_x = root_latch.exclusive();
let mut new_root_owned: Owned<HybridLatch<Node<K, V, IC, LC>>> =
Owned::new(HybridLatch::new(Node::Internal(InternalNode::new())));
match root_guard_x.as_mut() {
Node::Internal(root_internal_node) => {
if root_internal_node.len.load() <= 2 {
return Ok(());
}
let split_pos = root_internal_node.len.load() / 2;
let split_key = root_internal_node
.key_at(split_pos)
.expect("split position must be within node bounds")
.clone();
let mut new_right_node_owned =
Owned::new(HybridLatch::new(Node::Internal(InternalNode::new())));
{
let new_right_node =
new_right_node_owned.as_mut().as_mut().as_internal_mut();
root_internal_node.split(new_right_node, split_pos);
}
let old_root_edge = Atomic::from(tree_guard_x.load(Ordering::Acquire, eg));
let new_right_node_edge =
Atomic::<HybridLatch<Node<K, V, IC, LC>>>::from(new_right_node_owned);
{
let new_root = new_root_owned.as_mut().as_mut().as_internal_mut();
new_root.insert(split_key, old_root_edge);
new_root.upper_edge = new_right_node_edge;
}
}
Node::Leaf(root_leaf_node) => {
if root_leaf_node.len.load() <= 2 {
return Ok(());
}
let split_pos = root_leaf_node.len.load() / 2;
let split_key = root_leaf_node
.key_at(split_pos)
.expect("split position must be within node bounds")
.clone();
let mut new_right_node_owned =
Owned::new(HybridLatch::new(Node::Leaf(LeafNode::new())));
{
let new_right_node =
new_right_node_owned.as_mut().as_mut().as_leaf_mut();
root_leaf_node.split(new_right_node, split_pos);
}
let old_root_edge = Atomic::from(tree_guard_x.load(Ordering::Acquire, eg));
let new_right_node_edge =
Atomic::<HybridLatch<Node<K, V, IC, LC>>>::from(new_right_node_owned);
{
let new_root = new_root_owned.as_mut().as_mut().as_internal_mut();
new_root.insert(split_key, old_root_edge);
new_root.upper_edge = new_right_node_edge;
}
}
}
let new_root_node_edge =
Atomic::<HybridLatch<Node<K, V, IC, LC>>>::from(new_root_owned);
*tree_guard_x = new_root_node_edge;
self.height.fetch_add(1, Ordering::Relaxed);
}
ParentHandler::Parent {
parent_guard,
pos,
} => {
if parent_guard.as_internal().has_space() {
let swip = parent_guard.as_internal().edge_at(pos)?;
let target_guard = GenericTree::lock_coupling(&parent_guard, swip, eg)?;
let target_latch = target_guard.latch() as *const _;
let needle_latch = needle.latch() as *const _;
if target_latch != needle_latch {
return Err(error::Error::Reclaimed);
}
let mut parent_guard_x = parent_guard.to_exclusive()?;
let mut target_guard_x = target_guard.to_exclusive()?;
match target_guard_x.as_mut() {
Node::Internal(left_internal) => {
if left_internal.len.load() <= 2 {
return Ok(());
}
let split_pos = left_internal.len.load() / 2;
let split_key = left_internal
.key_at(split_pos)
.expect("split position must be within node bounds")
.clone();
let mut new_right_node_owned =
Owned::new(HybridLatch::new(Node::Internal(InternalNode::new())));
{
let new_right_node =
new_right_node_owned.as_mut().as_mut().as_internal_mut();
left_internal.split(new_right_node, split_pos);
}
let new_right_node_edge =
Atomic::<HybridLatch<Node<K, V, IC, LC>>>::from(
new_right_node_owned,
);
let parent_internal = parent_guard_x.as_internal_mut();
if pos == parent_internal.len.load() {
let left_edge = std::mem::replace(
&mut parent_internal.upper_edge,
new_right_node_edge,
);
parent_internal.insert(split_key, left_edge);
} else {
parent_internal.insert_after(pos, split_key, new_right_node_edge);
}
}
Node::Leaf(left_leaf) => {
if left_leaf.len.load() <= 2 {
return Ok(());
}
let split_pos = left_leaf.len.load() / 2;
let split_key = left_leaf
.key_at(split_pos)
.expect("split position must be within node bounds")
.clone();
let mut new_right_node_owned =
Owned::new(HybridLatch::new(Node::Leaf(LeafNode::new())));
{
let new_right_node =
new_right_node_owned.as_mut().as_mut().as_leaf_mut();
left_leaf.split(new_right_node, split_pos);
}
let new_right_node_edge =
Atomic::<HybridLatch<Node<K, V, IC, LC>>>::from(
new_right_node_owned,
);
let parent_internal = parent_guard_x.as_internal_mut();
if pos == parent_internal.len.load() {
let left_edge = std::mem::replace(
&mut parent_internal.upper_edge,
new_right_node_edge,
);
parent_internal.insert(split_key, left_edge);
} else {
parent_internal.insert_after(pos, split_key, new_right_node_edge);
}
}
}
} else {
self.try_split(&parent_guard, eg)?;
return Err(error::Error::Reclaimed);
}
}
}
Ok(())
}
pub(crate) fn try_merge<'t, 'g, 'e>(
&'t self,
needle: &OptimisticGuard<'g, Node<K, V, IC, LC>>,
eg: &'e epoch::Guard,
) -> error::Result<bool>
where
K: Ord,
{
let parent_handler = self.find_parent(needle, eg)?;
match parent_handler {
ParentHandler::Root {
tree_guard: _,
} => {
Ok(false)
}
ParentHandler::Parent {
mut parent_guard,
pos,
} => {
let parent_len = parent_guard.as_internal().len.load();
let swip = parent_guard.as_internal().edge_at(pos)?;
let mut target_guard = GenericTree::lock_coupling(&parent_guard, swip, eg)?;
if !target_guard.is_underfull() {
target_guard.recheck()?;
return Ok(false);
}
let merge_succeeded = if parent_len > 1 && pos > 0 {
let l_swip = parent_guard.as_internal().edge_at(pos - 1)?;
let left_guard = GenericTree::lock_coupling(&parent_guard, l_swip, eg)?;
if !left_guard.can_merge_with(&target_guard) {
left_guard.recheck()?;
target_guard.recheck()?;
false
} else {
let mut parent_guard_x = parent_guard.to_exclusive()?;
let mut target_guard_x = target_guard.to_exclusive()?;
let mut left_guard_x = left_guard.to_exclusive()?;
match target_guard_x.as_mut() {
Node::Leaf(ref mut target_leaf) => {
assert!(left_guard_x.is_leaf());
if !left_guard_x.as_leaf_mut().merge(target_leaf) {
parent_guard = parent_guard_x.unlock();
target_guard = target_guard_x.unlock();
false
} else {
let parent_internal = parent_guard_x.as_internal_mut();
if pos == parent_len {
let (_, left_edge) = parent_internal.remove_at(pos - 1);
let dropped_edge = std::mem::replace(
&mut parent_internal.upper_edge,
left_edge,
);
let shared = dropped_edge.load(Ordering::Relaxed, eg);
if !shared.is_null() {
unsafe { eg.defer_destroy(shared) };
}
} else {
let (_, left_edge) = parent_internal.remove_at(pos - 1);
let dropped_edge = std::mem::replace(
&mut parent_internal.edges[(pos - 1) as usize],
left_edge,
);
let shared = dropped_edge.load(Ordering::Relaxed, eg);
if !shared.is_null() {
unsafe { eg.defer_destroy(shared) };
}
}
parent_guard = parent_guard_x.unlock();
target_guard = target_guard_x.unlock();
true
}
}
Node::Internal(target_internal) => {
assert!(!left_guard_x.is_leaf());
if !left_guard_x.as_internal_mut().merge(target_internal) {
parent_guard = parent_guard_x.unlock();
target_guard = target_guard_x.unlock();
false
} else {
let parent_internal = parent_guard_x.as_internal_mut();
if pos == parent_len {
let (_, left_edge) = parent_internal.remove_at(pos - 1);
let dropped_edge = std::mem::replace(
&mut parent_internal.upper_edge,
left_edge,
);
let shared = dropped_edge.load(Ordering::Relaxed, eg);
if !shared.is_null() {
unsafe { eg.defer_destroy(shared) };
}
} else {
let (_, left_edge) = parent_internal.remove_at(pos - 1);
let dropped_edge = std::mem::replace(
&mut parent_internal.edges[(pos - 1) as usize],
left_edge,
);
let shared = dropped_edge.load(Ordering::Relaxed, eg);
if !shared.is_null() {
unsafe { eg.defer_destroy(shared) };
}
}
parent_guard = parent_guard_x.unlock();
target_guard = target_guard_x.unlock();
true
}
}
}
}
} else {
false
};
let merge_succeeded =
if !merge_succeeded && parent_len > 0 && (pos + 1) <= parent_len {
let r_swip = parent_guard.as_internal().edge_at(pos + 1)?;
let right_guard = GenericTree::lock_coupling(&parent_guard, r_swip, eg)?;
if !right_guard.can_merge_with(&target_guard) {
right_guard.recheck()?;
target_guard.recheck()?;
false
} else {
let mut parent_guard_x = parent_guard.to_exclusive()?;
let mut target_guard_x = target_guard.to_exclusive()?;
let mut right_guard_x = right_guard.to_exclusive()?;
match target_guard_x.as_mut() {
Node::Leaf(ref mut target_leaf) => {
assert!(right_guard_x.is_leaf());
if !target_leaf.merge(right_guard_x.as_leaf_mut()) {
parent_guard = parent_guard_x.unlock();
let _ = target_guard_x.unlock();
false
} else {
let parent_internal = parent_guard_x.as_internal_mut();
if pos + 1 == parent_len {
let (_, left_edge) = parent_internal.remove_at(pos);
let dropped_edge = std::mem::replace(
&mut parent_internal.upper_edge,
left_edge,
);
let shared = dropped_edge.load(Ordering::Relaxed, eg);
if !shared.is_null() {
unsafe { eg.defer_destroy(shared) };
}
} else {
let (_, left_edge) = parent_internal.remove_at(pos);
let dropped_edge = std::mem::replace(
&mut parent_internal.edges[pos as usize],
left_edge,
);
let shared = dropped_edge.load(Ordering::Relaxed, eg);
if !shared.is_null() {
unsafe { eg.defer_destroy(shared) };
}
}
parent_guard = parent_guard_x.unlock();
let _ = target_guard_x.unlock();
true
}
}
Node::Internal(target_internal) => {
assert!(!right_guard_x.is_leaf());
if !target_internal.merge(right_guard_x.as_internal_mut()) {
parent_guard = parent_guard_x.unlock();
let _ = target_guard_x.unlock();
false
} else {
let parent_internal = parent_guard_x.as_internal_mut();
if pos + 1 == parent_len {
let (_, left_edge) = parent_internal.remove_at(pos);
let dropped_edge = std::mem::replace(
&mut parent_internal.upper_edge,
left_edge,
);
let shared = dropped_edge.load(Ordering::Relaxed, eg);
if !shared.is_null() {
unsafe { eg.defer_destroy(shared) };
}
} else {
let (_, left_edge) = parent_internal.remove_at(pos);
let dropped_edge = std::mem::replace(
&mut parent_internal.edges[pos as usize],
left_edge,
);
let shared = dropped_edge.load(Ordering::Relaxed, eg);
if !shared.is_null() {
unsafe { eg.defer_destroy(shared) };
}
}
parent_guard = parent_guard_x.unlock();
let _ = target_guard_x.unlock();
true
}
}
}
}
} else {
merge_succeeded
};
let parent_merge = || {
if parent_guard.is_underfull() {
parent_guard.recheck()?;
let _ = self.try_merge(&parent_guard, eg)?;
}
error::Result::Ok(())
};
let _ = parent_merge();
Ok(merge_succeeded)
}
}
}
pub fn raw_iter(&self) -> iter::RawSharedIter<'_, K, V, IC, LC>
where
K: Ord,
{
iter::RawSharedIter::new(self)
}
pub fn raw_iter_mut(&self) -> iter::RawExclusiveIter<'_, K, V, IC, LC>
where
K: Ord,
V: Clone,
{
iter::RawExclusiveIter::new(self)
}
pub fn range<Q>(&self, min: Bound<&Q>, max: Bound<&Q>) -> iter::Range<'_, K, V, IC, LC>
where
K: Borrow<Q> + Clone + Ord,
Q: ?Sized + Ord,
{
iter::Range::new(self, min, max)
}
pub fn range_rev<Q>(&self, min: Bound<&Q>, max: Bound<&Q>) -> iter::RangeRev<'_, K, V, IC, LC>
where
K: Borrow<Q> + Clone + Ord,
Q: ?Sized + Ord,
{
iter::RangeRev::new(self, min, max)
}
pub fn keys(&self) -> iter::Keys<'_, K, V, IC, LC>
where
K: Clone + Ord,
{
iter::Keys::new(self)
}
pub fn values(&self) -> iter::Values<'_, K, V, IC, LC>
where
K: Clone + Ord,
{
iter::Values::new(self)
}
pub fn len(&self) -> usize {
let mut count = 0usize;
let mut iter = self.raw_iter();
iter.seek_to_first();
while iter.next().is_some() {
count += 1;
}
count
}
pub fn is_empty(&self) -> bool {
let eg = epoch::pin();
loop {
let perform = || {
let (leaf_guard, _parent_opt) = self.find_first_leaf_and_parent(&eg)?;
let is_empty = leaf_guard.as_leaf().len.load() == 0;
leaf_guard.recheck()?;
error::Result::Ok(is_empty)
};
match perform() {
Ok(result) => return result,
Err(_) => continue, }
}
}
}
#[repr(C, u8)]
pub(crate) enum Node<K: OptimisticRead, V: OptimisticRead, const IC: usize, const LC: usize> {
Internal(InternalNode<K, V, IC, LC>) = 0,
Leaf(LeafNode<K, V, LC>) = 1,
}
pub(crate) enum NodeKindRaw<K: OptimisticRead, V: OptimisticRead, const IC: usize, const LC: usize>
{
Internal(*const InternalNode<K, V, IC, LC>),
Leaf(*const LeafNode<K, V, LC>),
}
impl<
K: fmt::Debug + OptimisticRead,
V: fmt::Debug + OptimisticRead,
const IC: usize,
const LC: usize,
> fmt::Debug for Node<K, V, IC, LC>
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Node::Internal(ref internal) => f.debug_tuple("Internal").field(internal).finish(),
Node::Leaf(ref leaf) => f.debug_tuple("Leaf").field(leaf).finish(),
}
}
}
impl<K: OptimisticRead, V: OptimisticRead, const IC: usize, const LC: usize> Node<K, V, IC, LC> {
#[inline]
pub(crate) fn is_leaf(&self) -> bool {
matches!(self, Node::Leaf(_))
}
#[inline]
pub(crate) unsafe fn variant_raw(this: *const Self) -> NodeKindRaw<K, V, IC, LC> {
let tag = unsafe { ptr::read(this as *const u8) };
let payload_offset = core::mem::align_of::<Self>();
let payload = unsafe { (this as *const u8).add(payload_offset) };
match tag {
0 => NodeKindRaw::Internal(payload.cast::<InternalNode<K, V, IC, LC>>()),
1 => NodeKindRaw::Leaf(payload.cast::<LeafNode<K, V, LC>>()),
_ => {
std::hint::cold_path();
NodeKindRaw::Leaf(payload.cast::<LeafNode<K, V, LC>>())
}
}
}
#[inline]
pub(crate) unsafe fn as_leaf_ptr_mut(this: *mut Self) -> *mut LeafNode<K, V, LC> {
debug_assert!(matches!(
unsafe { Self::variant_raw(this as *const Self) },
NodeKindRaw::Leaf(_)
));
let payload_offset = core::mem::align_of::<Self>();
let payload = unsafe { (this as *mut u8).add(payload_offset) };
payload.cast::<LeafNode<K, V, LC>>()
}
#[inline]
#[allow(dead_code)]
pub(crate) fn try_as_leaf(&self) -> Option<&LeafNode<K, V, LC>> {
match self {
Node::Leaf(ref leaf) => Some(leaf),
Node::Internal(_) => None,
}
}
#[inline]
pub(crate) fn as_leaf(&self) -> &LeafNode<K, V, LC> {
match self {
Node::Leaf(ref leaf) => leaf,
Node::Internal(_) => {
unreachable!(
"as_leaf() called on internal node - this indicates a tree traversal bug"
)
}
}
}
#[inline]
#[allow(dead_code)]
pub(crate) fn try_as_leaf_mut(&mut self) -> Option<&mut LeafNode<K, V, LC>> {
match self {
Node::Leaf(ref mut leaf) => Some(leaf),
Node::Internal(_) => None,
}
}
#[inline]
pub(crate) fn as_leaf_mut(&mut self) -> &mut LeafNode<K, V, LC> {
match self {
Node::Leaf(ref mut leaf) => leaf,
Node::Internal(_) => {
unreachable!(
"as_leaf_mut() called on internal node - this indicates a tree traversal bug"
)
}
}
}
#[inline]
#[allow(dead_code)]
pub(crate) fn try_as_internal(&self) -> Option<&InternalNode<K, V, IC, LC>> {
match self {
Node::Internal(ref internal) => Some(internal),
Node::Leaf(_) => None,
}
}
#[inline]
pub(crate) fn as_internal(&self) -> &InternalNode<K, V, IC, LC> {
match self {
Node::Internal(ref internal) => internal,
Node::Leaf(_) => {
unreachable!(
"as_internal() called on leaf node - this indicates a tree traversal bug"
)
}
}
}
#[inline]
#[allow(dead_code)]
pub(crate) fn try_as_internal_mut(&mut self) -> Option<&mut InternalNode<K, V, IC, LC>> {
match self {
Node::Internal(ref mut internal) => Some(internal),
Node::Leaf(_) => None,
}
}
#[inline]
pub(crate) fn as_internal_mut(&mut self) -> &mut InternalNode<K, V, IC, LC> {
match self {
Node::Internal(ref mut internal) => internal,
Node::Leaf(_) => {
unreachable!(
"as_internal_mut() called on leaf node - this indicates a tree traversal bug"
)
}
}
}
#[cfg(test)]
#[inline]
pub(crate) fn keys(&self) -> Vec<K>
where
K: Clone,
{
match self {
Node::Internal(ref internal) => internal.keys.iter().cloned().collect(),
Node::Leaf(ref leaf) => {
let len = leaf.len.load() as usize;
(0..len)
.map(|i| unsafe { SlotArray::load_raw(ptr::addr_of!(leaf.keys), i) })
.collect()
}
}
}
#[inline]
pub(crate) fn sample_key(&self) -> Option<&K> {
match self {
Node::Internal(ref internal) => internal.sample_key.as_ref(),
Node::Leaf(ref leaf) => leaf.sample_key.as_ref(),
}
}
#[inline]
pub(crate) fn is_underfull(&self) -> bool {
match self {
Node::Internal(ref internal) => internal.is_underfull(),
Node::Leaf(ref leaf) => leaf.is_underfull(),
}
}
#[inline]
pub(crate) fn can_merge_with(&self, other: &Self) -> bool {
match self {
Node::Internal(ref internal) => match other {
Node::Internal(ref other) => {
((internal.len.load() + 1 + other.len.load()) as usize) < IC
}
_ => false, },
Node::Leaf(ref leaf) => match other {
Node::Leaf(ref other) => {
((leaf.len.load() + other.len.load()) as usize) < LC
}
_ => false, },
}
}
}
#[repr(C, align(64))]
pub(crate) struct LeafNode<K: OptimisticRead, V: OptimisticRead, const LC: usize> {
pub(crate) len: AtomicLen,
pub(crate) keys: SlotArray<K::Slot, LC>,
pub(crate) values: SlotArray<V::Slot, LC>,
pub(crate) lower_fence: Option<K>,
pub(crate) upper_fence: Option<K>,
pub(crate) sample_key: Option<K>,
}
impl<K: fmt::Debug + OptimisticRead, V: fmt::Debug + OptimisticRead, const LC: usize> fmt::Debug
for LeafNode<K, V, LC>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("LeafNode")
.field("len", &self.len.load_relaxed())
.field("lower_fence", &self.lower_fence)
.field("upper_fence", &self.upper_fence)
.field("sample_key", &self.sample_key)
.finish()
}
}
impl<K: OptimisticRead, V: OptimisticRead, const LC: usize> LeafNode<K, V, LC> {
pub fn new() -> LeafNode<K, V, LC> {
LeafNode {
len: AtomicLen::new(0),
keys: SlotArray::new(),
values: SlotArray::new(),
lower_fence: None,
upper_fence: None,
sample_key: None,
}
}
#[inline]
pub(crate) fn lower_bound<Q>(&self, key: &Q) -> (u16, bool)
where
K: Borrow<Q> + Ord,
Q: ?Sized + Ord,
{
if self.lower_fence().map(|fk| key < fk.borrow()).unwrap_or(false) {
return (0, false);
}
if let Some(fk) = self.upper_fence() {
if key > fk.borrow() {
return (self.len.load_relaxed(), false);
}
}
let mut lower = 0;
let mut upper = self.len.load_relaxed().min(LC as u16);
while lower < upper {
let mid = ((upper - lower) / 2) + lower;
let mut buf: core::mem::MaybeUninit<K> = core::mem::MaybeUninit::uninit();
let mid_key: &K = unsafe { self.keys.load_into(mid as usize, &mut buf) };
if key < mid_key.borrow() {
upper = mid;
} else if key > mid_key.borrow() {
lower = mid + 1;
} else {
return (mid, true);
}
}
(lower, false)
}
#[inline]
pub(crate) fn lower_fence(&self) -> Option<&K> {
self.lower_fence.as_ref()
}
#[inline]
pub(crate) fn upper_fence(&self) -> Option<&K> {
self.upper_fence.as_ref()
}
#[inline]
pub(crate) unsafe fn len_raw(this: *const Self) -> u16 {
unsafe { AtomicLen::load_raw(ptr::addr_of!((*this).len)) }
}
#[inline]
pub(crate) unsafe fn lower_bound_raw<Q>(this: *const Self, key: &Q) -> (u16, bool)
where
K: Borrow<Q> + Ord + OptimisticRead,
Q: ?Sized + Ord,
{
let lower_fence: *const Option<K> = unsafe { ptr::addr_of!((*this).lower_fence) };
let upper_fence: *const Option<K> = unsafe { ptr::addr_of!((*this).upper_fence) };
let lf_snapshot: core::mem::ManuallyDrop<Option<K>> =
unsafe { core::mem::ManuallyDrop::new(ptr::read(lower_fence)) };
if let Some(fk) = lf_snapshot.as_ref() {
if key < fk.borrow() {
return (0, false);
}
}
let len = unsafe { Self::len_raw(this) };
let uf_snapshot: core::mem::ManuallyDrop<Option<K>> =
unsafe { core::mem::ManuallyDrop::new(ptr::read(upper_fence)) };
if let Some(fk) = uf_snapshot.as_ref() {
if key > fk.borrow() {
return (len, false);
}
}
let keys_ptr: *const SlotArray<K::Slot, LC> = unsafe { ptr::addr_of!((*this).keys) };
let mut lower: u16 = 0;
let mut upper: u16 = len.min(LC as u16);
while lower < upper {
let mid = ((upper - lower) / 2) + lower;
let mut buf: core::mem::MaybeUninit<K> = core::mem::MaybeUninit::uninit();
let mid_key_opt =
unsafe { SlotArray::try_load_into_raw(keys_ptr, mid as usize, &mut buf) };
let mid_key = match mid_key_opt {
Some(k) => k,
None => {
std::hint::cold_path();
return (lower, false);
}
};
if key < mid_key.borrow() {
upper = mid;
} else if key > mid_key.borrow() {
lower = mid + 1;
} else {
return (mid, true);
}
}
(lower, false)
}
#[inline]
pub(crate) fn value_at(&self, pos: u16) -> error::Result<V> {
if pos as usize >= self.len.load_relaxed() as usize {
return Err(error::Error::Unwind);
}
unsafe { SlotArray::try_load_raw(ptr::addr_of!(self.values), pos as usize) }
.ok_or(error::Error::Unwind)
}
#[inline]
pub(crate) fn key_at(&self, pos: u16) -> error::Result<K> {
if pos as usize >= self.len.load_relaxed() as usize {
return Err(error::Error::Unwind);
}
unsafe { SlotArray::try_load_raw(ptr::addr_of!(self.keys), pos as usize) }
.ok_or(error::Error::Unwind)
}
#[inline]
#[allow(dead_code)]
pub(crate) fn kv_at(&self, pos: u16) -> error::Result<(K, V)> {
let k = self.key_at(pos)?;
let v = self.value_at(pos)?;
Ok((k, v))
}
#[inline]
pub(crate) unsafe fn kv_at_unchecked(&self, pos: u16) -> (K, V) {
let k = unsafe { SlotArray::load_raw(ptr::addr_of!(self.keys), pos as usize) };
let v = unsafe { SlotArray::load_raw(ptr::addr_of!(self.values), pos as usize) };
(k, v)
}
#[inline]
pub(crate) fn has_space(&self) -> bool {
(self.len.load_relaxed() as usize) < LC
}
#[inline]
pub(crate) fn is_underfull(&self) -> bool {
(self.len.load_relaxed() as usize) * 10 < LC * 4
}
pub(crate) unsafe fn remove_at_raw(this: *mut Self, pos: u16, eg: &epoch::Guard) -> (K, V) {
let len = unsafe { AtomicLen::load_raw_relaxed(ptr::addr_of!((*this).len)) } as usize;
let keys_ptr = unsafe { ptr::addr_of!((*this).keys) };
let values_ptr = unsafe { ptr::addr_of!((*this).values) };
let removed_k: K = unsafe { SlotArray::load_raw(keys_ptr, pos as usize) };
let removed_v: V = unsafe { SlotArray::load_raw(values_ptr, pos as usize) };
let displaced_k = unsafe { SlotArray::shift_remove_raw(keys_ptr, len, pos as usize) };
let displaced_v = unsafe { SlotArray::shift_remove_raw(values_ptr, len, pos as usize) };
eg.defer(move || drop(displaced_k));
eg.defer(move || drop(displaced_v));
let len_ptr: *const AtomicLen = unsafe { ptr::addr_of!((*this).len) };
unsafe { (*len_ptr).fetch_sub_relaxed(1) };
(removed_k, removed_v)
}
pub(crate) unsafe fn swap_value_at_raw(
this: *mut Self,
pos: u16,
value: V,
eg: &epoch::Guard,
) -> V {
let len = unsafe { AtomicLen::load_raw_relaxed(ptr::addr_of!((*this).len)) } as usize;
debug_assert!((pos as usize) < len);
let values_ptr = unsafe { ptr::addr_of!((*this).values) };
let old_v: V = unsafe { SlotArray::load_raw(values_ptr, pos as usize) };
let displaced = unsafe { SlotArray::swap_init_raw(values_ptr, pos as usize, value) };
eg.defer(move || drop(displaced));
old_v
}
#[inline]
pub(crate) fn within_bounds<Q>(&self, key: &Q) -> bool
where
K: Borrow<Q> + Ord,
Q: ?Sized + Ord,
{
match (self.lower_fence().map(Borrow::borrow), self.upper_fence().map(Borrow::borrow)) {
(Some(lf), Some(uf)) => key > lf && key <= uf,
(Some(lf), None) => key > lf,
(None, Some(uf)) => key <= uf,
(None, None) => true,
}
}
}
impl<K: Clone + OptimisticRead, V: Clone + OptimisticRead, const LC: usize> LeafNode<K, V, LC> {
pub(crate) unsafe fn insert_at_raw(this: *mut Self, pos: u16, key: K, value: V) -> Option<u16> {
let len_ptr: *const AtomicLen = unsafe { ptr::addr_of!((*this).len) };
let len = unsafe { AtomicLen::load_raw_relaxed(len_ptr) } as usize;
if len >= LC {
return None;
}
let sample_key_ptr: *mut Option<K> = unsafe { ptr::addr_of_mut!((*this).sample_key) };
if unsafe { (*sample_key_ptr).is_none() } {
unsafe { ptr::write(sample_key_ptr, Some(key.clone())) };
}
let keys_ptr = unsafe { ptr::addr_of!((*this).keys) };
let values_ptr = unsafe { ptr::addr_of!((*this).values) };
unsafe { SlotArray::shift_insert_raw(keys_ptr, len, pos as usize, key) };
unsafe { SlotArray::shift_insert_raw(values_ptr, len, pos as usize, value) };
unsafe { (*len_ptr).fetch_add_relaxed(1) };
Some(pos)
}
}
impl<K: Clone + OptimisticRead, V: OptimisticRead, const LC: usize> LeafNode<K, V, LC> {
pub(crate) fn split(&mut self, right: &mut LeafNode<K, V, LC>, split_pos: u16) {
let total = self.len.load_relaxed() as usize;
let right_start = (split_pos + 1) as usize;
let right_count = total - right_start;
let self_keys_ptr: *const _ = ptr::addr_of!(self.keys);
let split_key: K = unsafe { SlotArray::load_raw(self_keys_ptr, split_pos as usize) };
right.lower_fence = Some(split_key.clone());
right.upper_fence = self.upper_fence.clone();
self.upper_fence = Some(split_key);
let right_ptr: *const Self = right;
let self_keys = self_keys_ptr;
let self_values = ptr::addr_of!(self.values);
let right_keys = unsafe { ptr::addr_of!((*right_ptr).keys) };
let right_values = unsafe { ptr::addr_of!((*right_ptr).values) };
for (dst_idx, src_pos) in (right_start..total).enumerate() {
unsafe {
SlotArray::move_raw(self_keys, src_pos, right_keys, dst_idx);
SlotArray::move_raw(self_values, src_pos, right_values, dst_idx);
}
}
let self_first: K = unsafe { SlotArray::load_raw(self_keys, 0) };
let right_first: K = unsafe { SlotArray::load_raw(right_keys, 0) };
self.sample_key = Some(self_first);
right.sample_key = Some(right_first);
unsafe {
self.len.store_relaxed(right_start as u16); right.len.store_relaxed(right_count as u16);
}
}
pub(crate) fn merge(&mut self, right: &mut LeafNode<K, V, LC>) -> bool {
let self_len = self.len.load_relaxed() as usize;
let right_len = right.len.load_relaxed() as usize;
if self_len + right_len > LC {
return false;
}
self.upper_fence = right.upper_fence.take();
let self_keys = ptr::addr_of!(self.keys);
let self_values = ptr::addr_of!(self.values);
let right_ptr: *const Self = right;
let right_keys = unsafe { ptr::addr_of!((*right_ptr).keys) };
let right_values = unsafe { ptr::addr_of!((*right_ptr).values) };
for src_idx in 0..right_len {
let dst_idx = self_len + src_idx;
unsafe {
SlotArray::move_raw(right_keys, src_idx, self_keys, dst_idx);
SlotArray::move_raw(right_values, src_idx, self_values, dst_idx);
}
}
unsafe { right.len.store_relaxed(0) };
if let Some(sample) = right.sample_key.take() {
self.sample_key = Some(sample);
} else if self.sample_key.is_none() && (self_len + right_len) > 0 {
let first_key: K = unsafe { SlotArray::load_raw(self_keys, 0) };
self.sample_key = Some(first_key);
}
unsafe { self.len.store_relaxed((self_len + right_len) as u16) };
true
}
}
#[repr(C, align(64))]
pub(crate) struct InternalNode<
K: OptimisticRead,
V: OptimisticRead,
const IC: usize,
const LC: usize,
> {
pub(crate) len: AtomicLen,
pub(crate) keys: InlineVec<K, IC>,
pub(crate) edges: InlineVec<Atomic<HybridLatch<Node<K, V, IC, LC>>>, IC>,
pub(crate) upper_edge: Atomic<HybridLatch<Node<K, V, IC, LC>>>,
pub(crate) lower_fence: Option<K>,
pub(crate) upper_fence: Option<K>,
pub(crate) sample_key: Option<K>,
}
impl<K: fmt::Debug + OptimisticRead, V: OptimisticRead, const IC: usize, const LC: usize> fmt::Debug
for InternalNode<K, V, IC, LC>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("InternalNode")
.field("len", &self.len.load_relaxed())
.field("keys", &self.keys)
.field("edges", &self.edges)
.field("upper_edge", &self.upper_edge)
.field("lower_fence", &self.lower_fence)
.field("upper_fence", &self.upper_fence)
.field("sample_key", &self.sample_key)
.finish()
}
}
impl<K: OptimisticRead, V: OptimisticRead, const IC: usize, const LC: usize>
InternalNode<K, V, IC, LC>
{
pub(crate) fn new() -> InternalNode<K, V, IC, LC> {
InternalNode {
len: AtomicLen::new(0),
keys: InlineVec::new(),
edges: InlineVec::new(),
upper_edge: Atomic::null(),
lower_fence: None,
upper_fence: None,
sample_key: None,
}
}
#[inline]
pub(crate) fn lower_bound<Q>(&self, key: &Q) -> (u16, bool)
where
K: Borrow<Q> + Ord,
Q: ?Sized + Ord,
{
if self.lower_fence().map(|fk| key < fk.borrow()).unwrap_or(false) {
return (0, false);
}
if let Some(fk) = self.upper_fence() {
if key > fk.borrow() {
return (self.len.load_relaxed(), false);
}
}
let keys_len = self.keys.len() as u16;
let mut lower = 0;
let mut upper = self.len.load_relaxed().min(keys_len);
while lower < upper {
let mid = ((upper - lower) / 2) + lower;
let Some(mid_key) = self.keys.get(mid as usize) else {
std::hint::cold_path();
return (lower, false);
};
if key < mid_key.borrow() {
upper = mid;
} else if key > mid_key.borrow() {
lower = mid + 1;
} else {
return (mid, true);
}
}
(lower, false)
}
#[inline]
pub(crate) fn lower_fence(&self) -> Option<&K> {
self.lower_fence.as_ref()
}
#[inline]
pub(crate) fn upper_fence(&self) -> Option<&K> {
self.upper_fence.as_ref()
}
#[inline]
pub(crate) unsafe fn len_raw(this: *const Self) -> u16 {
unsafe { AtomicLen::load_raw(ptr::addr_of!((*this).len)) }
}
#[inline]
#[allow(dead_code)]
pub(crate) unsafe fn keys_ptr_raw(this: *const Self) -> *const K {
unsafe { InlineVec::raw_data_ptr(ptr::addr_of!((*this).keys)) }
}
#[inline]
pub(crate) unsafe fn edges_ptr_raw(
this: *const Self,
) -> *const Atomic<HybridLatch<Node<K, V, IC, LC>>> {
unsafe { InlineVec::raw_data_ptr(ptr::addr_of!((*this).edges)) }
}
#[inline]
pub(crate) unsafe fn edge_at_raw(
this: *const Self,
pos: u16,
) -> error::Result<*const Atomic<HybridLatch<Node<K, V, IC, LC>>>> {
let len = unsafe { Self::len_raw(this) };
if pos == len {
let upper_edge_ptr: *const Atomic<HybridLatch<Node<K, V, IC, LC>>> =
unsafe { ptr::addr_of!((*this).upper_edge) };
Ok(upper_edge_ptr)
} else if pos < IC as u16 {
let edges_ptr = unsafe { Self::edges_ptr_raw(this) };
Ok(unsafe { edges_ptr.add(pos as usize) })
} else {
Err(error::Error::Unwind)
}
}
#[inline]
pub(crate) unsafe fn lower_bound_raw<Q>(this: *const Self, key: &Q) -> (u16, bool)
where
K: Borrow<Q> + Ord + OptimisticRead,
Q: ?Sized + Ord,
{
let lower_fence: *const Option<K> = unsafe { ptr::addr_of!((*this).lower_fence) };
let upper_fence: *const Option<K> = unsafe { ptr::addr_of!((*this).upper_fence) };
let lf_snapshot: core::mem::ManuallyDrop<Option<K>> =
unsafe { core::mem::ManuallyDrop::new(ptr::read(lower_fence)) };
if let Some(fk) = lf_snapshot.as_ref() {
if key < fk.borrow() {
return (0, false);
}
}
let len = unsafe { Self::len_raw(this) };
let uf_snapshot: core::mem::ManuallyDrop<Option<K>> =
unsafe { core::mem::ManuallyDrop::new(ptr::read(upper_fence)) };
if let Some(fk) = uf_snapshot.as_ref() {
if key > fk.borrow() {
return (len, false);
}
}
let keys_ptr = unsafe { Self::keys_ptr_raw(this) };
let mut lower: u16 = 0;
let mut upper: u16 = len.min(IC as u16);
while lower < upper {
let mid = ((upper - lower) / 2) + lower;
let mid_key_snapshot: core::mem::ManuallyDrop<K> =
unsafe { core::mem::ManuallyDrop::new(ptr::read(keys_ptr.add(mid as usize))) };
let mid_key: &K = &mid_key_snapshot;
if key < mid_key.borrow() {
upper = mid;
} else if key > mid_key.borrow() {
lower = mid + 1;
} else {
return (mid, true);
}
}
(lower, false)
}
#[inline]
pub(crate) fn edge_at(
&self,
pos: u16,
) -> error::Result<&Atomic<HybridLatch<Node<K, V, IC, LC>>>> {
if pos == self.len.load_relaxed() {
let eg = epoch::pin();
let shared = self.upper_edge.load(Ordering::Relaxed, &eg);
if shared.is_null() {
Err(error::Error::Unwind)
} else {
Ok(&self.upper_edge)
}
} else {
self.edges.get(pos as usize).ok_or(error::Error::Unwind)
}
}
#[inline]
pub(crate) fn key_at(&self, pos: u16) -> error::Result<&K> {
self.keys.get(pos as usize).ok_or(error::Error::Unwind)
}
#[inline]
pub(crate) fn has_space(&self) -> bool {
(self.len.load_relaxed() as usize) < IC
}
#[inline]
pub(crate) fn is_underfull(&self) -> bool {
(self.len.load_relaxed() as usize) * 10 < IC * 4
}
pub(crate) fn insert(
&mut self,
key: K,
value: Atomic<HybridLatch<Node<K, V, IC, LC>>>,
) -> Option<u16>
where
K: Ord,
{
let (pos, exact) = self.lower_bound(&key);
if exact {
unimplemented!("upserts");
} else {
if !self.has_space() {
return None;
}
self.keys.insert(pos as usize, key);
self.edges.insert(pos as usize, value);
unsafe { self.len.fetch_add_relaxed(1) };
}
Some(pos)
}
pub(crate) fn remove_at(&mut self, pos: u16) -> (K, Atomic<HybridLatch<Node<K, V, IC, LC>>>) {
let key = self.keys.remove(pos as usize);
let edge = self.edges.remove(pos as usize);
unsafe { self.len.fetch_sub_relaxed(1) };
(key, edge)
}
pub(crate) fn insert_after(
&mut self,
pos: u16,
key: K,
edge: Atomic<HybridLatch<Node<K, V, IC, LC>>>,
) {
self.keys.insert(pos as usize, key);
self.edges.insert((pos + 1) as usize, edge);
unsafe { self.len.fetch_add_relaxed(1) };
}
}
impl<K: Clone + OptimisticRead, V: OptimisticRead, const IC: usize, const LC: usize>
InternalNode<K, V, IC, LC>
{
pub(crate) fn split(&mut self, right: &mut InternalNode<K, V, IC, LC>, split_pos: u16) {
let split_key =
self.key_at(split_pos).expect("split position must be within node bounds").clone();
right.lower_fence = Some(split_key.clone());
right.upper_fence = self.upper_fence.clone();
self.upper_fence = Some(split_key);
assert!(right.keys.is_empty());
assert!(right.edges.is_empty());
right.keys.extend(self.keys.drain((split_pos + 1) as usize..));
right.edges.extend(self.edges.drain((split_pos + 1) as usize..));
right.upper_edge = std::mem::replace(&mut self.upper_edge, Atomic::null());
self.upper_edge =
self.edges.pop().expect("edges non-empty: split requires at least one edge");
self.keys.pop().expect("keys non-empty: split requires at least one key");
self.sample_key = Some(self.keys[0].clone());
right.sample_key = Some(right.keys[0].clone());
unsafe {
right.len.store_relaxed(right.keys.len() as u16);
self.len.store_relaxed(self.keys.len() as u16);
}
}
pub(crate) fn merge(&mut self, right: &mut InternalNode<K, V, IC, LC>) -> bool {
if (self.len.load_relaxed() + right.len.load_relaxed() + 1) as usize > IC {
return false;
}
let _left_upper_fence = std::mem::replace(&mut self.upper_fence, right.upper_fence.take());
let left_upper_edge = std::mem::replace(
&mut self.upper_edge,
std::mem::replace(&mut right.upper_edge, Atomic::null()),
);
self.keys.push(
right
.lower_fence
.take()
.expect("merge requires right node to have lower_fence (separator key)"),
);
self.edges.push(left_upper_edge);
self.keys.extend(right.keys.drain(..));
self.edges.extend(right.edges.drain(..));
if let Some(sample) = right.sample_key.take() {
self.sample_key = Some(sample);
} else if self.sample_key.is_none() && !self.keys.is_empty() {
self.sample_key = Some(self.keys[0].clone());
}
unsafe {
self.len.store_relaxed(self.keys.len() as u16);
right.len.store_relaxed(0);
}
true
}
}
#[cfg(any(test, feature = "test-utils"))]
impl<
K: Clone + Ord + std::fmt::Debug + OptimisticRead,
V: OptimisticRead,
const IC: usize,
const LC: usize,
> GenericTree<K, V, IC, LC>
{
pub fn assert_invariants(&self) {
let eg = epoch::pin();
let height = self.height.load(Ordering::Acquire);
let tree_guard = self.root.optimistic_or_spin();
let root_ptr = tree_guard.load(Ordering::Acquire, &eg);
if root_ptr.is_null() {
assert_eq!(height, 1, "Empty tree should have height 1");
return;
}
let root_latch = unsafe { root_ptr.deref() };
let root_guard = root_latch.optimistic_or_spin();
self.validate_node_recursive(&root_guard, 0, height, None, None, &eg);
}
fn validate_node_recursive<'a>(
&self,
guard: &OptimisticGuard<'a, Node<K, V, IC, LC>>,
level: usize,
height: usize,
expected_lower: Option<&K>,
expected_upper: Option<&K>,
eg: &epoch::Guard,
) {
let is_leaf_level = level == height - 1;
match guard.inner() {
Node::Leaf(leaf) => {
assert!(
is_leaf_level,
"Found leaf at level {} but expected internal (height={})",
level, height
);
let leaf_len = leaf.len.load() as usize;
let keys_owned: Vec<K> = (0..leaf_len)
.map(|i| unsafe { SlotArray::load_raw(ptr::addr_of!(leaf.keys), i) })
.collect();
for i in 1..leaf_len {
assert!(
keys_owned[i - 1] < keys_owned[i],
"Keys not sorted at positions {} and {}: {:?} >= {:?}",
i - 1,
i,
keys_owned[i - 1],
keys_owned[i]
);
}
if let Some(lower) = &leaf.lower_fence {
for key in &keys_owned {
assert!(
key > lower,
"Key {:?} not greater than lower_fence {:?}",
key,
lower
);
}
}
if let Some(upper) = &leaf.upper_fence {
for key in &keys_owned {
assert!(key <= upper, "Key {:?} not <= upper_fence {:?}", key, upper);
}
}
if let Some(lower) = expected_lower {
for key in &keys_owned {
assert!(
key > lower,
"Key {:?} not greater than parent lower bound {:?}",
key,
lower
);
}
}
if let Some(upper) = expected_upper {
for key in &keys_owned {
assert!(
key <= upper,
"Key {:?} not <= parent upper bound {:?}",
key,
upper
);
}
}
}
Node::Internal(internal) => {
assert!(
!is_leaf_level,
"Found internal node at leaf level {} (height={})",
level, height
);
let eg_local = epoch::pin();
assert!(
!internal.upper_edge.load(Ordering::Relaxed, &eg_local).is_null(),
"Internal node at level {} has no upper_edge",
level
);
assert_eq!(
internal.len.load() as usize,
internal.keys.len(),
"Internal len {} != keys.len() {}",
internal.len.load(),
internal.keys.len()
);
assert_eq!(
internal.keys.len(),
internal.edges.len(),
"Internal keys.len() {} != edges.len() {}",
internal.keys.len(),
internal.edges.len()
);
for i in 1..internal.keys.len() {
assert!(
internal.keys[i - 1] < internal.keys[i],
"Internal keys not sorted at {} and {}: {:?} >= {:?}",
i - 1,
i,
internal.keys[i - 1],
internal.keys[i]
);
}
if let Some(lower) = &internal.lower_fence {
for key in &internal.keys[..] {
assert!(
key > lower,
"Internal key {:?} not > lower_fence {:?}",
key,
lower
);
}
}
if let Some(upper) = &internal.upper_fence {
for key in &internal.keys[..] {
assert!(
key <= upper,
"Internal key {:?} not <= upper_fence {:?}",
key,
upper
);
}
}
let mut prev_upper: Option<&K> = expected_lower;
for (i, edge) in internal.edges.iter().enumerate() {
let child_ptr = edge.load(Ordering::Acquire, eg);
if !child_ptr.is_null() {
let child_latch = unsafe { child_ptr.deref() };
let child_guard = child_latch.optimistic_or_spin();
let child_upper = Some(&internal.keys[i]);
self.validate_node_recursive(
&child_guard,
level + 1,
height,
prev_upper,
child_upper,
eg,
);
prev_upper = child_upper;
}
}
let child_ptr = internal.upper_edge.load(Ordering::Acquire, eg);
if !child_ptr.is_null() {
let child_latch = unsafe { child_ptr.deref() };
let child_guard = child_latch.optimistic_or_spin();
self.validate_node_recursive(
&child_guard,
level + 1,
height,
prev_upper,
expected_upper,
eg,
);
}
}
}
}
}
#[cfg(test)]
mod node_layout {
use super::*;
#[test]
fn leaf_node_is_cache_line_aligned() {
assert_eq!(core::mem::align_of::<LeafNode<i64, i64, 16>>(), 64);
assert_eq!(core::mem::align_of::<LeafNode<String, String, 16>>(), 64);
}
#[test]
fn internal_node_is_cache_line_aligned() {
assert_eq!(core::mem::align_of::<InternalNode<i64, i64, 16, 16>>(), 64);
assert_eq!(core::mem::align_of::<InternalNode<String, i64, 16, 16>>(), 64);
}
}
#[cfg(test)]
mod raw_shared_iter_load_into {
use super::*;
#[test]
fn raw_shared_iter_string_kv_no_clone() {
let tree: Tree<String, String> = Tree::new();
for i in 0..1000 {
let k = format!("k{:06}", i);
tree.insert(k.clone(), k);
}
let mut iter = tree.raw_iter();
iter.seek_to_first();
let mut seen = 0;
while let Some((k, v)) = iter.next() {
assert_eq!(k, v);
assert_eq!(*k, format!("k{:06}", seen));
seen += 1;
}
assert_eq!(seen, 1000);
let mut iter = tree.raw_iter();
iter.seek_to_last();
let mut seen = 1000usize;
while let Some((k, _v)) = iter.prev() {
seen -= 1;
assert_eq!(*k, format!("k{:06}", seen));
}
assert_eq!(seen, 0);
}
}
#[cfg(test)]
mod leaf_binary_search_load_into {
use super::*;
#[test]
fn leaf_lower_bound_load_into_smoke() {
let tree: Tree<String, i64> = Tree::new();
for i in 0..10 {
tree.insert(format!("k{:04}", i), i);
}
for i in 0..10 {
let k = format!("k{:04}", i);
assert_eq!(tree.lookup(&k, |v| *v), Some(i));
assert_eq!(tree.lookup_optimistic(&k, |v| *v), Some(i));
}
assert_eq!(tree.lookup(&"k9999".to_string(), |v| *v), None);
assert_eq!(tree.lookup_optimistic(&"k9999".to_string(), |v| *v), None);
assert_eq!(tree.lookup(&"a".to_string(), |v| *v), None);
assert_eq!(tree.lookup_optimistic(&"a".to_string(), |v| *v), None);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn basic_insert_and_lookup() {
let tree: Tree<i32, &str> = Tree::new();
assert_eq!(tree.insert(1, "one"), None);
assert_eq!(tree.insert(2, "two"), None);
assert_eq!(tree.insert(3, "three"), None);
tree.assert_invariants();
assert_eq!(tree.lookup(&1, |v| *v), Some("one"));
assert_eq!(tree.lookup(&2, |v| *v), Some("two"));
assert_eq!(tree.lookup(&3, |v| *v), Some("three"));
assert_eq!(tree.lookup(&4, |v| *v), None);
}
#[test]
fn optimistic_lookup_basic() {
let tree: Tree<i32, u64> = Tree::new();
tree.insert(1, 10);
tree.insert(2, 20);
tree.insert(3, 30);
assert_eq!(tree.lookup_optimistic(&1, |v| *v), Some(10));
assert_eq!(tree.lookup_optimistic(&2, |v| *v), Some(20));
assert_eq!(tree.lookup_optimistic(&3, |v| *v), Some(30));
assert_eq!(tree.lookup_optimistic(&4, |v| *v), None);
assert_eq!(tree.get_optimistic(&1), Some(10));
assert_eq!(tree.get_optimistic(&99), None);
assert!(tree.contains_key(&1));
assert!(!tree.contains_key(&99));
}
#[test]
fn optimistic_lookup_across_splits() {
let tree: Tree<i64, u64> = Tree::new();
let n: i64 = 5_000;
for i in 0..n {
tree.insert(i, i as u64);
}
tree.assert_invariants();
for i in (0..n).step_by(37) {
assert_eq!(tree.get_optimistic(&i), Some(i as u64));
assert!(tree.contains_key(&i));
}
assert_eq!(tree.get_optimistic(&(n + 1)), None);
assert!(!tree.contains_key(&(n + 1)));
}
#[derive(Clone)]
struct RefcountedBlob(std::sync::Arc<Vec<u8>>);
unsafe impl OptimisticRead for RefcountedBlob {
const EPOCH_DEFERRED_DROP: bool = true;
type Slot = crate::atomic_slot::BoxedSlot<Self>;
}
#[test]
fn epoch_deferred_drop_basic() {
let tree: Tree<i32, RefcountedBlob> = Tree::new();
let blob = RefcountedBlob(std::sync::Arc::new(b"hello world".to_vec()));
assert!(!tree.insert_defer(1, blob.clone()));
assert_eq!(std::sync::Arc::strong_count(&blob.0), 2);
let got =
tree.lookup_optimistic(&1, |v| v.clone()).expect("inserted value should be present");
assert_eq!(std::sync::Arc::strong_count(&blob.0), 3);
assert_eq!(&got.0[..], b"hello world");
drop(got);
assert_eq!(std::sync::Arc::strong_count(&blob.0), 2);
let blob2 = RefcountedBlob(std::sync::Arc::new(b"replaced".to_vec()));
assert!(tree.insert_defer(1, blob2.clone()));
assert_eq!(std::sync::Arc::strong_count(&blob.0), 3);
assert_eq!(std::sync::Arc::strong_count(&blob2.0), 2);
assert!(tree.remove_defer(&1));
assert!(!tree.remove_defer(&1));
assert_eq!(std::sync::Arc::strong_count(&blob2.0), 3);
}
#[test]
fn epoch_deferred_drop_optimistic_reader_vs_defer_writer() {
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use std::thread;
let keys: i32 = if cfg!(miri) {
8
} else {
200
};
let rounds: i32 = if cfg!(miri) {
4
} else {
50
};
let reader_threads = if cfg!(miri) {
2
} else {
4
};
let tree: Arc<Tree<i32, RefcountedBlob>> = Arc::new(Tree::new());
let stop = Arc::new(AtomicBool::new(false));
for i in 0..keys {
tree.insert_defer(i, RefcountedBlob(Arc::new(vec![i as u8; 32])));
}
let mut handles = Vec::new();
for _ in 0..reader_threads {
let tree = Arc::clone(&tree);
let stop = Arc::clone(&stop);
handles.push(thread::spawn(move || {
while !stop.load(Ordering::Relaxed) {
for k in 0..keys {
if let Some(blob) = tree.lookup_optimistic(&k, |v| v.clone()) {
let s: usize = blob.0.iter().map(|&b| b as usize).sum();
std::hint::black_box(s);
}
}
}
}));
}
let writer = {
let tree = Arc::clone(&tree);
let stop = Arc::clone(&stop);
thread::spawn(move || {
for round in 0..rounds {
for k in 0..keys {
let v = RefcountedBlob(Arc::new(vec![(k + round) as u8; 32]));
tree.insert_defer(k, v);
}
}
stop.store(true, Ordering::Relaxed);
})
};
writer.join().unwrap();
for h in handles {
h.join().unwrap();
}
}
#[test]
fn k_deferred_drop_optimistic_reader_vs_defer_writer() {
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use std::thread;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
struct RcKey(Arc<Vec<u8>>);
unsafe impl OptimisticRead for RcKey {
const EPOCH_DEFERRED_DROP: bool = true;
type Slot = crate::atomic_slot::BoxedSlot<Self>;
}
let keys: u8 = if cfg!(miri) {
8
} else {
64
};
let rounds: u64 = if cfg!(miri) {
4
} else {
50
};
let reader_threads = if cfg!(miri) {
2
} else {
4
};
let mk_key = |i: u8| RcKey(Arc::new(vec![i; 8]));
let tree: Arc<Tree<RcKey, u64>> = Arc::new(Tree::new());
let stop = Arc::new(AtomicBool::new(false));
for i in 0..keys {
tree.insert_defer(mk_key(i), i as u64);
}
let mut handles = Vec::new();
for _ in 0..reader_threads {
let tree = Arc::clone(&tree);
let stop = Arc::clone(&stop);
handles.push(thread::spawn(move || {
while !stop.load(Ordering::Relaxed) {
for i in 0..keys {
let k = mk_key(i);
let _ = tree.lookup_optimistic(&k, |v| *v);
}
}
}));
}
let writer = {
let tree = Arc::clone(&tree);
let stop = Arc::clone(&stop);
thread::spawn(move || {
for round in 0..rounds {
for i in 0..keys {
let k = mk_key(i);
if round % 2 == 0 {
tree.remove_defer(&k);
} else {
tree.insert_defer(k, round * 100 + i as u64);
}
}
}
stop.store(true, Ordering::Relaxed);
})
};
writer.join().unwrap();
for h in handles {
h.join().unwrap();
}
}
#[test]
fn insert_update() {
let tree: Tree<i32, &str> = Tree::new();
assert_eq!(tree.insert(1, "one"), None);
assert_eq!(tree.insert(1, "uno"), Some("one"));
assert_eq!(tree.lookup(&1, |v| *v), Some("uno"));
tree.assert_invariants();
}
#[test]
fn remove() {
let tree: Tree<i32, &str> = Tree::new();
tree.insert(1, "one");
tree.insert(2, "two");
tree.assert_invariants();
assert_eq!(tree.remove(&1), Some("one"));
assert_eq!(tree.lookup(&1, |v| *v), None);
assert_eq!(tree.lookup(&2, |v| *v), Some("two"));
tree.assert_invariants();
}
#[test]
fn raw_iter() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..100 {
tree.insert(i, i * 10);
}
tree.assert_invariants();
let mut iter = tree.raw_iter();
iter.seek_to_first();
for i in 0..100 {
let result = iter.next();
let (k, v) = result.unwrap();
assert_eq!(*k, i);
assert_eq!(*v, i * 10);
}
assert!(iter.next().is_none());
}
#[test]
fn raw_iter_reverse() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..100 {
tree.insert(i, i * 10);
}
tree.assert_invariants();
let mut iter = tree.raw_iter();
iter.seek_to_last();
for i in (0..100).rev() {
let (k, v) = iter.prev().unwrap();
assert_eq!(*k, i);
assert_eq!(*v, i * 10);
}
assert!(iter.prev().is_none());
}
#[test]
fn len_and_is_empty() {
let tree: Tree<i32, i32> = Tree::new();
assert!(tree.is_empty());
assert_eq!(tree.len(), 0);
tree.insert(1, 10);
assert!(!tree.is_empty());
assert_eq!(tree.len(), 1);
tree.insert(2, 20);
assert_eq!(tree.len(), 2);
tree.assert_invariants();
tree.remove(&1);
assert_eq!(tree.len(), 1);
tree.assert_invariants();
}
#[test]
fn leaf_lower_bound_empty() {
let leaf: LeafNode<i32, i32, 64> = LeafNode::new();
let (pos, exact) = leaf.lower_bound(&5);
assert_eq!(pos, 0);
assert!(!exact);
}
#[test]
fn leaf_lower_bound_exact_match() {
let mut leaf: LeafNode<i32, i32, 64> = LeafNode::new();
unsafe { LeafNode::insert_at_raw(&mut leaf, 0, 10, 100) };
unsafe { LeafNode::insert_at_raw(&mut leaf, 1, 20, 200) };
unsafe { LeafNode::insert_at_raw(&mut leaf, 2, 30, 300) };
let (pos, exact) = leaf.lower_bound(&20);
assert_eq!(pos, 1);
assert!(exact);
}
#[test]
fn leaf_lower_bound_between_keys() {
let mut leaf: LeafNode<i32, i32, 64> = LeafNode::new();
unsafe { LeafNode::insert_at_raw(&mut leaf, 0, 10, 100) };
unsafe { LeafNode::insert_at_raw(&mut leaf, 1, 20, 200) };
unsafe { LeafNode::insert_at_raw(&mut leaf, 2, 30, 300) };
let (pos, exact) = leaf.lower_bound(&25);
assert_eq!(pos, 2); assert!(!exact);
}
#[test]
fn leaf_lower_bound_before_all() {
let mut leaf: LeafNode<i32, i32, 64> = LeafNode::new();
unsafe { LeafNode::insert_at_raw(&mut leaf, 0, 10, 100) };
unsafe { LeafNode::insert_at_raw(&mut leaf, 1, 20, 200) };
let (pos, exact) = leaf.lower_bound(&5);
assert_eq!(pos, 0);
assert!(!exact);
}
#[test]
fn leaf_lower_bound_after_all() {
let mut leaf: LeafNode<i32, i32, 64> = LeafNode::new();
unsafe { LeafNode::insert_at_raw(&mut leaf, 0, 10, 100) };
unsafe { LeafNode::insert_at_raw(&mut leaf, 1, 20, 200) };
let (pos, exact) = leaf.lower_bound(&25);
assert_eq!(pos, 2);
assert!(!exact);
}
#[test]
fn leaf_lower_bound_respects_lower_fence() {
let mut leaf: LeafNode<i32, i32, 64> = LeafNode::new();
leaf.lower_fence = Some(50);
unsafe { LeafNode::insert_at_raw(&mut leaf, 0, 60, 600) };
unsafe { LeafNode::insert_at_raw(&mut leaf, 1, 70, 700) };
let (pos, exact) = leaf.lower_bound(&40);
assert_eq!(pos, 0);
assert!(!exact);
}
#[test]
fn leaf_lower_bound_respects_upper_fence() {
let mut leaf: LeafNode<i32, i32, 64> = LeafNode::new();
leaf.upper_fence = Some(50);
unsafe { LeafNode::insert_at_raw(&mut leaf, 0, 30, 300) };
unsafe { LeafNode::insert_at_raw(&mut leaf, 1, 40, 400) };
let (pos, exact) = leaf.lower_bound(&60);
assert_eq!(pos, 2);
assert!(!exact);
}
#[test]
fn leaf_within_bounds() {
let mut leaf: LeafNode<i32, i32, 64> = LeafNode::new();
leaf.lower_fence = Some(10);
leaf.upper_fence = Some(50);
assert!(!leaf.within_bounds(&5)); assert!(!leaf.within_bounds(&10)); assert!(leaf.within_bounds(&30)); assert!(leaf.within_bounds(&50)); assert!(!leaf.within_bounds(&55)); }
#[test]
fn leaf_within_bounds_no_lower_fence() {
let mut leaf: LeafNode<i32, i32, 64> = LeafNode::new();
leaf.upper_fence = Some(50);
assert!(leaf.within_bounds(&5)); assert!(leaf.within_bounds(&50));
assert!(!leaf.within_bounds(&55));
}
#[test]
fn leaf_within_bounds_no_upper_fence() {
let mut leaf: LeafNode<i32, i32, 64> = LeafNode::new();
leaf.lower_fence = Some(10);
assert!(!leaf.within_bounds(&5));
assert!(leaf.within_bounds(&50)); assert!(leaf.within_bounds(&1000));
}
#[test]
fn leaf_within_bounds_no_fences() {
let leaf: LeafNode<i32, i32, 64> = LeafNode::new();
assert!(leaf.within_bounds(&0));
assert!(leaf.within_bounds(&100));
assert!(leaf.within_bounds(&i32::MAX));
}
#[test]
fn leaf_insert_at_and_remove_at() {
let mut leaf: LeafNode<i32, i32, 64> = LeafNode::new();
assert!(unsafe { LeafNode::insert_at_raw(&mut leaf, 0, 10, 100) }.is_some());
assert!(unsafe { LeafNode::insert_at_raw(&mut leaf, 1, 30, 300) }.is_some());
assert!(unsafe { LeafNode::insert_at_raw(&mut leaf, 1, 20, 200) }.is_some());
assert_eq!(leaf.len.load(), 3);
assert_eq!(leaf.key_at(0).unwrap(), 10);
assert_eq!(leaf.key_at(1).unwrap(), 20);
assert_eq!(leaf.key_at(2).unwrap(), 30);
let eg = epoch::pin();
let (k, v) = unsafe { LeafNode::remove_at_raw(&mut leaf, 1, &eg) };
assert_eq!(k, 20);
assert_eq!(v, 200);
assert_eq!(leaf.len.load(), 2);
}
#[test]
fn leaf_split_sets_fences_correctly() {
let mut left: LeafNode<i32, i32, 64> = LeafNode::new();
for i in 0..10 {
unsafe { LeafNode::insert_at_raw(&mut left, i as u16, i * 10, i * 100) };
}
let mut right: LeafNode<i32, i32, 64> = LeafNode::new();
left.split(&mut right, 5);
assert_eq!(left.len.load(), 6); assert_eq!(right.len.load(), 4);
assert!(left.lower_fence.is_none()); assert_eq!(left.upper_fence, Some(50));
assert_eq!(right.lower_fence, Some(50)); assert!(right.upper_fence.is_none());
assert_eq!(left.sample_key, Some(0));
assert_eq!(right.sample_key, Some(60));
}
#[test]
fn leaf_merge_combines_entries() {
let mut left: LeafNode<i32, i32, 64> = LeafNode::new();
unsafe { LeafNode::insert_at_raw(&mut left, 0, 10, 100) };
unsafe { LeafNode::insert_at_raw(&mut left, 1, 20, 200) };
left.upper_fence = Some(25);
let mut right: LeafNode<i32, i32, 64> = LeafNode::new();
right.lower_fence = Some(25);
right.upper_fence = Some(50);
unsafe { LeafNode::insert_at_raw(&mut right, 0, 30, 300) };
unsafe { LeafNode::insert_at_raw(&mut right, 1, 40, 400) };
right.sample_key = Some(30);
let result = left.merge(&mut right);
assert!(result);
assert_eq!(left.len.load(), 4);
assert_eq!(left.key_at(0).unwrap(), 10);
assert_eq!(left.key_at(1).unwrap(), 20);
assert_eq!(left.key_at(2).unwrap(), 30);
assert_eq!(left.key_at(3).unwrap(), 40);
assert_eq!(left.upper_fence, Some(50));
assert_eq!(left.sample_key, Some(30));
assert_eq!(right.len.load(), 0);
}
#[test]
fn leaf_merge_fails_when_too_full() {
let mut left: LeafNode<i32, i32, 4> = LeafNode::new();
unsafe { LeafNode::insert_at_raw(&mut left, 0, 10, 100) };
unsafe { LeafNode::insert_at_raw(&mut left, 1, 20, 200) };
unsafe { LeafNode::insert_at_raw(&mut left, 2, 30, 300) };
let mut right: LeafNode<i32, i32, 4> = LeafNode::new();
unsafe { LeafNode::insert_at_raw(&mut right, 0, 40, 400) };
unsafe { LeafNode::insert_at_raw(&mut right, 1, 50, 500) };
let result = left.merge(&mut right);
assert!(!result);
assert_eq!(left.len.load(), 3);
assert_eq!(right.len.load(), 2);
}
#[test]
fn leaf_has_space() {
let mut leaf: LeafNode<i32, i32, 3> = LeafNode::new();
assert!(leaf.has_space());
unsafe { LeafNode::insert_at_raw(&mut leaf, 0, 1, 1) };
assert!(leaf.has_space());
unsafe { LeafNode::insert_at_raw(&mut leaf, 1, 2, 2) };
assert!(leaf.has_space());
unsafe { LeafNode::insert_at_raw(&mut leaf, 2, 3, 3) };
assert!(!leaf.has_space());
}
#[test]
fn leaf_is_underfull() {
let mut leaf: LeafNode<i32, i32, 10> = LeafNode::new();
assert!(leaf.is_underfull());
for i in 0..3 {
unsafe { LeafNode::insert_at_raw(&mut leaf, i as u16, i, i) };
}
assert!(leaf.is_underfull());
unsafe { LeafNode::insert_at_raw(&mut leaf, 3, 3, 3) };
assert!(!leaf.is_underfull());
}
#[test]
fn internal_lower_bound_empty() {
let internal: InternalNode<i32, i32, 64, 64> = InternalNode::new();
let (pos, exact) = internal.lower_bound(&5);
assert_eq!(pos, 0);
assert!(!exact);
}
#[test]
fn internal_lower_bound_finds_correct_child() {
let mut internal: InternalNode<i32, i32, 64, 64> = InternalNode::new();
internal.keys.push(10);
internal.keys.push(20);
internal.keys.push(30);
internal.len.store(3);
let (pos, exact) = internal.lower_bound(&5);
assert_eq!(pos, 0); assert!(!exact);
let (pos, exact) = internal.lower_bound(&10);
assert_eq!(pos, 0); assert!(exact);
let (pos, exact) = internal.lower_bound(&15);
assert_eq!(pos, 1); assert!(!exact);
let (pos, exact) = internal.lower_bound(&25);
assert_eq!(pos, 2); assert!(!exact);
let (pos, exact) = internal.lower_bound(&35);
assert_eq!(pos, 3); assert!(!exact);
}
#[test]
fn internal_has_space() {
let internal: InternalNode<i32, i32, 3, 64> = InternalNode::new();
assert!(internal.has_space());
internal.len.store(2);
assert!(internal.has_space());
internal.len.store(3);
assert!(!internal.has_space());
}
#[test]
fn internal_is_underfull() {
let internal: InternalNode<i32, i32, 10, 64> = InternalNode::new();
internal.len.store(3);
assert!(internal.is_underfull());
internal.len.store(4);
assert!(!internal.is_underfull());
}
#[test]
fn new_tree_has_height_one() {
let tree: Tree<i32, i32> = Tree::new();
assert_eq!(tree.height(), 1);
}
#[test]
fn inserts_cause_splits_and_height_increase() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..200 {
tree.insert(i, i);
}
tree.assert_invariants();
assert!(tree.height() > 1);
for i in 0..200 {
assert_eq!(tree.lookup(&i, |v| *v), Some(i));
}
}
#[test]
fn many_inserts_cause_multiple_levels() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..1000 {
tree.insert(i, i);
}
tree.assert_invariants();
assert!(tree.height() >= 2);
assert_eq!(tree.len(), 1000);
assert_eq!(tree.lookup(&0, |v| *v), Some(0));
assert_eq!(tree.lookup(&500, |v| *v), Some(500));
assert_eq!(tree.lookup(&999, |v| *v), Some(999));
}
#[test]
fn reverse_insertion_order() {
let tree: Tree<i32, i32> = Tree::new();
for i in (0..200).rev() {
tree.insert(i, i);
}
tree.assert_invariants();
let mut iter = tree.raw_iter();
iter.seek_to_first();
for i in 0..200 {
let (k, v) = iter.next().unwrap();
assert_eq!(*k, i);
assert_eq!(*v, i);
}
}
#[test]
fn random_insertion_order() {
use rand::prelude::*;
let tree: Tree<i32, i32> = Tree::new();
let mut keys: Vec<i32> = (0..200).collect();
let mut rng = rand::rng();
keys.shuffle(&mut rng);
for k in keys {
tree.insert(k, k * 10);
}
tree.assert_invariants();
for i in 0..200 {
assert_eq!(tree.lookup(&i, |v| *v), Some(i * 10));
}
let mut iter = tree.raw_iter();
iter.seek_to_first();
let mut prev = -1;
while let Some((k, _)) = iter.next() {
assert!(*k > prev);
prev = *k;
}
}
#[test]
fn delete_all_entries() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..100 {
tree.insert(i, i);
}
tree.assert_invariants();
for i in 0..100 {
assert_eq!(tree.remove(&i), Some(i));
}
tree.assert_invariants();
assert!(tree.is_empty());
}
#[test]
fn delete_in_reverse_order() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..100 {
tree.insert(i, i);
}
tree.assert_invariants();
for i in (0..100).rev() {
assert_eq!(tree.remove(&i), Some(i));
}
tree.assert_invariants();
assert!(tree.is_empty());
}
#[test]
fn delete_random_order() {
use rand::prelude::*;
let tree: Tree<i32, i32> = Tree::new();
for i in 0..100 {
tree.insert(i, i);
}
tree.assert_invariants();
let mut keys: Vec<i32> = (0..100).collect();
let mut rng = rand::rng();
keys.shuffle(&mut rng);
for k in keys {
assert_eq!(tree.remove(&k), Some(k));
}
tree.assert_invariants();
assert!(tree.is_empty());
}
#[test]
fn delete_nonexistent_returns_none() {
let tree: Tree<i32, i32> = Tree::new();
tree.insert(1, 10);
assert_eq!(tree.remove(&999), None);
assert_eq!(tree.len(), 1);
tree.assert_invariants();
}
#[test]
fn remove_entry_returns_key_and_value() {
let tree: Tree<i32, i32> = Tree::new();
tree.insert(42, 420);
let result = tree.remove_entry(&42);
assert_eq!(result, Some((42, 420)));
tree.assert_invariants();
}
#[test]
fn interleaved_insert_and_delete() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..50 {
tree.insert(i, i);
}
tree.assert_invariants();
for i in 0..25 {
tree.remove(&i);
}
tree.assert_invariants();
for i in 50..100 {
tree.insert(i, i);
}
for i in 50..75 {
tree.remove(&i);
}
tree.assert_invariants();
assert_eq!(tree.len(), 50);
for i in 25..50 {
assert_eq!(tree.lookup(&i, |v| *v), Some(i));
}
for i in 75..100 {
assert_eq!(tree.lookup(&i, |v| *v), Some(i));
}
}
#[test]
fn node_is_leaf() {
let leaf_node: Node<i32, i32, 64, 64> = Node::Leaf(LeafNode::new());
let internal_node: Node<i32, i32, 64, 64> = Node::Internal(InternalNode::new());
assert!(leaf_node.is_leaf());
assert!(!internal_node.is_leaf());
}
#[test]
fn node_can_merge_with_same_type() {
let leaf1: Node<i32, i32, 64, 64> = Node::Leaf(LeafNode::new());
let leaf2: Node<i32, i32, 64, 64> = Node::Leaf(LeafNode::new());
assert!(leaf1.can_merge_with(&leaf2));
}
#[test]
fn node_cannot_merge_with_different_type() {
let leaf: Node<i32, i32, 64, 64> = Node::Leaf(LeafNode::new());
let internal: Node<i32, i32, 64, 64> = Node::Internal(InternalNode::new());
assert!(!leaf.can_merge_with(&internal));
assert!(!internal.can_merge_with(&leaf));
}
#[test]
fn empty_tree_lookup() {
let tree: Tree<i32, i32> = Tree::new();
tree.assert_invariants();
assert_eq!(tree.lookup(&1, |v| *v), None);
}
#[test]
fn empty_tree_remove() {
let tree: Tree<i32, i32> = Tree::new();
tree.assert_invariants();
assert_eq!(tree.remove(&1), None);
tree.assert_invariants();
}
#[test]
fn duplicate_inserts_update_value() {
let tree: Tree<i32, i32> = Tree::new();
tree.insert(1, 10);
tree.insert(1, 20);
tree.insert(1, 30);
tree.assert_invariants();
assert_eq!(tree.lookup(&1, |v| *v), Some(30));
assert_eq!(tree.len(), 1);
}
#[test]
fn string_keys() {
let tree: Tree<String, i32> = Tree::new();
tree.insert("apple".to_string(), 1);
tree.insert("banana".to_string(), 2);
tree.insert("cherry".to_string(), 3);
tree.assert_invariants();
assert_eq!(tree.lookup(&"banana".to_string(), |v| *v), Some(2));
}
#[test]
fn lookup_with_borrowed_key() {
let tree: Tree<String, i32> = Tree::new();
tree.insert("hello".to_string(), 42);
tree.assert_invariants();
assert_eq!(tree.lookup("hello", |v| *v), Some(42));
}
#[test]
fn empty_string_key() {
let tree: Tree<String, i32> = Tree::new();
tree.insert("".to_string(), 42);
tree.assert_invariants();
assert_eq!(tree.lookup(&"".to_string(), |v| *v), Some(42));
}
#[test]
fn large_values() {
let tree: Tree<i32, Vec<u8>> = Tree::new();
let large_value = vec![0u8; 10000];
tree.insert(1, large_value.clone());
tree.assert_invariants();
let result = tree.lookup(&1, |v| v.len());
assert_eq!(result, Some(10000));
}
#[test]
fn tree_default_creates_empty_tree() {
let tree: Tree<i32, i32> = Tree::default();
tree.assert_invariants();
assert!(tree.is_empty());
assert_eq!(tree.height(), 1);
}
#[test]
fn node_keys_returns_keys() {
let mut leaf: LeafNode<i32, i32, 64> = LeafNode::new();
unsafe { LeafNode::insert_at_raw(&mut leaf, 0, 10, 100) };
unsafe { LeafNode::insert_at_raw(&mut leaf, 1, 20, 200) };
unsafe { LeafNode::insert_at_raw(&mut leaf, 2, 30, 300) };
let node: Node<i32, i32, 64, 64> = Node::Leaf(leaf);
let keys = node.keys();
assert_eq!(keys.as_slice(), &[10, 20, 30]);
}
#[test]
fn leaf_sample_key_initially_none() {
let leaf: LeafNode<i32, i32, 64> = LeafNode::new();
let node: Node<i32, i32, 64, 64> = Node::Leaf(leaf);
assert!(node.sample_key().is_none());
}
#[test]
fn internal_sample_key_initially_none() {
let internal: InternalNode<i32, i32, 64, 64> = InternalNode::new();
let node: Node<i32, i32, 64, 64> = Node::Internal(internal);
assert!(node.sample_key().is_none());
}
#[test]
fn contains_key_returns_true_for_existing() {
let tree: Tree<i32, &str> = Tree::new();
tree.insert(1, "one");
tree.insert(2, "two");
tree.insert(3, "three");
assert!(tree.contains_key(&1));
assert!(tree.contains_key(&2));
assert!(tree.contains_key(&3));
}
#[test]
fn contains_key_returns_false_for_missing() {
let tree: Tree<i32, &str> = Tree::new();
tree.insert(1, "one");
assert!(!tree.contains_key(&0));
assert!(!tree.contains_key(&2));
assert!(!tree.contains_key(&100));
}
#[test]
fn contains_key_empty_tree() {
let tree: Tree<i32, &str> = Tree::new();
assert!(!tree.contains_key(&1));
}
#[test]
fn get_returns_cloned_value() {
let tree: Tree<i32, String> = Tree::new();
tree.insert(1, "one".to_string());
tree.insert(2, "two".to_string());
assert_eq!(tree.get(&1), Some("one".to_string()));
assert_eq!(tree.get(&2), Some("two".to_string()));
assert_eq!(tree.get(&3), None);
}
#[test]
fn get_empty_tree() {
let tree: Tree<i32, String> = Tree::new();
assert_eq!(tree.get(&1), None);
}
#[test]
fn first_returns_minimum() {
let tree: Tree<i32, &str> = Tree::new();
tree.insert(3, "three");
tree.insert(1, "one");
tree.insert(2, "two");
let first = tree.first(|k, v| (*k, *v));
assert_eq!(first, Some((1, "one")));
}
#[test]
fn first_empty_tree() {
let tree: Tree<i32, &str> = Tree::new();
let first = tree.first(|k, v| (*k, *v));
assert_eq!(first, None);
}
#[test]
fn first_single_entry() {
let tree: Tree<i32, &str> = Tree::new();
tree.insert(42, "answer");
let first = tree.first(|k, v| (*k, *v));
assert_eq!(first, Some((42, "answer")));
}
#[test]
fn last_returns_maximum() {
let tree: Tree<i32, &str> = Tree::new();
tree.insert(1, "one");
tree.insert(3, "three");
tree.insert(2, "two");
let last = tree.last(|k, v| (*k, *v));
assert_eq!(last, Some((3, "three")));
}
#[test]
fn last_empty_tree() {
let tree: Tree<i32, &str> = Tree::new();
let last = tree.last(|k, v| (*k, *v));
assert_eq!(last, None);
}
#[test]
fn last_single_entry() {
let tree: Tree<i32, &str> = Tree::new();
tree.insert(42, "answer");
let last = tree.last(|k, v| (*k, *v));
assert_eq!(last, Some((42, "answer")));
}
#[test]
fn pop_first_returns_minimum() {
let tree: Tree<i32, &str> = Tree::new();
tree.insert(3, "three");
tree.insert(1, "one");
tree.insert(2, "two");
assert_eq!(tree.pop_first(), Some((1, "one")));
assert_eq!(tree.len(), 2);
assert_eq!(tree.pop_first(), Some((2, "two")));
assert_eq!(tree.len(), 1);
assert_eq!(tree.pop_first(), Some((3, "three")));
assert!(tree.is_empty());
}
#[test]
fn pop_first_empty_tree() {
let tree: Tree<i32, &str> = Tree::new();
assert_eq!(tree.pop_first(), None);
}
#[test]
fn pop_last_returns_maximum() {
let tree: Tree<i32, &str> = Tree::new();
tree.insert(1, "one");
tree.insert(3, "three");
tree.insert(2, "two");
assert_eq!(tree.pop_last(), Some((3, "three")));
assert_eq!(tree.len(), 2);
assert_eq!(tree.pop_last(), Some((2, "two")));
assert_eq!(tree.len(), 1);
assert_eq!(tree.pop_last(), Some((1, "one")));
assert!(tree.is_empty());
}
#[test]
fn pop_last_empty_tree() {
let tree: Tree<i32, &str> = Tree::new();
assert_eq!(tree.pop_last(), None);
}
#[test]
fn clear_empties_tree() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..100 {
tree.insert(i, i * 10);
}
assert_eq!(tree.len(), 100);
assert!(tree.height() > 1);
tree.clear();
assert!(tree.is_empty());
assert_eq!(tree.height(), 1);
assert_eq!(tree.len(), 0);
}
#[test]
fn clear_empty_tree() {
let tree: Tree<i32, i32> = Tree::new();
tree.clear();
assert!(tree.is_empty());
assert_eq!(tree.height(), 1);
}
#[test]
fn clear_then_insert() {
let tree: Tree<i32, &str> = Tree::new();
tree.insert(1, "one");
tree.insert(2, "two");
tree.clear();
assert!(tree.is_empty());
tree.insert(3, "three");
tree.insert(4, "four");
assert_eq!(tree.len(), 2);
assert_eq!(tree.get(&3), Some("three"));
assert_eq!(tree.get(&4), Some("four"));
assert_eq!(tree.get(&1), None); }
#[test]
fn contains_key_with_borrowed_key() {
let tree: Tree<String, i32> = Tree::new();
tree.insert("hello".to_string(), 42);
tree.insert("world".to_string(), 99);
assert!(tree.contains_key("hello"));
assert!(tree.contains_key("world"));
assert!(!tree.contains_key("missing"));
}
#[test]
fn get_with_borrowed_key() {
let tree: Tree<String, i32> = Tree::new();
tree.insert("hello".to_string(), 42);
assert_eq!(tree.get("hello"), Some(42));
assert_eq!(tree.get("missing"), None);
}
#[test]
fn first_multilevel_tree() {
let tree: Tree<i32, i32> = Tree::new();
for i in (0..200).rev() {
tree.insert(i, i * 10);
}
tree.assert_invariants();
assert!(tree.height() > 1);
let first = tree.first(|k, v| (*k, *v));
assert_eq!(first, Some((0, 0)));
}
#[test]
fn last_multilevel_tree() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..200 {
tree.insert(i, i * 10);
}
tree.assert_invariants();
assert!(tree.height() > 1);
let last = tree.last(|k, v| (*k, *v));
assert_eq!(last, Some((199, 1990)));
}
#[test]
fn clear_maintains_invariants() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..200 {
tree.insert(i, i);
}
tree.assert_invariants();
tree.clear();
tree.assert_invariants();
for i in 0..50 {
tree.insert(i, i * 2);
}
tree.assert_invariants();
}
#[test]
fn range_full() {
use std::ops::Bound::Unbounded;
let tree: Tree<i32, i32> = Tree::new();
for i in 0..10 {
tree.insert(i, i * 10);
}
let mut range = tree.range(Unbounded, Unbounded);
for i in 0..10 {
let (k, v) = range.next().unwrap();
assert_eq!(*k, i);
assert_eq!(*v, i * 10);
}
assert!(range.next().is_none());
}
#[test]
fn range_included_bounds() {
use std::ops::Bound::Included;
let tree: Tree<i32, i32> = Tree::new();
for i in 0..10 {
tree.insert(i, i * 10);
}
let mut range = tree.range(Included(&3), Included(&6));
assert_eq!(range.next(), Some((&3, &30)));
assert_eq!(range.next(), Some((&4, &40)));
assert_eq!(range.next(), Some((&5, &50)));
assert_eq!(range.next(), Some((&6, &60)));
assert_eq!(range.next(), None);
}
#[test]
fn range_excluded_bounds() {
use std::ops::Bound::Excluded;
let tree: Tree<i32, i32> = Tree::new();
for i in 0..10 {
tree.insert(i, i * 10);
}
let mut range = tree.range(Excluded(&3), Excluded(&6));
assert_eq!(range.next(), Some((&4, &40)));
assert_eq!(range.next(), Some((&5, &50)));
assert_eq!(range.next(), None);
}
#[test]
fn range_mixed_bounds() {
use std::ops::Bound::{Excluded, Included, Unbounded};
let tree: Tree<i32, i32> = Tree::new();
for i in 0..10 {
tree.insert(i, i * 10);
}
let mut range = tree.range(Unbounded, Excluded(&5));
for i in 0..5 {
let (k, v) = range.next().unwrap();
assert_eq!(*k, i);
assert_eq!(*v, i * 10);
}
assert!(range.next().is_none());
let mut range = tree.range(Included(&5), Unbounded);
for i in 5..10 {
let (k, v) = range.next().unwrap();
assert_eq!(*k, i);
assert_eq!(*v, i * 10);
}
assert!(range.next().is_none());
}
#[test]
fn range_empty_tree() {
use std::ops::Bound::Unbounded;
let tree: Tree<i32, i32> = Tree::new();
let mut range = tree.range(Unbounded, Unbounded);
assert!(range.next().is_none());
}
#[test]
fn range_nonexistent_bounds() {
use std::ops::Bound::Included;
let tree: Tree<i32, i32> = Tree::new();
tree.insert(0, 0);
tree.insert(2, 20);
tree.insert(4, 40);
tree.insert(6, 60);
let mut range = tree.range(Included(&1), Included(&5));
assert_eq!(range.next(), Some((&2, &20)));
assert_eq!(range.next(), Some((&4, &40)));
assert_eq!(range.next(), None);
}
#[test]
fn range_rev_full() {
use std::ops::Bound::Unbounded;
let tree: Tree<i32, i32> = Tree::new();
for i in 0..10 {
tree.insert(i, i * 10);
}
let mut range = tree.range_rev(Unbounded, Unbounded);
for i in (0..10).rev() {
let (k, v) = range.next().unwrap();
assert_eq!(*k, i);
assert_eq!(*v, i * 10);
}
assert!(range.next().is_none());
}
#[test]
fn range_rev_included_bounds() {
use std::ops::Bound::Included;
let tree: Tree<i32, i32> = Tree::new();
for i in 0..10 {
tree.insert(i, i * 10);
}
let mut range = tree.range_rev(Included(&3), Included(&6));
assert_eq!(range.next(), Some((&6, &60)));
assert_eq!(range.next(), Some((&5, &50)));
assert_eq!(range.next(), Some((&4, &40)));
assert_eq!(range.next(), Some((&3, &30)));
assert_eq!(range.next(), None);
}
#[test]
fn range_rev_excluded_bounds() {
use std::ops::Bound::Excluded;
let tree: Tree<i32, i32> = Tree::new();
for i in 0..10 {
tree.insert(i, i * 10);
}
let mut range = tree.range_rev(Excluded(&3), Excluded(&6));
assert_eq!(range.next(), Some((&5, &50)));
assert_eq!(range.next(), Some((&4, &40)));
assert_eq!(range.next(), None);
}
#[test]
fn range_rev_mixed_bounds() {
use std::ops::Bound::{Excluded, Included, Unbounded};
let tree: Tree<i32, i32> = Tree::new();
for i in 0..10 {
tree.insert(i, i * 10);
}
let mut range = tree.range_rev(Excluded(&5), Unbounded);
for i in (6..10).rev() {
let (k, v) = range.next().unwrap();
assert_eq!(*k, i);
assert_eq!(*v, i * 10);
}
assert!(range.next().is_none());
let mut range = tree.range_rev(Unbounded, Included(&5));
for i in (0..=5).rev() {
let (k, v) = range.next().unwrap();
assert_eq!(*k, i);
assert_eq!(*v, i * 10);
}
assert!(range.next().is_none());
}
#[test]
fn range_rev_empty_tree() {
use std::ops::Bound::Unbounded;
let tree: Tree<i32, i32> = Tree::new();
let mut range = tree.range_rev(Unbounded, Unbounded);
assert!(range.next().is_none());
}
#[test]
fn range_rev_nonexistent_bounds() {
use std::ops::Bound::Included;
let tree: Tree<i32, i32> = Tree::new();
tree.insert(0, 0);
tree.insert(2, 20);
tree.insert(4, 40);
tree.insert(6, 60);
let mut range = tree.range_rev(Included(&1), Included(&5));
assert_eq!(range.next(), Some((&4, &40)));
assert_eq!(range.next(), Some((&2, &20)));
assert_eq!(range.next(), None);
}
#[test]
fn range_rev_single_element() {
use std::ops::Bound::Included;
let tree: Tree<i32, i32> = Tree::new();
tree.insert(5, 50);
let mut range = tree.range_rev(Included(&5), Included(&5));
assert_eq!(range.next(), Some((&5, &50)));
assert_eq!(range.next(), None);
}
#[test]
fn range_rev_peek() {
use std::ops::Bound::{Included, Unbounded};
let tree: Tree<i32, i32> = Tree::new();
for i in 0..10 {
tree.insert(i, i * 10);
}
let mut range = tree.range_rev(Included(&3), Unbounded);
assert_eq!(range.peek(), Some((&9, &90)));
assert_eq!(range.peek(), Some((&9, &90)));
assert_eq!(range.next(), Some((&9, &90)));
assert_eq!(range.peek(), Some((&8, &80)));
}
#[test]
fn range_rev_peek_respects_lower_bound() {
use std::ops::Bound::Included;
let tree: Tree<i32, i32> = Tree::new();
for i in 0..10 {
tree.insert(i, i * 10);
}
let mut range = tree.range_rev(Included(&7), Included(&9));
assert_eq!(range.peek(), Some((&9, &90)));
assert_eq!(range.next(), Some((&9, &90)));
assert_eq!(range.peek(), Some((&8, &80)));
assert_eq!(range.next(), Some((&8, &80)));
assert_eq!(range.peek(), Some((&7, &70)));
assert_eq!(range.next(), Some((&7, &70)));
assert!(range.peek().is_none());
assert!(range.next().is_none());
}
#[test]
fn range_rev_large_tree() {
use std::ops::Bound::Unbounded;
let tree: Tree<i32, i32> = Tree::new();
for i in 0..200 {
tree.insert(i, i);
}
assert!(tree.height() > 1, "Tree should have multiple levels");
let mut range = tree.range_rev(Unbounded, Unbounded);
for i in (0..200).rev() {
let (k, v) = range.next().unwrap();
assert_eq!(*k, i);
assert_eq!(*v, i);
}
assert!(range.next().is_none());
}
#[test]
fn keys_basic() {
let tree: Tree<i32, &str> = Tree::new();
tree.insert(3, "three");
tree.insert(1, "one");
tree.insert(2, "two");
let mut keys = tree.keys();
assert_eq!(keys.next(), Some(&1));
assert_eq!(keys.next(), Some(&2));
assert_eq!(keys.next(), Some(&3));
assert_eq!(keys.next(), None);
}
#[test]
fn keys_empty_tree() {
let tree: Tree<i32, i32> = Tree::new();
let mut keys = tree.keys();
assert!(keys.next().is_none());
}
#[test]
fn keys_large_tree() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..200 {
tree.insert(i, i);
}
let mut keys = tree.keys();
for i in 0..200 {
assert_eq!(keys.next(), Some(&i));
}
assert!(keys.next().is_none());
}
#[test]
fn values_basic() {
let tree: Tree<i32, &str> = Tree::new();
tree.insert(3, "three");
tree.insert(1, "one");
tree.insert(2, "two");
let mut values = tree.values();
assert_eq!(values.next(), Some(&"one"));
assert_eq!(values.next(), Some(&"two"));
assert_eq!(values.next(), Some(&"three"));
assert_eq!(values.next(), None);
}
#[test]
fn values_empty_tree() {
let tree: Tree<i32, i32> = Tree::new();
let mut values = tree.values();
assert!(values.next().is_none());
}
#[test]
fn values_large_tree() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..200 {
tree.insert(i, i * 10);
}
let mut values = tree.values();
for i in 0..200 {
assert_eq!(values.next(), Some(&(i * 10)));
}
assert!(values.next().is_none());
}
#[test]
fn get_or_insert_new_key() {
let tree: Tree<i32, String> = Tree::new();
let value = tree.get_or_insert(1, "default".to_string());
assert_eq!(value, "default");
assert_eq!(tree.lookup(&1, |v| v.clone()), Some("default".to_string()));
assert_eq!(tree.len(), 1);
tree.assert_invariants();
}
#[test]
fn get_or_insert_existing_key() {
let tree: Tree<i32, String> = Tree::new();
tree.insert(1, "existing".to_string());
let value = tree.get_or_insert(1, "new_default".to_string());
assert_eq!(value, "existing");
assert_eq!(tree.lookup(&1, |v| v.clone()), Some("existing".to_string()));
assert_eq!(tree.len(), 1);
tree.assert_invariants();
}
#[test]
fn get_or_insert_with_lazy_evaluation() {
let tree: Tree<i32, String> = Tree::new();
tree.insert(1, "existing".to_string());
let value = tree.get_or_insert_with(1, || {
panic!("closure should not be called for existing key");
});
assert_eq!(value, "existing");
let value = tree.get_or_insert_with(2, || "computed".to_string());
assert_eq!(value, "computed");
assert_eq!(tree.len(), 2);
tree.assert_invariants();
}
#[test]
fn get_or_insert_triggers_split() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..64 {
tree.get_or_insert(i, i * 10);
}
tree.assert_invariants();
assert_eq!(tree.len(), 64);
let value = tree.get_or_insert(64, 640);
assert_eq!(value, 640);
tree.assert_invariants();
assert_eq!(tree.len(), 65);
assert!(tree.height() >= 2, "Tree should have split");
for i in 0..=64 {
assert_eq!(tree.lookup(&i, |v| *v), Some(i * 10));
}
}
#[test]
fn get_or_insert_multiple_operations() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..100 {
let value = tree.get_or_insert(i % 50, i);
if i < 50 {
assert_eq!(value, i);
} else {
assert_eq!(value, i - 50);
}
}
tree.assert_invariants();
assert_eq!(tree.len(), 50);
}
}