use core::mem;
use super::super::interleaving::Interleaving;
use super::super::node::Node;
use super::super::node::inline_keys::SearchKey;
use super::super::node::internal::Internal;
use super::super::node::latch::Latched;
use super::super::node::leaf::Leaf;
use super::super::node_stack::LastEdge;
use super::super::prefix::PrefixedKey;
use super::LatchedTree;
use super::descent::{Exclusive, HeldLeaf, TreePath};
use super::held::HeldNodes;
use crate::allocator::Allocator;
use crate::inline_key::InlineKeyStrategy;
pub(crate) trait InsertPolicy<K, V> {
type Output;
fn occupied(self, key: K, value: V, stored: &K, stored_value: &mut V) -> Self::Output;
fn vacant(self, key: &K, value: &V) -> Self::Output;
}
pub(crate) struct Replace;
impl<K, V> InsertPolicy<K, V> for Replace {
type Output = Option<V>;
#[inline(always)]
fn occupied(self, key: K, value: V, _stored: &K, stored_value: &mut V) -> Option<V> {
drop(key);
Some(mem::replace(stored_value, value))
}
#[inline(always)]
fn vacant(self, _key: &K, _value: &V) -> Option<V> {
None
}
}
pub(crate) struct ReadOrInsert<F>(pub(crate) F);
impl<K, V, R, F: FnOnce(&K, &V) -> R> InsertPolicy<K, V> for ReadOrInsert<F> {
type Output = R;
#[inline(always)]
fn occupied(self, key: K, value: V, stored: &K, stored_value: &mut V) -> R {
drop((key, value));
(self.0)(stored, stored_value)
}
#[inline(always)]
fn vacant(self, key: &K, value: &V) -> R {
(self.0)(key, value)
}
}
impl<K, V, S: InlineKeyStrategy<K>> LatchedTree<K, V, S> {
#[inline]
pub(crate) fn insert<P: InsertPolicy<K, V>>(
&self,
key: K,
value: V,
policy: P,
alloc: &impl Allocator,
) -> P::Output
where
K: Ord,
{
if self.root_page().is_none() {
self.start_tree(&self.pages(alloc));
}
let (mut key, value, policy) = match self.append(key, value, policy) {
Ok(output) => return output,
Err(entry) => entry,
};
loop {
let Ok((held, at_separator)) =
self.descend::<K, Exclusive, ()>(&SearchKey::new(&key), &mut ())
else {
key = self.shrink_shared_prefix_for(key, alloc);
continue;
};
return match self.insert_into(&held, at_separator, key, value, policy, alloc) {
Ok(output) => output,
Err((key, value, policy, _)) => {
drop(held);
self.insert_splitting(key, value, policy, alloc)
}
};
}
}
#[inline(always)]
pub(super) fn insert_into<P: InsertPolicy<K, V>>(
&self,
held: &HeldLeaf<K, V, S, Exclusive>,
at_separator: bool,
key: K,
value: V,
policy: P,
alloc: &impl Allocator,
) -> Result<P::Output, (K, V, P, usize)>
where
K: Ord,
{
let leaf = held.leaf();
if at_separator {
return Ok(policy.occupied(key, value, leaf.head_key(), leaf.head_value_mut()));
}
match leaf.search_always_inlined(&SearchKey::new(&key)) {
Ok(index) => Ok(policy.occupied(key, value, leaf.key(index), leaf.value_mut(index))),
Err(edge) if leaf.len() < Leaf::<K, V, Latched<S>>::capacity() => {
let key = self.prefixed(key, leaf, alloc);
let output = policy.vacant(key.key(), &value);
leaf.insert_fit(edge, key.window_at(leaf.prefix_len()), value);
Ok(output)
}
Err(edge) => Err((key, value, policy, edge)),
}
}
#[inline(always)]
fn prefixed(
&self,
key: K,
leaf: Leaf<K, V, Latched<S>>,
alloc: &impl Allocator,
) -> PrefixedKey<K> {
if self.is_root(leaf) {
self.change_held(|tree| tree.shrink_shared_prefix_for(key, alloc))
} else {
PrefixedKey::checked_by_descent(key)
}
}
#[inline(never)]
pub(super) fn insert_splitting<P: InsertPolicy<K, V>>(
&self,
mut key: K,
mut value: V,
mut policy: P,
alloc: &impl Allocator,
) -> P::Output
where
K: Ord,
{
let pages = self.pages(alloc);
loop {
let mut path = TreePath::new();
let Ok((held, at_separator)) =
self.descend::<K, Exclusive, _>(&SearchKey::new(&key), &mut path)
else {
key = self.shrink_shared_prefix_for(key, alloc);
continue;
};
let edge;
(key, value, policy, edge) =
match self.insert_into(&held, at_separator, key, value, policy, alloc) {
Ok(output) => return output,
Err(full) => full,
};
match self.split(&path, &held, edge, key, value, policy, &pages) {
Ok(output) => return output,
Err(entry) => (key, value, policy) = entry,
}
Interleaving::wait(1);
}
}
#[expect(
clippy::too_many_arguments,
reason = "a refused split gives the entry and its policy back"
)]
fn split<P: InsertPolicy<K, V>>(
&self,
path: &TreePath<K, V, S>,
held: &HeldLeaf<K, V, S, Exclusive>,
edge: usize,
key: K,
value: V,
policy: P,
pages: &impl Allocator,
) -> Result<P::Output, (K, V, P)>
where
K: Ord,
{
let room = (0..path.depth())
.rev()
.find(|&level| path.level(level).routed.len < Internal::<K, V, Latched<S>>::capacity());
let top = path.fences_top(room.unwrap_or(0));
let mut held_nodes = HeldNodes::new();
if !held_nodes.take_path(path, top) {
return Err((key, value, policy));
}
let leaf = held.leaf();
let was_last_leaf = self.is_rightmost_leaf(leaf);
let key = self.prefixed(key, leaf, pages);
let output = policy.vacant(key.key(), &value);
self.change_held(|tree| {
let mut uncounted = 0;
path.node_stack_to_leaf(tree, top, leaf, edge)
.insert_prefixed(key, value, pages, &mut uncounted);
});
if was_last_leaf {
let took_separator = match room {
Some(level) => Node::Internal(path.level(level).node),
None => self.root_page().expect("a tree that split").node(),
};
self.point_appends_to(took_separator.border_leaf::<LastEdge>());
}
drop(held_nodes);
Ok(output)
}
}