use core::fmt;
use super::PrefixMatchBehavior;
use crate::{
allocator::Allocator,
raw::{
match_concrete_node_ptr, operations::lookup, ConcreteNodePtr, InnerNode, InnerNodeCommon,
LeafNode, NodePtr, OpaqueNodePtr, TreePath, TreePathSearch,
},
AsBytes,
};
unsafe fn remove_child_from_inner_node_and_compress<
const PREFIX_LEN: usize,
N: InnerNode<PREFIX_LEN>,
A: Allocator,
>(
inner_node_ptr: NodePtr<PREFIX_LEN, N>,
key_fragment: u8,
#[cfg(debug_assertions)] expected_leaf_node: NodePtr<
PREFIX_LEN,
LeafNode<N::Key, N::Value, PREFIX_LEN>,
>,
alloc: &A,
) -> Option<OpaqueNodePtr<N::Key, N::Value, PREFIX_LEN>> {
let inner_node = unsafe { inner_node_ptr.as_mut() };
let _removed = inner_node.remove_child(key_fragment);
#[cfg(debug_assertions)]
{
debug_assert!(
_removed.is_some(),
"child must be present at [{key_fragment}] in inner node [{inner_node:?}]"
);
let removed = _removed.unwrap();
debug_assert!(
removed.is::<LeafNode<N::Key, N::Value, PREFIX_LEN>>(),
"child at [{key_fragment}] in inner node [{inner_node:?}] must be a leaf node"
);
debug_assert_eq!(
removed,
expected_leaf_node.to_opaque(),
"child at [{key_fragment}] in inner node [{inner_node:?}] should be [{:?}]",
expected_leaf_node.to_opaque()
);
}
if inner_node.header().num_children() == 1 {
let mut children = inner_node.iter();
let (child_key_byte, child_node_ptr) = children.next().expect("expected single child");
debug_assert!(
children.next().is_none(),
"expected only a single child, not more"
);
drop(children);
if let Some(child_header) = unsafe { child_node_ptr.header_mut() } {
let parent_header = inner_node.header();
let parent_prefix = parent_header.read_prefix();
let parent_len = parent_header.prefix_len();
let (old_prefix, old_len, old_capped_len) = child_header.clear_prefix();
child_header.push_prefix(parent_prefix, parent_len);
child_header.push_prefix(&[child_key_byte], 1);
child_header.push_prefix(&old_prefix[..old_capped_len], old_len);
}
unsafe {
drop(NodePtr::deallocate_node_ptr(inner_node_ptr, alloc));
}
Some(child_node_ptr)
} else if N::TYPE.should_shrink_inner_node(inner_node.header().num_children()) {
let new_inner_node = inner_node.shrink();
let new_inner_node_ptr = NodePtr::allocate_node_ptr(new_inner_node, alloc).to_opaque();
unsafe {
drop(NodePtr::deallocate_node_ptr(inner_node_ptr, alloc));
}
Some(new_inner_node_ptr)
} else {
None
}
}
unsafe fn inner_delete_non_root_unchecked<K, V, const PREFIX_LEN: usize, A: Allocator>(
leaf_node_ptr: NodePtr<PREFIX_LEN, LeafNode<K, V, PREFIX_LEN>>,
parent_node_ptr: OpaqueNodePtr<K, V, PREFIX_LEN>,
child_key_byte: u8,
grandparent_node_ptr: Option<(OpaqueNodePtr<K, V, PREFIX_LEN>, u8)>,
original_root: OpaqueNodePtr<K, V, PREFIX_LEN>,
alloc: &A,
) -> DeleteResult<K, V, PREFIX_LEN> {
let new_parent_node_ptr = match_concrete_node_ptr!(match (parent_node_ptr.to_node_ptr()) {
InnerNode(parent_node_ptr) => unsafe {
remove_child_from_inner_node_and_compress(
parent_node_ptr,
child_key_byte,
#[cfg(debug_assertions)]
leaf_node_ptr,
alloc,
)
},
LeafNode(_leaf) => unreachable!("Cannot have delete from leaf node"),
});
if let Some(new_parent_node_ptr) = new_parent_node_ptr {
if let Some((grandparent_node_ptr, parent_key_byte)) = grandparent_node_ptr {
match_concrete_node_ptr!(match (grandparent_node_ptr.to_node_ptr()) {
InnerNode(inner_node_ptr) => {
let inner_node = unsafe { inner_node_ptr.as_mut() };
inner_node.write_child(parent_key_byte, new_parent_node_ptr);
},
LeafNode(_leaf) => {
unreachable!("Cannot modify children of a leaf node")
},
})
}
}
unsafe { LeafNode::remove_self(leaf_node_ptr) }
let leaf_node = unsafe { NodePtr::deallocate_node_ptr(leaf_node_ptr, alloc) };
let new_root = match (new_parent_node_ptr, grandparent_node_ptr) {
(Some(new_parent_node_ptr), None) => new_parent_node_ptr,
_ => original_root,
};
DeleteResult {
new_root: Some(new_root),
deleted_leaf: leaf_node,
}
}
#[derive(Debug)]
pub struct DeleteResult<K, V, const PREFIX_LEN: usize> {
pub new_root: Option<OpaqueNodePtr<K, V, PREFIX_LEN>>,
pub deleted_leaf: LeafNode<K, V, PREFIX_LEN>,
}
pub struct DeletePoint<K, V, const PREFIX_LEN: usize> {
pub path: TreePath<K, V, PREFIX_LEN>,
pub leaf_node_ptr: NodePtr<PREFIX_LEN, LeafNode<K, V, PREFIX_LEN>>,
}
impl<K, V, const PREFIX_LEN: usize> fmt::Debug for DeletePoint<K, V, PREFIX_LEN> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DeletePoint")
.field("path", &self.path)
.field("leaf_node_ptr", &self.leaf_node_ptr)
.finish()
}
}
impl<K, V, const PREFIX_LEN: usize> DeletePoint<K, V, PREFIX_LEN> {
pub unsafe fn apply<A: Allocator>(
self,
root: OpaqueNodePtr<K, V, PREFIX_LEN>,
alloc: &A,
) -> DeleteResult<K, V, PREFIX_LEN> {
match self.path {
TreePath::Root => {
let leaf_node = unsafe { NodePtr::deallocate_node_ptr(self.leaf_node_ptr, alloc) };
DeleteResult {
new_root: None,
deleted_leaf: leaf_node,
}
},
TreePath::ChildOfRoot {
parent: root_parent,
child_key_byte,
} => unsafe {
inner_delete_non_root_unchecked(
self.leaf_node_ptr,
root_parent,
child_key_byte,
None,
root,
alloc,
)
},
TreePath::Normal {
grandparent,
parent_key_byte,
parent,
child_key_byte,
} => unsafe {
inner_delete_non_root_unchecked(
self.leaf_node_ptr,
parent,
child_key_byte,
Some((grandparent, parent_key_byte)),
root,
alloc,
)
},
}
}
}
pub unsafe fn search_for_delete_point<K, V, const PREFIX_LEN: usize>(
root: OpaqueNodePtr<K, V, PREFIX_LEN>,
key_bytes: &[u8],
) -> Option<DeletePoint<K, V, PREFIX_LEN>>
where
K: AsBytes,
{
let mut path = TreePathSearch::default();
let mut current_node = root;
let mut current_depth = 0;
let mut prefix_match_state = PrefixMatchBehavior::default();
loop {
let next_node = match_concrete_node_ptr!(match (current_node.to_node_ptr()) {
InnerNode(inner_ptr) => unsafe {
lookup::check_prefix_lookup_child(
inner_ptr,
key_bytes,
&mut current_depth,
&mut prefix_match_state,
)
},
LeafNode(leaf_node_ptr) => {
let leaf = unsafe { leaf_node_ptr.as_ref() };
if prefix_match_state.matches_leaf_key(leaf, key_bytes, current_depth) {
return Some(DeletePoint {
path: path.finish(),
leaf_node_ptr,
});
} else {
return None;
}
},
})?;
debug_assert!(
current_depth > 0,
"for a non-leaf node, there should be some amount of key"
);
let last_key_byte = key_bytes[current_depth - 1];
path.visit_inner_node(current_node, last_key_byte);
current_node = next_node;
}
}
#[inline]
pub unsafe fn find_minimum_to_delete<K, V, const PREFIX_LEN: usize>(
root: OpaqueNodePtr<K, V, PREFIX_LEN>,
) -> DeletePoint<K, V, PREFIX_LEN> {
let mut path = TreePathSearch::default();
let mut current_node = root;
loop {
let (last_key_byte, next_node) =
match_concrete_node_ptr!(match (current_node.to_node_ptr()) {
InnerNode(inner_node) => unsafe { inner_node.as_ref().min() },
LeafNode(leaf_node_ptr) => {
return DeletePoint {
path: path.finish(),
leaf_node_ptr,
};
},
});
path.visit_inner_node(current_node, last_key_byte);
current_node = next_node;
}
}
#[inline]
pub unsafe fn find_maximum_to_delete<K, V, const PREFIX_LEN: usize>(
root: OpaqueNodePtr<K, V, PREFIX_LEN>,
) -> DeletePoint<K, V, PREFIX_LEN> {
let mut path = TreePathSearch::default();
let mut current_node = root;
loop {
let (last_key_byte, next_node) =
match_concrete_node_ptr!(match (current_node.to_node_ptr()) {
InnerNode(inner_node) => unsafe { inner_node.as_ref().max() },
LeafNode(leaf_node_ptr) => {
return DeletePoint {
path: path.finish(),
leaf_node_ptr,
};
},
});
path.visit_inner_node(current_node, last_key_byte);
current_node = next_node;
}
}
#[cfg(test)]
mod tests;