rbtree: range and drain
This commit is contained in:
parent
47288aeed1
commit
67551afc56
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue