use std::cmp::Ordering;
use crate::{
utils::{binary_search_min, Array},
Storage, M,
};
use super::{Balance, Offset, WouldUnderflow};
#[derive(Clone)]
pub struct Leaf<T, S: Storage<T>> {
parent: Option<S::Node>,
items: Array<T, { M + 1 }>,
}
impl<T, S: Storage<T>> Leaf<T, S> {
pub fn new(parent: Option<S::Node>, items: Array<T, { M + 1 }>) -> Self {
Self { parent, items }
}
#[inline]
pub fn from_item(parent: Option<S::Node>, item: T) -> Leaf<T, S> {
let mut items = Array::new();
items.push(item);
Leaf { parent, items }
}
pub fn forget(&mut self) {
std::mem::forget(std::mem::take(&mut self.items));
}
#[inline]
pub fn parent(&self) -> Option<S::Node> {
self.parent
}
#[inline]
pub fn set_parent(&mut self, p: Option<S::Node>) {
self.parent = p
}
#[inline]
pub fn item_count(&self) -> usize {
self.items.len()
}
#[inline]
pub fn items(&self) -> &Array<T, { M + 1 }> {
&self.items
}
#[inline]
pub fn iter(&self) -> std::slice::Iter<T> {
self.items.as_ref().iter()
}
#[inline]
pub fn get<Q: ?Sized>(&self, cmp: impl Fn(&T, &Q) -> Ordering, key: &Q) -> Option<&T> {
match binary_search_min(cmp, &self.items, key) {
Some((i, eq)) => {
if eq {
Some(&self.items[i])
} else {
None
}
}
_ => None,
}
}
#[inline]
pub fn get_mut<Q: ?Sized>(
&mut self,
cmp: impl Fn(&T, &Q) -> Ordering,
key: &Q,
) -> Option<&mut T> {
match binary_search_min(cmp, &self.items, key) {
Some((i, eq)) => {
if eq {
Some(&mut self.items[i])
} else {
None
}
}
_ => None,
}
}
#[inline]
pub fn offset_of<Q: ?Sized>(
&self,
cmp: impl Fn(&T, &Q) -> Ordering,
key: &Q,
) -> Result<Offset, Offset> {
match binary_search_min(cmp, &self.items, key) {
Some((i, eq)) => {
if eq {
Ok(i.into())
} else {
Err((i + 1).into())
}
}
None => Err(0.into()),
}
}
#[inline]
pub fn item(&self, offset: Offset) -> Option<&T> {
match offset.value() {
Some(offset) => self.items.get(offset),
None => None,
}
}
#[inline]
pub fn item_mut(&mut self, offset: Offset) -> Option<&mut T> {
match offset.value() {
Some(offset) => self.items.get_mut(offset),
None => None,
}
}
#[inline]
pub fn insert_by_key(
&mut self,
cmp: impl Fn(&T, &T) -> Ordering,
mut item: T,
) -> (Offset, Option<T>) {
match binary_search_min(cmp, &self.items, &item) {
Some((i, eq)) => {
if eq {
std::mem::swap(&mut item, &mut self.items[i]);
(i.into(), Some(item))
} else {
self.items.insert(i + 1, item);
((i + 1).into(), None)
}
}
None => {
self.items.insert(0, item);
(0.into(), None)
}
}
}
#[inline]
pub fn split(&mut self) -> (usize, T, Leaf<T, S>) {
assert!(self.is_overflowing());
let median_i = (self.items.len() - 1) / 2;
let right_items = self.items.drain(median_i + 1..).collect();
let median = self.items.pop().unwrap();
let right_leaf = Leaf {
parent: self.parent,
items: right_items,
};
assert!(!self.is_underflowing());
assert!(!right_leaf.is_underflowing());
(self.items.len(), median, right_leaf)
}
#[inline]
pub fn append(&mut self, separator: T, mut other: Leaf<T, S>) -> Offset {
let offset = self.items.len();
self.items.push(separator);
self.items.append(&mut other.items);
offset.into()
}
#[inline]
pub fn push_left(&mut self, item: T) {
self.items.insert(0, item)
}
#[inline]
pub fn pop_left(&mut self) -> Result<T, WouldUnderflow> {
if self.item_count() < M / 2 {
Err(WouldUnderflow)
} else {
Ok(self.items.remove(0).unwrap())
}
}
#[inline]
pub fn push_right(&mut self, item: T) -> Offset {
let offset = self.items.len();
self.items.push(item);
offset.into()
}
#[inline]
pub fn pop_right(&mut self) -> Result<(Offset, T), WouldUnderflow> {
if self.item_count() < M / 2 {
Err(WouldUnderflow)
} else {
let offset = self.items.len();
let item = self.items.pop().unwrap();
Ok((offset.into(), item))
}
}
#[inline]
pub fn balance(&self) -> Balance {
if self.is_overflowing() {
Balance::Overflow
} else if self.is_underflowing() {
Balance::Underflow(self.items.is_empty())
} else {
Balance::Balanced
}
}
#[inline]
pub fn is_overflowing(&self) -> bool {
self.item_count() > M
}
#[inline]
pub fn is_underflowing(&self) -> bool {
self.item_count() < M / 2 - 1
}
#[inline]
pub fn insert(&mut self, offset: Offset, item: T) {
match offset.value() {
Some(offset) => self.items.insert(offset, item),
None => panic!("Offset out of bounds"),
}
}
#[inline]
pub fn remove(&mut self, offset: Offset) -> T {
match offset.value() {
Some(offset) => self.items.remove(offset).unwrap(),
None => panic!("Offset out of bounds"),
}
}
#[inline]
pub fn remove_last(&mut self) -> T {
self.items.pop().unwrap()
}
#[cfg(feature = "dot")]
#[inline]
pub fn dot_write_label<W: std::io::Write>(&self, f: &mut W) -> std::io::Result<()>
where
T: std::fmt::Display,
{
for item in &self.items {
write!(f, "{{{}}}|", item)?;
}
Ok(())
}
#[cfg(debug_assertions)]
pub fn validate(
&self,
cmp: impl Fn(&T, &T) -> Ordering,
parent: Option<S::Node>,
min: Option<&T>,
max: Option<&T>,
) {
if self.parent() != parent {
panic!("wrong parent")
}
if min.is_some() || max.is_some() {
match self.balance() {
Balance::Overflow => panic!("leaf is overflowing"),
Balance::Underflow(_) => panic!("leaf is underflowing"),
_ => (),
}
}
if !self.items.windows(2).all(|w| cmp(&w[0], &w[1]).is_lt()) {
panic!("leaf items are not sorted")
}
if let Some(min) = min {
if let Some(item) = self.items.first() {
if cmp(min, item).is_ge() {
panic!("leaf item key is greater than right separator")
}
}
}
if let Some(max) = max {
if let Some(item) = self.items.last() {
if cmp(max, item).is_le() {
panic!("leaf item key is less than left separator")
}
}
}
}
}