diff --git a/Cargo.lock b/Cargo.lock index 36af936..009422b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,6 +18,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "equivalent" version = "1.0.2" @@ -52,6 +58,7 @@ name = "werkzeug" version = "0.1.0" dependencies = [ "atomic-wait", + "either", "hashbrown", ] diff --git a/Cargo.toml b/Cargo.toml index 1ea1c04..e343f97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,4 +16,5 @@ nightly = [] # While I could use libc / windows for this, why not just use this tiny crate # which does exactly and only a futex atomic-wait = "1.1.0" -hashbrown = {version = "0.15", optional = true} \ No newline at end of file +hashbrown = {version = "0.15", optional = true} +either = "1.15.0" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 72bea4d..9404bc5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,6 @@ #![cfg_attr( feature = "nightly", feature( - strict_provenance_atomic_ptr, box_vec_non_null, maybe_uninit_slice, debug_closure_helpers, diff --git a/src/option.rs b/src/option.rs index a688509..809b9d1 100644 --- a/src/option.rs +++ b/src/option.rs @@ -79,20 +79,20 @@ impl, U> core::ops::FromResidual for TransposedOption { } } -#[cfg(all(test, feature = "transposed-option"))] -mod tests { - use super::*; - use TransposedOption::*; +// #[cfg(all(test, feature = "transposed-option"))] +// mod tests { +// use super::*; +// use TransposedOption::*; - #[test] - fn transposed_option_try() { - let a: TransposedOption = try { - TransposedOption::Some(42)?; - None::?; +// #[test] +// fn transposed_option_try() { +// let a: TransposedOption = try { +// TransposedOption::Some(42)?; +// None::?; - Some(3) - }; +// Some(3) +// }; - assert_eq!(a, TransposedOption::Some(42)); - } -} +// assert_eq!(a, TransposedOption::Some(42)); +// } +// } diff --git a/src/tree.rs b/src/tree.rs index fd55a28..d936cfd 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -15,6 +15,8 @@ use alloc::boxed::Box; use core::{marker::PhantomData, mem::MaybeUninit, ptr::NonNull}; +use crate::tree::subtree::Subtree; + mod marker { use core::marker::PhantomData; @@ -52,7 +54,7 @@ mod marker { } #[derive(Debug)] -struct LeafNode { +pub(crate) struct LeafNode { parent: Option>, parent_idx: MaybeUninit, value: Option, @@ -65,13 +67,13 @@ struct LeafNode { type BoxedNode = NonNull>; #[derive(Debug)] -struct NodeRef { +pub(crate) struct NodeRef { node: NonNull>, _marker: PhantomData, } #[derive(Debug)] -struct Handle { +pub(crate) struct Handle { node: Node, idx: usize, _marker: PhantomData, @@ -207,6 +209,7 @@ impl Handle, mar } impl NodeRef { + #[allow(dead_code)] pub(super) fn deallocate_and_ascend( self, ) -> Option, marker::Edge>> { @@ -544,6 +547,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V>, marker::Value> { } impl NodeRef { + #[allow(dead_code)] /// Borrows exclusive access to the leaf portion of a dying leaf or internal node. fn as_leaf_dying(&mut self) -> &mut LeafNode { let ptr = Self::as_leaf_ptr(self); @@ -553,6 +557,7 @@ impl NodeRef { } impl NodeRef { + #[allow(dead_code)] pub(super) unsafe fn into_value(mut self) -> Option { let leaf = self.as_leaf_dying(); leaf.value.take() @@ -864,23 +869,36 @@ mod search { } } -enum TreeOr<'a, K, V, T> { +pub(crate) enum TreeOr<'a, K, V, T> { Tree(borrow::DormantMutRef<'a, Tree>), Other(T), } +impl<'a, K, V, T> TreeOr<'a, K, V, T> { + #[allow(dead_code)] + fn as_tree_mut(&mut self) -> &mut borrow::DormantMutRef<'a, Tree> { + match self { + TreeOr::Tree(tree) => tree, + TreeOr::Other(_) => panic!("no tree present"), + } + } + + #[allow(dead_code)] + fn as_other_mut(&mut self) -> &mut T { + match self { + TreeOr::Tree(_) => panic!("no other present"), + TreeOr::Other(other) => other, + } + } +} + type TreeOrHandle<'a, BorrowType, K, V, HandleType> = TreeOr<'a, K, V, Handle, HandleType>>; -enum HandleOrTree<'a, BorrowType, K, V, HandleType> { - Handle(Handle, HandleType>), - Tree(borrow::DormantMutRef<'a, Tree>), -} - mod entry { use core::marker::PhantomData; - use crate::tree::TreeOrHandle; + use crate::tree::{TreeOrHandle, subtree::Subtree}; use super::{Handle, NodeRef, marker}; @@ -949,10 +967,8 @@ mod entry { unsafe { self.handle.value_mut() } } - pub fn into_subtree(self) -> super::subtree::Subtree> { - super::subtree::Subtree { - root: self.handle.node, - } + pub fn into_subtree(self) -> super::subtree::Subtree<'a, K, V, marker::Mut<'a>> { + Subtree::new_root(self.handle.node) } } @@ -998,7 +1014,9 @@ mod entry { mod subtree { use core::marker::PhantomData; - use crate::tree::{TreeOrHandle, search}; + use either::Either; + + use crate::tree::{TreeOr, TreeOrHandle, borrow::DormantMutRef, search}; use super::{ NodeRef, OnceAndIter, @@ -1007,11 +1025,59 @@ mod subtree { }; // BorrowType may be one of `Immut`, `Mut`. - pub struct Subtree { - pub(super) root: NodeRef, + pub struct Subtree<'tree, K, V, BorrowType> { + pub(super) root: TreeOr<'tree, K, V, NodeRef>, } - impl Subtree + impl<'tree, K, V, BorrowType> Subtree<'tree, K, V, BorrowType> { + fn root(&self) -> Option<&NodeRef> { + match &self.root { + TreeOr::Tree(_) => None, + TreeOr::Other(node) => Some(node), + } + } + + pub(crate) fn new_root(node: NodeRef) -> Self { + Self { + root: TreeOr::Other(node), + } + } + + pub(crate) fn new_empty(tree: DormantMutRef<'tree, super::Tree>) -> Self { + Self { + root: TreeOr::Tree(tree), + } + } + } + + impl<'tree, K, V> Subtree<'tree, K, V, marker::Mut<'tree>> { + /// Returns a mutable reference to the root node of this subtree. + /// This function rechecks whether the tree is empty. + fn root_mut<'a>( + &'a mut self, + ) -> Either, K, V>, DormantMutRef<'a, super::Tree>> { + let node = match &mut self.root { + TreeOr::Tree(tree) => { + let (tree, borrow) = DormantMutRef::new(unsafe { tree.reborrow() }); + match tree.root.as_mut() { + Some(node) => node.borrow_mut().dormant(), + None => return Either::Right(borrow), + } + } + TreeOr::Other(node) => node.dormant(), + }; + + self.root = TreeOr::Other(unsafe { node.awaken() }); + + let TreeOr::Other(node) = &mut self.root else { + unreachable!() + }; + + return Either::Left(unsafe { node.reborrow_mut() }); + } + } + + impl<'tree, K, V, BorrowType> Subtree<'tree, K, V, BorrowType> where K: Ord, { @@ -1019,7 +1085,7 @@ mod subtree { where Q: Iterator, { - let root = self.root.reborrow(); + let root = self.root()?.reborrow(); match root.search_tree(&mut key_seq) { search::SearchResult::Found(handle) => Some(unsafe { handle.into_value() }), _ => { @@ -1029,13 +1095,16 @@ mod subtree { } } - pub fn get_subtree(&self, mut key_seq: Q) -> Option>> + pub fn get_subtree( + &'_ self, + mut key_seq: Q, + ) -> Option>> where Q: Iterator, { - let root = self.root.reborrow(); + let root = self.root()?.reborrow(); match root.search_tree(&mut key_seq) { - search::SearchResult::Found(handle) => Some(Subtree { root: handle.node }), + search::SearchResult::Found(handle) => Some(Subtree::new_root(handle.node)), _ => { // key not found None @@ -1044,7 +1113,7 @@ mod subtree { } } - impl<'a, K, V> Subtree> + impl<'tree, K, V> Subtree<'tree, K, V, marker::Mut<'tree>> where K: Ord, { @@ -1052,7 +1121,7 @@ mod subtree { where Q: Iterator, { - let root = unsafe { self.root.reborrow_mut() }; + let root = self.root_mut().left()?; match root.search_tree(&mut key_seq) { search::SearchResult::Found(handle) => Some(handle.into_value_mut()), _ => { @@ -1065,13 +1134,13 @@ mod subtree { pub fn get_subtree_mut( &'_ mut self, mut key_seq: Q, - ) -> Option>> + ) -> Option>> where Q: Iterator, { - let root = unsafe { self.root.reborrow_mut() }; + let root = self.root_mut().left()?; match root.search_tree(&mut key_seq) { - search::SearchResult::Found(handle) => Some(Subtree { root: handle.node }), + search::SearchResult::Found(handle) => Some(Subtree::new_root(handle.node)), _ => { // key not found None @@ -1085,24 +1154,30 @@ mod subtree { { use Entry::*; - // SAFETY: this is actually our borrow? - let root = unsafe { self.root.reborrow_mut() }; - - match root.search_tree(&mut key_seq) { - search::SearchResult::Found(handle) => Occupied(OccupiedEntry { - handle, - _marker: PhantomData, - }), - search::SearchResult::GoDown(handle) => Vacant(VacantEntry { - key: key_seq.into(), - handle: TreeOrHandle::Other(handle), - _marker: PhantomData, - }), - search::SearchResult::Insert(key, handle) => Vacant(VacantEntry { - key: OnceAndIter::once(key, key_seq), - handle: TreeOrHandle::Other(handle), - _marker: PhantomData, - }), + match self.root_mut() { + Either::Right(tree) => { + return Vacant(VacantEntry { + key: key_seq.into(), + handle: TreeOrHandle::Tree(tree), + _marker: PhantomData, + }); + } + Either::Left(root) => match root.search_tree(&mut key_seq) { + search::SearchResult::Found(handle) => Occupied(OccupiedEntry { + handle, + _marker: PhantomData, + }), + search::SearchResult::GoDown(handle) => Vacant(VacantEntry { + key: key_seq.into(), + handle: TreeOrHandle::Other(handle), + _marker: PhantomData, + }), + search::SearchResult::Insert(key, handle) => Vacant(VacantEntry { + key: OnceAndIter::once(key, key_seq), + handle: TreeOrHandle::Other(handle), + _marker: PhantomData, + }), + }, } } } @@ -1123,7 +1198,7 @@ mod borrow { /// the compiler to follow. A `DormantMutRef` allows you to check borrowing /// yourself, while still expressing its stacked nature, and encapsulating /// the raw pointer code needed to do this without undefined behavior. - pub(super) struct DormantMutRef<'a, T> { + pub(crate) struct DormantMutRef<'a, T> { ptr: NonNull, _marker: PhantomData<&'a mut T>, } @@ -1307,45 +1382,35 @@ impl Tree where K: Ord, { - pub fn as_subtree_mut<'a>(&'a mut self) -> Option>> { - let root = self.root.as_mut()?.borrow_mut().dormant(); - - Some(subtree::Subtree { - root: unsafe { root.awaken() }, - }) + pub fn as_subtree_mut<'a>(&'a mut self) -> subtree::Subtree<'a, K, V, marker::Mut<'a>> { + match self.root.as_mut() { + Some(node) => { + let dormant = node.borrow_mut().dormant(); + Subtree::new_root(unsafe { dormant.awaken() }) + } + None => { + let (_, dormant) = borrow::DormantMutRef::new(self); + Subtree::new_empty(dormant) + } + } } pub fn entry<'a, Q>(&'a mut self, key_seq: Q) -> entry::Entry<'a, OnceAndIter, K, V> where Q: Iterator, { - use borrow::DormantMutRef; - use entry::{Entry::*, VacantEntry}; - - let (tree, dormant) = DormantMutRef::new(self); - - let entry = match tree.as_subtree_mut() { - Some(mut subtree) => { - let entry = subtree.entry(key_seq); - // SAFETY: extending the lifetime is fine because we borrow the tree for 'a, - // and no references to the subtree are live after this. - // The same could be achieved using `dormant.reborrow()` a bunch - // of times while destructuring the entry. - unsafe { - core::mem::transmute::< - entry::Entry<'_, OnceAndIter, K, V>, - entry::Entry<'a, OnceAndIter, K, V>, - >(entry) - } - } - None => Vacant(VacantEntry { - key: key_seq.into(), - handle: TreeOrHandle::Tree(dormant), - _marker: PhantomData, - }), - }; - - entry + let mut subtree = self.as_subtree_mut(); + let entry = subtree.entry(key_seq); + // SAFETY: extending the lifetime is fine because we borrow the tree for 'a, + // and no references to the subtree are live after this. + // The same could be achieved using `dormant.reborrow()` a bunch + // of times while destructuring the entry. + unsafe { + core::mem::transmute::< + entry::Entry<'_, OnceAndIter, K, V>, + entry::Entry<'a, OnceAndIter, K, V>, + >(entry) + } } }