use super::Child;
use super::internal::Internal;
use super::page::PageByType;
use crate::inline_key::InlineKeyStrategy;
pub(in crate::tree) struct Siblings<K, V, S, C> {
parent: Internal<K, V, S>,
index: usize,
left: C,
right: C,
}
#[derive(Debug, PartialEq, Eq)]
pub(in crate::tree) enum StealError {
DonorEmpty,
ReceiverFull,
}
impl<K, V, S: InlineKeyStrategy<K>, C: Child<K, V, S>> Siblings<K, V, S, C> {
pub(super) fn new(parent: Internal<K, V, S>, index: usize, left: C, right: C) -> Self {
Self {
parent,
index,
left,
right,
}
}
pub(in crate::tree) fn parent(&self) -> Internal<K, V, S> {
self.parent
}
pub(in crate::tree) fn index(&self) -> usize {
self.index
}
pub(in crate::tree) fn left(&self) -> C {
self.left
}
pub(in crate::tree) fn right(&self) -> C {
self.right
}
pub(in crate::tree) fn left_len(&self) -> usize {
self.left.len()
}
pub(in crate::tree) fn right_len(&self) -> usize {
self.right.len()
}
pub(in crate::tree) fn can_merge(&self) -> bool {
C::fit_merged(self.left.len(), self.right.len())
}
pub(in crate::tree) fn merge(self) -> PageByType<K, V, S> {
assert!(
self.can_merge(),
"the children don't fit in one node with their separator"
);
let fill = self.parent.window(self.index);
let (separator, _) = self.parent.remove_with_right_child(self.index);
self.left.move_prefix_back_to(fill);
self.right.move_prefix_back_to(fill);
unsafe {
C::append(self.left, fill, separator, self.right);
self.right.free_page()
}
}
pub(in crate::tree) fn steal_left(&mut self) -> Result<(), StealError> {
if self.left.len() == 0 {
return Err(StealError::DonorEmpty);
}
if self.right.len() == C::capacity() {
return Err(StealError::ReceiverFull);
}
let fill = self.parent.window(self.index);
self.right.move_prefix_back_to(fill);
unsafe { C::steal_left_unchecked(self, fill) };
Ok(())
}
pub(in crate::tree) fn steal_right(&mut self) -> Result<(), StealError> {
if self.right.len() == 0 {
return Err(StealError::DonorEmpty);
}
if self.left.len() == C::capacity() {
return Err(StealError::ReceiverFull);
}
let fill = self.parent.window(self.index);
self.left.move_prefix_back_to(fill);
unsafe { C::steal_right_unchecked(self, fill) };
Ok(())
}
}