rbtree: range and drain

This commit is contained in:
janis 2026-08-05 19:01:16 +02:00
parent 47288aeed1
commit 67551afc56
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
2 changed files with 232 additions and 11 deletions

View file

@ -6,4 +6,22 @@ mod raw_node;
extern crate alloc; extern crate alloc;
pub use raw_node::{Color, RBTree, Side, TreeIter, TreeNodeIter, UnsafeNode}; pub use raw_node::{
Color, Drain, Handle, LeftOrRight, RBTree, SearchResult, Side, TreeIter, TreeNodeIter,
UnsafeNode,
};
fn replace<T, R>(v: &mut T, f: impl FnOnce(T) -> (T, R)) -> R {
struct Guard;
impl Drop for Guard {
fn drop(&mut self) {
panic!("replace() panicked");
}
}
let guard = Guard;
let value = unsafe { core::ptr::read(v) };
let (new_value, ret) = f(value);
unsafe { core::ptr::write(v, new_value) };
core::mem::forget(guard);
ret
}

View file

@ -54,6 +54,26 @@ pub enum SearchResult<T> {
Empty, Empty,
} }
impl<N: UnsafeNode> SearchResult<Handle<N>> {
fn next_extant(self, inclusive: bool) -> Option<Handle<N>> {
match self {
SearchResult::FoundAt(handle) if inclusive => Some(handle),
SearchResult::FoundAt(handle) | SearchResult::NotFoundAt(handle) => handle.next_of(),
SearchResult::Empty => None,
}
}
fn next_back_extant(self, inclusive: bool) -> Option<Handle<N>> {
match self {
SearchResult::FoundAt(handle) if inclusive => Some(handle),
SearchResult::FoundAt(handle) | SearchResult::NotFoundAt(handle) => {
handle.next_back_of()
}
SearchResult::Empty => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Color { pub enum Color {
Red, Red,
@ -197,7 +217,7 @@ impl<N> Clone for Handle<N> {
impl<N> !Sync for Handle<N> {} impl<N> !Sync for Handle<N> {}
impl<N: UnsafeNode> Handle<N> { impl<N: UnsafeNode> Handle<N> {
fn from_node(node: Option<NonNull<N>>) -> Self { pub fn from_node(node: Option<NonNull<N>>) -> Self {
let Some(node) = node else { let Some(node) = node else {
return Handle::EmptyRoot; return Handle::EmptyRoot;
}; };
@ -218,8 +238,7 @@ impl<N: UnsafeNode> Handle<N> {
} }
} }
#[expect(dead_code)] pub fn refresh_from_node(&mut self) {
fn refresh_from_node(&mut self) {
*self = Self::from_node(self.node()); *self = Self::from_node(self.node());
} }
@ -396,6 +415,34 @@ impl<N: UnsafeNode> Handle<N> {
Some(side.map(|_| parent)) Some(side.map(|_| parent))
} }
fn remove_from_parent_into_node(self) -> (Option<NonNull<N>>, Option<Self>) {
match self {
Handle::EmptyRoot => (None, None),
Handle::Root(node) => (Some(node), None),
Handle::Child {
parent,
node: LeftOrRight::Left(Some(node)),
} => {
unsafe { parent.as_ref().set_left(None) };
(Some(node), Some(Handle::from_node(Some(parent))))
}
Handle::Child {
parent,
node: LeftOrRight::Right(Some(node)),
} => {
unsafe { parent.as_ref().set_right(None) };
(Some(node), Some(Handle::from_node(Some(parent))))
}
Handle::Child {
parent,
node: LeftOrRight::Right(None) | LeftOrRight::Left(None),
} => {
unsafe { parent.as_ref().set_right(None) };
(None, Some(Handle::from_node(Some(parent))))
}
}
}
fn parent(&self) -> Option<Self> { fn parent(&self) -> Option<Self> {
self.parent_and_side().map(LeftOrRight::into_inner) self.parent_and_side().map(LeftOrRight::into_inner)
} }
@ -528,6 +575,18 @@ impl<N: UnsafeNode> Handle<N> {
Some(current) Some(current)
} }
/// moves to the least non-nil node in the tree, or `Err(self)`.
pub fn into_least_leaf(mut self) -> Self {
while let Some(child) = self
.left_child_extant()
.or_else(|| self.right_child_extant())
{
self = child;
}
self
}
/// Returns the greatest non-nil node in the subtree rooted at `self`, or /// Returns the greatest non-nil node in the subtree rooted at `self`, or
/// `None` if the subtree is empty. /// `None` if the subtree is empty.
pub fn maximum_of(&self) -> Option<Self> { pub fn maximum_of(&self) -> Option<Self> {
@ -839,7 +898,7 @@ impl<N: UnsafeNode> RBTree<N> {
pub fn pop_min(&mut self) -> Option<NonNull<N>> { pub fn pop_min(&mut self) -> Option<NonNull<N>> {
let min = self.root_handle().minimum_of()?; let min = self.root_handle().minimum_of()?;
self.remove_node(min) self.remove_handle(min)
} }
#[must_use] #[must_use]
@ -852,11 +911,11 @@ impl<N: UnsafeNode> RBTree<N> {
return None; return None;
}; };
self.remove_node(z) self.remove_handle(z)
} }
#[must_use] #[must_use]
fn remove_node(&mut self, z: Handle<N>) -> Option<NonNull<N>> { pub fn remove_handle(&mut self, z: Handle<N>) -> Option<NonNull<N>> {
// Y is either Z, the removed node in the case that Z has at most // Y is either Z, the removed node in the case that Z has at most
// one child, or Y is Z's successor which is guaranteed to have at most one // one child, or Y is Z's successor which is guaranteed to have at most one
// child (the right child). // child (the right child).
@ -1028,6 +1087,74 @@ impl<N: UnsafeNode> RBTree<N> {
range: TreeRange::full_range(self.root_handle()), range: TreeRange::full_range(self.root_handle()),
} }
} }
pub fn range<T, R>(&self, range: R) -> TreeIter<'_, N>
where
T: Ord + ?Sized,
N::Key: core::borrow::Borrow<T> + Ord,
R: core::ops::RangeBounds<T>,
{
use core::ops::Bound;
let front = match range.start_bound() {
Bound::Included(key) => self.find_by_key(key).next_extant(true),
Bound::Excluded(key) => self.find_by_key(key).next_extant(false),
Bound::Unbounded => None,
}
.or_else(|| self.root_handle().minimum_of());
let back = match range.end_bound() {
Bound::Included(key) => self.find_by_key(key).next_back_extant(true),
Bound::Excluded(key) => self.find_by_key(key).next_back_extant(false),
Bound::Unbounded => None,
}
.or_else(|| self.root_handle().maximum_of());
TreeIter {
range: TreeRange {
start: front.map(RangeHandle::Node),
end: back.map(RangeHandle::Node),
_pd: PhantomData,
},
}
}
pub fn drain(&mut self) -> Drain<'_, N> {
let node = self.root_handle();
self.root = None;
Drain {
node,
_pd: PhantomData,
}
}
}
pub struct Drain<'a, N: UnsafeNode> {
node: Handle<N>,
_pd: PhantomData<&'a mut RBTree<N>>,
}
impl<'a, N: UnsafeNode> Drain<'a, N> {
fn next(&mut self) -> Option<NonNull<N>> {
if self.node.is_nil() {
return None;
}
crate::replace(&mut self.node, |node| {
let leaf = node.into_least_leaf();
let (node, parent) = leaf.remove_from_parent_into_node();
(parent.unwrap_or(Handle::EmptyRoot), node)
})
}
}
impl<'a, N: UnsafeNode> Iterator for Drain<'a, N> {
type Item = NonNull<N>;
fn next(&mut self) -> Option<Self::Item> {
self.next()
}
} }
impl<N: UnsafeNode> Default for RBTree<N> { impl<N: UnsafeNode> Default for RBTree<N> {
@ -1078,6 +1205,15 @@ impl<'a, N: UnsafeNode + 'a> TreeRange<'a, N> {
_pd: PhantomData, _pd: PhantomData,
} }
} }
fn empty() -> Self {
Self {
start: None,
end: None,
_pd: PhantomData,
}
}
fn full_range(root: Handle<N>) -> Self { fn full_range(root: Handle<N>) -> Self {
Self { Self {
start: Some(RangeHandle::Root(root.clone())), start: Some(RangeHandle::Root(root.clone())),
@ -1121,8 +1257,8 @@ impl<'a, N: UnsafeNode + 'a> TreeRange<'a, N> {
match self.end { match self.end {
None => None, None => None,
_ => { _ => {
if self.start == self.end { if current == self.end {
self.end = None; *self = TreeRange::empty();
} }
current.map(RangeHandle::into_inner) current.map(RangeHandle::into_inner)
@ -1137,8 +1273,8 @@ impl<'a, N: UnsafeNode + 'a> TreeRange<'a, N> {
match self.start { match self.start {
None => None, None => None,
_ => { _ => {
if self.start == self.end { if current == self.start {
self.start = None; *self = TreeRange::empty();
} }
current.map(RangeHandle::into_inner) current.map(RangeHandle::into_inner)
@ -1195,6 +1331,8 @@ impl<'a, N: UnsafeNode + 'a> DoubleEndedIterator for TreeIter<'a, N> {
mod tests { mod tests {
use std::cell::Cell; use std::cell::Cell;
use core::sync::atomic::{AtomicI32, Ordering};
use super::*; use super::*;
#[derive(Debug)] #[derive(Debug)]
@ -1438,4 +1576,69 @@ mod tests {
assert!(matches!(result, SearchResult::Empty)); assert!(matches!(result, SearchResult::Empty));
} }
} }
#[test]
fn drain() {
let mut tree = RBTree::<TestNode>::new();
let count = AtomicI32::new(0);
for node in (1..=10).map(|i| {
count.fetch_add(i, Ordering::SeqCst);
Box::into_raw(Box::new(TestNode::new(i)))
}) {
let None = tree.insert_node(unsafe { NonNull::new_unchecked(node) }) else {
panic!("duplicate node")
};
}
let drain = tree.drain();
drain.for_each(|node| {
let node = unsafe { Box::from_raw(node.as_ptr()) };
count.fetch_sub(node.key, Ordering::SeqCst);
});
assert_eq!(
count.load(Ordering::SeqCst),
0,
"all nodes should have been drained and dropped"
);
}
#[test]
fn drain_collect() {
let mut tree = RBTree::<TestNode>::new();
for node in (1..=10).map(|i| Box::into_raw(Box::new(TestNode::new(i)))) {
let None = tree.insert_node(unsafe { NonNull::new_unchecked(node) }) else {
panic!("duplicate node")
};
}
let mut nodes: Vec<_> = tree
.drain()
.map(|node| unsafe { Box::from_raw(node.as_ptr()).key })
.collect();
nodes.sort();
assert_eq!(nodes, (1..=10).collect::<Vec<_>>());
}
#[test]
fn range() {
let mut tree = RBTree::<TestNode>::new();
for node in (1..=10).map(|i| Box::into_raw(Box::new(TestNode::new(i)))) {
let None = tree.insert_node(unsafe { NonNull::new_unchecked(node) }) else {
panic!("duplicate node")
};
}
let range = tree.range(3..=7);
let keys: Vec<_> = range.cloned().collect();
assert_eq!(keys, vec![3, 4, 5, 6, 7]);
}
} }