#![forbid(unsafe_code)]
use core::mem;
use super::node::inline_keys::Separator;
use super::node::internal::Internal;
use super::node::leaf::Leaf;
use super::node::page::NodePtr;
use super::node::siblings::Siblings;
use super::node::{Child, Insertion, Node};
use super::node_stack::{FirstEdge, LastEdge, NodeEnd, NodeStackMut};
use super::root::Tree;
use crate::allocator::Allocator;
use crate::inline_key::InlineKeyStrategy;
struct SeparatorPlace {
child_edge: Option<usize>,
index: usize,
hung: bool,
}
impl<K, V, S: InlineKeyStrategy<K>> Tree<K, V, S> {
pub(in crate::tree) fn join(
&mut self,
key: K,
value: V,
right: &mut Self,
alloc: &impl Allocator,
) {
let separator = self.shrink_shared_prefixes_for_separator(right, key);
let mut right = right.take();
let (mut node, mut right_depth) = (right.root_mut(), 0);
let separator = loop {
node = match node {
Node::Leaf(leaf) => break leaf.put_separator_head(separator, value),
Node::Internal(internal) => {
right_depth += 1;
internal.child(0)
}
};
};
let left_depth = self.leaf_depth();
if left_depth >= right_depth {
self.join_at_border::<LastEdge>(separator, right, right_depth, alloc);
} else {
let left = mem::replace(self, right);
self.join_at_border::<FirstEdge>(separator, left, left_depth, alloc);
}
}
fn join_at_border<End: NodeEnd>(
&mut self,
separator: Separator<K, S>,
shorter: Self,
shorter_depth: usize,
alloc: &impl Allocator,
) {
let shorter = shorter.into_node(alloc);
let hung = {
let mut stack = NodeStackMut::new(self);
stack.descend_border::<End>(shorter_depth);
let place = stack.absorb_or_hang::<End>(separator, shorter, shorter_depth, alloc);
stack.refit_separator_spines(&place);
place.hung
};
if hung {
self.refit_border_siblings::<End>();
}
}
}
impl<K, V, S: InlineKeyStrategy<K>> NodeStackMut<'_, K, V, S> {
fn descend_border<End: NodeEnd>(&mut self, subtree_depth: usize) {
self.start_at_root();
self.descend_to_end::<End>();
for _ in 0..subtree_depth {
self.ascend();
}
}
fn absorb_or_hang<End: NodeEnd>(
&mut self,
separator: Separator<K, S>,
shorter: Node<K, V, S>,
shorter_depth: usize,
alloc: &impl Allocator,
) -> SeparatorPlace {
let right = if End::IS_LAST {
shorter
} else {
let displaced = self.ascend().replace_child(0, shorter);
self.descend();
displaced
};
let index = self.node().len();
let (separator, right) = match self.node().absorb(separator, right) {
Ok(page) => {
page.deallocate(alloc);
return SeparatorPlace {
child_edge: None,
index,
hung: false,
};
}
Err(unabsorbed) => unabsorbed,
};
self.hang_beside(separator, right, alloc);
self.descend_border::<End>(shorter_depth + 1);
let index = if End::IS_LAST {
self.node().len() - 1
} else {
0
};
self.stock_beside_separator(index)
}
fn hang_beside(
&mut self,
separator: Separator<K, S>,
right: Node<K, V, S>,
alloc: &impl Allocator,
) {
let mut carried = (separator, right);
loop {
let (separator, right) = carried;
let node = self.ascend_raising(alloc);
let index = self.index();
match node.insert(index, separator, right, alloc) {
Insertion::Fit(_) => return,
Insertion::Split(split) => {
carried = (split.separator, Node::Internal(split.right));
}
}
}
}
fn stock_beside_separator(&mut self, index: usize) -> SeparatorPlace {
let node = self.internal();
if node.has_leaf_children() {
node.siblings::<Leaf<K, V, S>>(index)
.stock_beside_separator(index)
} else {
node.siblings::<Internal<K, V, S>>(index)
.stock_beside_separator(index)
}
}
fn refit_separator_spines(&mut self, place: &SeparatorPlace) {
if !NodePtr::<K, V, S>::has_inline_keys() {
return;
}
if let Some(edge) = place.child_edge {
self.set_index(edge);
self.descend();
}
if self.ends_at_leaf() {
return;
}
let index = place.index;
self.refit_border_below::<LastEdge>(index);
self.refit_border_below::<FirstEdge>(index + 1);
self.refit_children_to_fences([index, index + 1]);
}
}
impl<K, V, S: InlineKeyStrategy<K>, C: Child<K, V, S>> Siblings<K, V, S, C> {
fn stock_beside_separator(mut self, index: usize) -> SeparatorPlace {
let min_len = C::min_len();
if self.right_len() < min_len {
let steals = min_len - self.right_len();
for _ in 0..steals {
self.steal_left()
.expect("a child too full to share a node can spare keys");
}
return SeparatorPlace {
child_edge: Some(index + 1),
index: steals - 1,
hung: true,
};
}
if self.left_len() < min_len {
let left_len = self.left_len();
for _ in 0..min_len - left_len {
self.steal_right()
.expect("a child too full to share a node can spare keys");
}
return SeparatorPlace {
child_edge: Some(index),
index: left_len,
hung: true,
};
}
SeparatorPlace {
child_edge: None,
index,
hung: true,
}
}
}
impl<K, V, S: InlineKeyStrategy<K>> Tree<K, V, S> {
pub(crate) fn concat(left: Self, right: Self, alloc: &impl Allocator) -> Self {
let left = Self::destroy_if_empty(left, alloc);
let right = Self::destroy_if_empty(right, alloc);
if !left.has_root() {
return right;
}
if !right.has_root() {
return left;
}
let mut left = DetachedTree::new(left, alloc);
let mut right = DetachedTree::new(right, alloc);
let mut left_length = 1;
let (key, value) = (left.tree)
.pop_last(alloc, &mut left_length)
.expect("a tree with entries has a last one");
left.tree = Self::destroy_if_empty(left.take(), alloc);
if !left.tree.has_root() {
let mut right_length = 0;
let mut stack = NodeStackMut::new(&mut right.tree);
stack.start_at_root();
stack.descend_to_leaf::<FirstEdge>();
stack.insert(key, value, alloc, &mut right_length);
return right.take();
}
left.tree.join(key, value, &mut right.tree, alloc);
left.take()
}
fn destroy_if_empty(tree: Self, alloc: &impl Allocator) -> Self {
if tree
.root_page()
.is_some_and(|root_page| root_page.node().len() > 0)
{
return tree;
}
tree.destroy(alloc);
Self::EMPTY
}
}
pub(crate) struct DetachedTree<K, V, S: InlineKeyStrategy<K>, A: Allocator> {
tree: Tree<K, V, S>,
alloc: A,
}
impl<K, V, S: InlineKeyStrategy<K>, A: Allocator> DetachedTree<K, V, S, A> {
pub(crate) fn new(tree: Tree<K, V, S>, alloc: A) -> Self {
Self { tree, alloc }
}
pub(crate) fn tree_mut(&mut self) -> &mut Tree<K, V, S> {
&mut self.tree
}
pub(crate) fn take(&mut self) -> Tree<K, V, S> {
self.tree.take()
}
pub(crate) fn first_key_value(&self) -> Option<(&K, &V)> {
self.tree.first_key_value()
}
}
impl<K, V, S: InlineKeyStrategy<K>, A: Allocator> Drop for DetachedTree<K, V, S, A> {
fn drop(&mut self) {
self.tree.take().destroy(&self.alloc);
}
}