mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-28 15:43:21 +00:00
Auto merge of #75200 - ssomers:btree_valmut, r=Mark-Simulacrum
BTreeMap: introduce marker::ValMut and reserve Mut for unique access The mutable BTreeMap iterators (apart from `DrainFilter`) are double-ended, meaning they have to rely on a front and a back handle that each represent a reference into the tree. Reserve a type category `marker::ValMut` for them, so that we guarantee that they cannot reach operations on handles with borrow type `marker::Mut`and that these operations can assume unique access to the tree. Including #75195, benchmarks report no genuine change: ``` benchcmp old new --threshold 5 name old ns/iter new ns/iter diff ns/iter diff % speedup btree::map::iter_100 3,333 3,023 -310 -9.30% x 1.10 btree::map::range_unbounded_vs_iter 36,624 31,569 -5,055 -13.80% x 1.16 ``` r? @Mark-Simulacrum
This commit is contained in:
commit
70c5f6efc4
@ -5,7 +5,6 @@ use core::hash::{Hash, Hasher};
|
||||
use core::iter::{FromIterator, FusedIterator, Peekable};
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::{self, ManuallyDrop};
|
||||
use core::ops::Bound::{Excluded, Included, Unbounded};
|
||||
use core::ops::{Index, RangeBounds};
|
||||
use core::ptr;
|
||||
|
||||
@ -408,8 +407,8 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for Range<'_, K, V> {
|
||||
/// [`range_mut`]: BTreeMap::range_mut
|
||||
#[stable(feature = "btree_range", since = "1.17.0")]
|
||||
pub struct RangeMut<'a, K: 'a, V: 'a> {
|
||||
front: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
|
||||
back: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
|
||||
front: Option<Handle<NodeRef<marker::ValMut<'a>, K, V, marker::Leaf>, marker::Edge>>,
|
||||
back: Option<Handle<NodeRef<marker::ValMut<'a>, K, V, marker::Leaf>, marker::Edge>>,
|
||||
|
||||
// Be invariant in `K` and `V`
|
||||
_marker: PhantomData<&'a mut (K, V)>,
|
||||
@ -999,7 +998,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
||||
R: RangeBounds<T>,
|
||||
{
|
||||
if let Some(root) = &self.root {
|
||||
let (f, b) = range_search(root.node_as_ref(), range);
|
||||
let (f, b) = root.node_as_ref().range_search(range);
|
||||
|
||||
Range { front: Some(f), back: Some(b) }
|
||||
} else {
|
||||
@ -1045,7 +1044,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
||||
R: RangeBounds<T>,
|
||||
{
|
||||
if let Some(root) = &mut self.root {
|
||||
let (f, b) = range_search(root.node_as_mut(), range);
|
||||
let (f, b) = root.node_as_valmut().range_search(range);
|
||||
|
||||
RangeMut { front: Some(f), back: Some(b), _marker: PhantomData }
|
||||
} else {
|
||||
@ -1478,7 +1477,7 @@ impl<K, V> IntoIterator for BTreeMap<K, V> {
|
||||
fn into_iter(self) -> IntoIter<K, V> {
|
||||
let mut me = ManuallyDrop::new(self);
|
||||
if let Some(root) = me.root.take() {
|
||||
let (f, b) = full_range_search(root.into_ref());
|
||||
let (f, b) = root.into_ref().full_range();
|
||||
|
||||
IntoIter { front: Some(f), back: Some(b), length: me.length }
|
||||
} else {
|
||||
@ -1942,7 +1941,7 @@ impl<'a, K, V> RangeMut<'a, K, V> {
|
||||
self.front == self.back
|
||||
}
|
||||
|
||||
unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
|
||||
unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) {
|
||||
unsafe { unwrap_unchecked(self.front.as_mut()).next_unchecked() }
|
||||
}
|
||||
}
|
||||
@ -1963,7 +1962,7 @@ impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> {
|
||||
impl<K, V> FusedIterator for RangeMut<'_, K, V> {}
|
||||
|
||||
impl<'a, K, V> RangeMut<'a, K, V> {
|
||||
unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
|
||||
unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) {
|
||||
unsafe { unwrap_unchecked(self.back.as_mut()).next_back_unchecked() }
|
||||
}
|
||||
}
|
||||
@ -2073,119 +2072,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds the leaf edges delimiting a specified range in or underneath a node.
|
||||
fn range_search<BorrowType, K, V, Q: ?Sized, R: RangeBounds<Q>>(
|
||||
root: NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
|
||||
range: R,
|
||||
) -> (
|
||||
Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>,
|
||||
Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>,
|
||||
)
|
||||
where
|
||||
Q: Ord,
|
||||
K: Borrow<Q>,
|
||||
{
|
||||
match (range.start_bound(), range.end_bound()) {
|
||||
(Excluded(s), Excluded(e)) if s == e => {
|
||||
panic!("range start and end are equal and excluded in BTreeMap")
|
||||
}
|
||||
(Included(s) | Excluded(s), Included(e) | Excluded(e)) if s > e => {
|
||||
panic!("range start is greater than range end in BTreeMap")
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
// We duplicate the root NodeRef here -- we will never access it in a way
|
||||
// that overlaps references obtained from the root.
|
||||
let mut min_node = unsafe { ptr::read(&root) };
|
||||
let mut max_node = root;
|
||||
let mut min_found = false;
|
||||
let mut max_found = false;
|
||||
|
||||
loop {
|
||||
let front = match (min_found, range.start_bound()) {
|
||||
(false, Included(key)) => match search::search_node(min_node, key) {
|
||||
Found(kv) => {
|
||||
min_found = true;
|
||||
kv.left_edge()
|
||||
}
|
||||
GoDown(edge) => edge,
|
||||
},
|
||||
(false, Excluded(key)) => match search::search_node(min_node, key) {
|
||||
Found(kv) => {
|
||||
min_found = true;
|
||||
kv.right_edge()
|
||||
}
|
||||
GoDown(edge) => edge,
|
||||
},
|
||||
(true, Included(_)) => min_node.last_edge(),
|
||||
(true, Excluded(_)) => min_node.first_edge(),
|
||||
(_, Unbounded) => min_node.first_edge(),
|
||||
};
|
||||
|
||||
let back = match (max_found, range.end_bound()) {
|
||||
(false, Included(key)) => match search::search_node(max_node, key) {
|
||||
Found(kv) => {
|
||||
max_found = true;
|
||||
kv.right_edge()
|
||||
}
|
||||
GoDown(edge) => edge,
|
||||
},
|
||||
(false, Excluded(key)) => match search::search_node(max_node, key) {
|
||||
Found(kv) => {
|
||||
max_found = true;
|
||||
kv.left_edge()
|
||||
}
|
||||
GoDown(edge) => edge,
|
||||
},
|
||||
(true, Included(_)) => max_node.first_edge(),
|
||||
(true, Excluded(_)) => max_node.last_edge(),
|
||||
(_, Unbounded) => max_node.last_edge(),
|
||||
};
|
||||
|
||||
if front.partial_cmp(&back) == Some(Ordering::Greater) {
|
||||
panic!("Ord is ill-defined in BTreeMap range");
|
||||
}
|
||||
match (front.force(), back.force()) {
|
||||
(Leaf(f), Leaf(b)) => {
|
||||
return (f, b);
|
||||
}
|
||||
(Internal(min_int), Internal(max_int)) => {
|
||||
min_node = min_int.descend();
|
||||
max_node = max_int.descend();
|
||||
}
|
||||
_ => unreachable!("BTreeMap has different depths"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Equivalent to `range_search(k, v, ..)` without the `Ord` bound.
|
||||
fn full_range_search<BorrowType, K, V>(
|
||||
root: NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
|
||||
) -> (
|
||||
Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>,
|
||||
Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>,
|
||||
) {
|
||||
// We duplicate the root NodeRef here -- we will never access it in a way
|
||||
// that overlaps references obtained from the root.
|
||||
let mut min_node = unsafe { ptr::read(&root) };
|
||||
let mut max_node = root;
|
||||
loop {
|
||||
let front = min_node.first_edge();
|
||||
let back = max_node.last_edge();
|
||||
match (front.force(), back.force()) {
|
||||
(Leaf(f), Leaf(b)) => {
|
||||
return (f, b);
|
||||
}
|
||||
(Internal(min_int), Internal(max_int)) => {
|
||||
min_node = min_int.descend();
|
||||
max_node = max_int.descend();
|
||||
}
|
||||
_ => unreachable!("BTreeMap has different depths"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> BTreeMap<K, V> {
|
||||
/// Gets an iterator over the entries of the map, sorted by key.
|
||||
///
|
||||
@ -2211,7 +2097,7 @@ impl<K, V> BTreeMap<K, V> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn iter(&self) -> Iter<'_, K, V> {
|
||||
if let Some(root) = &self.root {
|
||||
let (f, b) = full_range_search(root.node_as_ref());
|
||||
let (f, b) = root.node_as_ref().full_range();
|
||||
|
||||
Iter { range: Range { front: Some(f), back: Some(b) }, length: self.length }
|
||||
} else {
|
||||
@ -2243,7 +2129,7 @@ impl<K, V> BTreeMap<K, V> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
|
||||
if let Some(root) = &mut self.root {
|
||||
let (f, b) = full_range_search(root.node_as_mut());
|
||||
let (f, b) = root.node_as_valmut().full_range();
|
||||
|
||||
IterMut {
|
||||
range: RangeMut { front: Some(f), back: Some(b), _marker: PhantomData },
|
||||
@ -2826,7 +2712,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInter
|
||||
if stole_from_left && at_leaf {
|
||||
// SAFETY: This is safe since we just added an element to our node.
|
||||
unsafe {
|
||||
pos.next_unchecked();
|
||||
pos.move_next_unchecked();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1,10 +1,210 @@
|
||||
use core::borrow::Borrow;
|
||||
use core::cmp::Ordering;
|
||||
use core::intrinsics;
|
||||
use core::mem;
|
||||
use core::ops::Bound::{Excluded, Included, Unbounded};
|
||||
use core::ops::RangeBounds;
|
||||
use core::ptr;
|
||||
|
||||
use super::node::{marker, ForceResult::*, Handle, NodeRef};
|
||||
use super::search::{self, SearchResult};
|
||||
use super::unwrap_unchecked;
|
||||
|
||||
/// Finds the leaf edges delimiting a specified range in or underneath a node.
|
||||
fn range_search<BorrowType, K, V, Q, R>(
|
||||
root1: NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
|
||||
root2: NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
|
||||
range: R,
|
||||
) -> (
|
||||
Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>,
|
||||
Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>,
|
||||
)
|
||||
where
|
||||
Q: ?Sized + Ord,
|
||||
K: Borrow<Q>,
|
||||
R: RangeBounds<Q>,
|
||||
{
|
||||
match (range.start_bound(), range.end_bound()) {
|
||||
(Excluded(s), Excluded(e)) if s == e => {
|
||||
panic!("range start and end are equal and excluded in BTreeMap")
|
||||
}
|
||||
(Included(s) | Excluded(s), Included(e) | Excluded(e)) if s > e => {
|
||||
panic!("range start is greater than range end in BTreeMap")
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
let mut min_node = root1;
|
||||
let mut max_node = root2;
|
||||
let mut min_found = false;
|
||||
let mut max_found = false;
|
||||
|
||||
loop {
|
||||
let front = match (min_found, range.start_bound()) {
|
||||
(false, Included(key)) => match search::search_node(min_node, key) {
|
||||
SearchResult::Found(kv) => {
|
||||
min_found = true;
|
||||
kv.left_edge()
|
||||
}
|
||||
SearchResult::GoDown(edge) => edge,
|
||||
},
|
||||
(false, Excluded(key)) => match search::search_node(min_node, key) {
|
||||
SearchResult::Found(kv) => {
|
||||
min_found = true;
|
||||
kv.right_edge()
|
||||
}
|
||||
SearchResult::GoDown(edge) => edge,
|
||||
},
|
||||
(true, Included(_)) => min_node.last_edge(),
|
||||
(true, Excluded(_)) => min_node.first_edge(),
|
||||
(_, Unbounded) => min_node.first_edge(),
|
||||
};
|
||||
|
||||
let back = match (max_found, range.end_bound()) {
|
||||
(false, Included(key)) => match search::search_node(max_node, key) {
|
||||
SearchResult::Found(kv) => {
|
||||
max_found = true;
|
||||
kv.right_edge()
|
||||
}
|
||||
SearchResult::GoDown(edge) => edge,
|
||||
},
|
||||
(false, Excluded(key)) => match search::search_node(max_node, key) {
|
||||
SearchResult::Found(kv) => {
|
||||
max_found = true;
|
||||
kv.left_edge()
|
||||
}
|
||||
SearchResult::GoDown(edge) => edge,
|
||||
},
|
||||
(true, Included(_)) => max_node.first_edge(),
|
||||
(true, Excluded(_)) => max_node.last_edge(),
|
||||
(_, Unbounded) => max_node.last_edge(),
|
||||
};
|
||||
|
||||
if front.partial_cmp(&back) == Some(Ordering::Greater) {
|
||||
panic!("Ord is ill-defined in BTreeMap range");
|
||||
}
|
||||
match (front.force(), back.force()) {
|
||||
(Leaf(f), Leaf(b)) => {
|
||||
return (f, b);
|
||||
}
|
||||
(Internal(min_int), Internal(max_int)) => {
|
||||
min_node = min_int.descend();
|
||||
max_node = max_int.descend();
|
||||
}
|
||||
_ => unreachable!("BTreeMap has different depths"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Equivalent to `range_search(k, v, ..)` but without the `Ord` bound.
|
||||
fn full_range<BorrowType, K, V>(
|
||||
root1: NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
|
||||
root2: NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
|
||||
) -> (
|
||||
Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>,
|
||||
Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>,
|
||||
) {
|
||||
let mut min_node = root1;
|
||||
let mut max_node = root2;
|
||||
loop {
|
||||
let front = min_node.first_edge();
|
||||
let back = max_node.last_edge();
|
||||
match (front.force(), back.force()) {
|
||||
(Leaf(f), Leaf(b)) => {
|
||||
return (f, b);
|
||||
}
|
||||
(Internal(min_int), Internal(max_int)) => {
|
||||
min_node = min_int.descend();
|
||||
max_node = max_int.descend();
|
||||
}
|
||||
_ => unreachable!("BTreeMap has different depths"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal> {
|
||||
/// Creates a pair of leaf edges delimiting a specified range in or underneath a node.
|
||||
pub fn range_search<Q, R>(
|
||||
self,
|
||||
range: R,
|
||||
) -> (
|
||||
Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Edge>,
|
||||
Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Edge>,
|
||||
)
|
||||
where
|
||||
Q: ?Sized + Ord,
|
||||
K: Borrow<Q>,
|
||||
R: RangeBounds<Q>,
|
||||
{
|
||||
range_search(self, self, range)
|
||||
}
|
||||
|
||||
/// Returns (self.first_leaf_edge(), self.last_leaf_edge()), but more efficiently.
|
||||
pub fn full_range(
|
||||
self,
|
||||
) -> (
|
||||
Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Edge>,
|
||||
Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Edge>,
|
||||
) {
|
||||
full_range(self, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: 'a, V: 'a> NodeRef<marker::ValMut<'a>, K, V, marker::LeafOrInternal> {
|
||||
/// Splits a unique reference into a pair of leaf edges delimiting a specified range.
|
||||
/// The result are non-unique references allowing (some) mutation, which must be used
|
||||
/// carefully.
|
||||
pub fn range_search<Q, R>(
|
||||
self,
|
||||
range: R,
|
||||
) -> (
|
||||
Handle<NodeRef<marker::ValMut<'a>, K, V, marker::Leaf>, marker::Edge>,
|
||||
Handle<NodeRef<marker::ValMut<'a>, K, V, marker::Leaf>, marker::Edge>,
|
||||
)
|
||||
where
|
||||
Q: ?Sized + Ord,
|
||||
K: Borrow<Q>,
|
||||
R: RangeBounds<Q>,
|
||||
{
|
||||
// We duplicate the root NodeRef here -- we will never visit the same KV
|
||||
// twice, and never end up with overlapping value references.
|
||||
let self2 = unsafe { ptr::read(&self) };
|
||||
range_search(self, self2, range)
|
||||
}
|
||||
|
||||
/// Splits a unique reference into a pair of leaf edges delimiting the full range of the tree.
|
||||
/// The results are non-unique references allowing mutation (of values only), so must be used
|
||||
/// with care.
|
||||
pub fn full_range(
|
||||
self,
|
||||
) -> (
|
||||
Handle<NodeRef<marker::ValMut<'a>, K, V, marker::Leaf>, marker::Edge>,
|
||||
Handle<NodeRef<marker::ValMut<'a>, K, V, marker::Leaf>, marker::Edge>,
|
||||
) {
|
||||
// We duplicate the root NodeRef here -- we will never visit the same KV
|
||||
// twice, and never end up with overlapping value references.
|
||||
let self2 = unsafe { ptr::read(&self) };
|
||||
full_range(self, self2)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
|
||||
/// Splits a unique reference into a pair of leaf edges delimiting the full range of the tree.
|
||||
/// The results are non-unique references allowing massively destructive mutation, so must be
|
||||
/// used with the utmost care.
|
||||
pub fn full_range(
|
||||
self,
|
||||
) -> (
|
||||
Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge>,
|
||||
Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge>,
|
||||
) {
|
||||
// We duplicate the root NodeRef here -- we will never access it in a way
|
||||
// that overlaps references obtained from the root.
|
||||
let self2 = unsafe { ptr::read(&self) };
|
||||
full_range(self, self2)
|
||||
}
|
||||
}
|
||||
|
||||
impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
|
||||
/// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV
|
||||
/// on the right side, which is either in the same leaf node or in an ancestor node.
|
||||
@ -75,12 +275,13 @@ impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Internal>, marke
|
||||
macro_rules! def_next_kv_uncheched_dealloc {
|
||||
{ unsafe fn $name:ident : $adjacent_kv:ident } => {
|
||||
/// Given a leaf edge handle into an owned tree, returns a handle to the next KV,
|
||||
/// while deallocating any node left behind.
|
||||
/// Unsafe for two reasons:
|
||||
/// - The caller must ensure that the leaf edge is not the last one in the tree.
|
||||
/// - The node pointed at by the given handle, and its ancestors, may be deallocated,
|
||||
/// while the reference to those nodes in the surviving ancestors is left dangling;
|
||||
/// thus using the returned handle to navigate further is dangerous.
|
||||
/// while deallocating any node left behind yet leaving the corresponding edge
|
||||
/// in its parent node dangling.
|
||||
///
|
||||
/// # Safety
|
||||
/// - The leaf edge must not be the last one in the direction travelled.
|
||||
/// - The node carrying the next KV returned must not have been deallocated by a
|
||||
/// previous call on any handle obtained for this tree.
|
||||
unsafe fn $name <K, V>(
|
||||
leaf_edge: Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge>,
|
||||
) -> Handle<NodeRef<marker::Owned, K, V, marker::LeafOrInternal>, marker::KV> {
|
||||
@ -103,6 +304,15 @@ macro_rules! def_next_kv_uncheched_dealloc {
|
||||
def_next_kv_uncheched_dealloc! {unsafe fn next_kv_unchecked_dealloc: right_kv}
|
||||
def_next_kv_uncheched_dealloc! {unsafe fn next_back_kv_unchecked_dealloc: left_kv}
|
||||
|
||||
/// This replaces the value behind the `v` unique reference by calling the
|
||||
/// relevant function.
|
||||
///
|
||||
/// If a panic occurs in the `change` closure, the entire process will be aborted.
|
||||
#[inline]
|
||||
fn take_mut<T>(v: &mut T, change: impl FnOnce(T) -> T) {
|
||||
replace(v, |value| (change(value), ()))
|
||||
}
|
||||
|
||||
/// This replaces the value behind the `v` unique reference by calling the
|
||||
/// relevant function, and returns a result obtained along the way.
|
||||
///
|
||||
@ -128,7 +338,9 @@ fn replace<T, R>(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R {
|
||||
impl<'a, K, V> Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Edge> {
|
||||
/// Moves the leaf edge handle to the next leaf edge and returns references to the
|
||||
/// key and value in between.
|
||||
/// Unsafe because the caller must ensure that the leaf edge is not the last one in the tree.
|
||||
///
|
||||
/// # Safety
|
||||
/// There must be another KV in the direction travelled.
|
||||
pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
|
||||
replace(self, |leaf_edge| {
|
||||
let kv = leaf_edge.next_kv();
|
||||
@ -139,7 +351,9 @@ impl<'a, K, V> Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Ed
|
||||
|
||||
/// Moves the leaf edge handle to the previous leaf edge and returns references to the
|
||||
/// key and value in between.
|
||||
/// Unsafe because the caller must ensure that the leaf edge is not the first one in the tree.
|
||||
///
|
||||
/// # Safety
|
||||
/// There must be another KV in the direction travelled.
|
||||
pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) {
|
||||
replace(self, |leaf_edge| {
|
||||
let kv = leaf_edge.next_back_kv();
|
||||
@ -149,53 +363,69 @@ impl<'a, K, V> Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Ed
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge> {
|
||||
impl<'a, K, V> Handle<NodeRef<marker::ValMut<'a>, K, V, marker::Leaf>, marker::Edge> {
|
||||
/// Moves the leaf edge handle to the next leaf edge and returns references to the
|
||||
/// key and value in between.
|
||||
/// Unsafe for two reasons:
|
||||
/// - The caller must ensure that the leaf edge is not the last one in the tree.
|
||||
/// - Using the updated handle may well invalidate the returned references.
|
||||
pub unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
|
||||
/// The returned references might be invalidated when the updated handle is used again.
|
||||
///
|
||||
/// # Safety
|
||||
/// There must be another KV in the direction travelled.
|
||||
pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) {
|
||||
let kv = replace(self, |leaf_edge| {
|
||||
let kv = leaf_edge.next_kv();
|
||||
let kv = unsafe { unwrap_unchecked(kv.ok()) };
|
||||
(unsafe { ptr::read(&kv) }.next_leaf_edge(), kv)
|
||||
});
|
||||
// Doing the descend (and perhaps another move) invalidates the references
|
||||
// returned by `into_kv_mut`, so we have to do this last.
|
||||
kv.into_kv_mut()
|
||||
// returned by `into_kv_valmut`, so we have to do this last.
|
||||
kv.into_kv_valmut()
|
||||
}
|
||||
|
||||
/// Moves the leaf edge handle to the previous leaf and returns references to the
|
||||
/// key and value in between.
|
||||
/// Unsafe for two reasons:
|
||||
/// - The caller must ensure that the leaf edge is not the first one in the tree.
|
||||
/// - Using the updated handle may well invalidate the returned references.
|
||||
pub unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
|
||||
/// The returned references might be invalidated when the updated handle is used again.
|
||||
///
|
||||
/// # Safety
|
||||
/// There must be another KV in the direction travelled.
|
||||
pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) {
|
||||
let kv = replace(self, |leaf_edge| {
|
||||
let kv = leaf_edge.next_back_kv();
|
||||
let kv = unsafe { unwrap_unchecked(kv.ok()) };
|
||||
(unsafe { ptr::read(&kv) }.next_back_leaf_edge(), kv)
|
||||
});
|
||||
// Doing the descend (and perhaps another move) invalidates the references
|
||||
// returned by `into_kv_mut`, so we have to do this last.
|
||||
kv.into_kv_mut()
|
||||
// returned by `into_kv_valmut`, so we have to do this last.
|
||||
kv.into_kv_valmut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge> {
|
||||
/// Moves the leaf edge handle to the next leaf edge.
|
||||
///
|
||||
/// # Safety
|
||||
/// There must be another KV in the direction travelled.
|
||||
pub unsafe fn move_next_unchecked(&mut self) {
|
||||
take_mut(self, |leaf_edge| {
|
||||
let kv = leaf_edge.next_kv();
|
||||
let kv = unsafe { unwrap_unchecked(kv.ok()) };
|
||||
kv.next_leaf_edge()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge> {
|
||||
/// Moves the leaf edge handle to the next leaf edge and returns the key and value
|
||||
/// in between, while deallocating any node left behind.
|
||||
/// Unsafe for two reasons:
|
||||
/// - The caller must ensure that the leaf edge is not the last one in the tree
|
||||
/// and is not a handle previously resulting from counterpart `next_back_unchecked`.
|
||||
/// - Further use of the updated leaf edge handle is very dangerous. In particular,
|
||||
/// if the leaf edge is the last edge of a node, that node and possibly ancestors
|
||||
/// will be deallocated, while the reference to those nodes in the surviving ancestor
|
||||
/// is left dangling.
|
||||
/// The only safe way to proceed with the updated handle is to compare it, drop it,
|
||||
/// call this method again subject to both preconditions listed in the first point,
|
||||
/// or call counterpart `next_back_unchecked` subject to its preconditions.
|
||||
/// in between, deallocating any node left behind while leaving the corresponding
|
||||
/// edge in its parent node dangling.
|
||||
///
|
||||
/// # Safety
|
||||
/// - There must be another KV in the direction travelled.
|
||||
/// - That KV was not previously returned by counterpart `next_back_unchecked`
|
||||
/// on any copy of the handles being used to traverse the tree.
|
||||
///
|
||||
/// The only safe way to proceed with the updated handle is to compare it, drop it,
|
||||
/// call this method again subject to its safety conditions, or call counterpart
|
||||
/// `next_back_unchecked` subject to its safety conditions.
|
||||
pub unsafe fn next_unchecked(&mut self) -> (K, V) {
|
||||
replace(self, |leaf_edge| {
|
||||
let kv = unsafe { next_kv_unchecked_dealloc(leaf_edge) };
|
||||
@ -205,18 +435,18 @@ impl<K, V> Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Moves the leaf edge handle to the previous leaf edge and returns the key
|
||||
/// and value in between, while deallocating any node left behind.
|
||||
/// Unsafe for two reasons:
|
||||
/// - The caller must ensure that the leaf edge is not the first one in the tree
|
||||
/// and is not a handle previously resulting from counterpart `next_unchecked`.
|
||||
/// - Further use of the updated leaf edge handle is very dangerous. In particular,
|
||||
/// if the leaf edge is the first edge of a node, that node and possibly ancestors
|
||||
/// will be deallocated, while the reference to those nodes in the surviving ancestor
|
||||
/// is left dangling.
|
||||
/// The only safe way to proceed with the updated handle is to compare it, drop it,
|
||||
/// call this method again subject to both preconditions listed in the first point,
|
||||
/// or call counterpart `next_unchecked` subject to its preconditions.
|
||||
/// Moves the leaf edge handle to the previous leaf edge and returns the key and value
|
||||
/// in between, deallocating any node left behind while leaving the corresponding
|
||||
/// edge in its parent node dangling.
|
||||
///
|
||||
/// # Safety
|
||||
/// - There must be another KV in the direction travelled.
|
||||
/// - That leaf edge was not previously returned by counterpart `next_unchecked`
|
||||
/// on any copy of the handles being used to traverse the tree.
|
||||
///
|
||||
/// The only safe way to proceed with the updated handle is to compare it, drop it,
|
||||
/// call this method again subject to its safety conditions, or call counterpart
|
||||
/// `next_unchecked` subject to its safety conditions.
|
||||
pub unsafe fn next_back_unchecked(&mut self) -> (K, V) {
|
||||
replace(self, |leaf_edge| {
|
||||
let kv = unsafe { next_back_kv_unchecked_dealloc(leaf_edge) };
|
||||
|
@ -186,6 +186,15 @@ impl<K, V> Root<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn node_as_valmut(&mut self) -> NodeRef<marker::ValMut<'_>, K, V, marker::LeafOrInternal> {
|
||||
NodeRef {
|
||||
height: self.height,
|
||||
node: self.node.as_ptr(),
|
||||
root: ptr::null(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_ref(self) -> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
|
||||
NodeRef {
|
||||
height: self.height,
|
||||
@ -253,9 +262,12 @@ impl<K, V> Root<K, V> {
|
||||
/// A reference to a node.
|
||||
///
|
||||
/// This type has a number of parameters that controls how it acts:
|
||||
/// - `BorrowType`: This can be `Immut<'a>` or `Mut<'a>` for some `'a` or `Owned`.
|
||||
/// - `BorrowType`: This can be `Immut<'a>`, `Mut<'a>` or `ValMut<'a>' for some `'a`
|
||||
/// or `Owned`.
|
||||
/// When this is `Immut<'a>`, the `NodeRef` acts roughly like `&'a Node`,
|
||||
/// when this is `Mut<'a>`, the `NodeRef` acts roughly like `&'a mut Node`,
|
||||
/// when this is `ValMut<'a>`, the `NodeRef` acts as immutable with respect
|
||||
/// to keys and tree structure, but allows mutable references to values,
|
||||
/// and when this is `Owned`, the `NodeRef` acts roughly like `Box<Node>`.
|
||||
/// - `K` and `V`: These control what types of things are stored in the nodes.
|
||||
/// - `Type`: This can be `Leaf`, `Internal`, or `LeafOrInternal`. When this is
|
||||
@ -282,6 +294,7 @@ unsafe impl<BorrowType, K: Sync, V: Sync, Type> Sync for NodeRef<BorrowType, K,
|
||||
|
||||
unsafe impl<'a, K: Sync + 'a, V: Sync + 'a, Type> Send for NodeRef<marker::Immut<'a>, K, V, Type> {}
|
||||
unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef<marker::Mut<'a>, K, V, Type> {}
|
||||
unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef<marker::ValMut<'a>, K, V, Type> {}
|
||||
unsafe impl<K: Send, V: Send, Type> Send for NodeRef<marker::Owned, K, V, Type> {}
|
||||
|
||||
impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Internal> {
|
||||
@ -515,6 +528,22 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::ValMut<'a>, K, V, Type> {
|
||||
/// Same as the marker::Mut method, but far more dangerous because ValMut-based iterators:
|
||||
/// - have front and back handles often refering to the same node, so `self` is not unique;
|
||||
/// - hand out mutable references to parts of these slices to the public.
|
||||
fn into_slices_mut(self) -> (&'a [K], &'a mut [V]) {
|
||||
let len = self.len();
|
||||
let leaf = self.node.as_ptr();
|
||||
// SAFETY: The keys and values of a node must always be initialized up to length.
|
||||
let keys = unsafe { slice::from_raw_parts(MaybeUninit::first_ptr(&(*leaf).keys), len) };
|
||||
let vals = unsafe {
|
||||
slice::from_raw_parts_mut(MaybeUninit::first_ptr_mut(&mut (*leaf).vals), len)
|
||||
};
|
||||
(keys, vals)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
|
||||
/// Adds a key/value pair to the end of the node.
|
||||
pub fn push(&mut self, key: K, val: V) {
|
||||
@ -1053,11 +1082,13 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>
|
||||
let vals = self.node.into_val_slice_mut();
|
||||
unsafe { vals.get_unchecked_mut(self.idx) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_kv_mut(self) -> (&'a mut K, &'a mut V) {
|
||||
impl<'a, K, V, NodeType> Handle<NodeRef<marker::ValMut<'a>, K, V, NodeType>, marker::KV> {
|
||||
pub fn into_kv_valmut(self) -> (&'a K, &'a mut V) {
|
||||
unsafe {
|
||||
let (keys, vals) = self.node.into_slices_mut();
|
||||
(keys.get_unchecked_mut(self.idx), vals.get_unchecked_mut(self.idx))
|
||||
(keys.get_unchecked(self.idx), vals.get_unchecked_mut(self.idx))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1558,6 +1589,7 @@ pub mod marker {
|
||||
pub enum Owned {}
|
||||
pub struct Immut<'a>(PhantomData<&'a ()>);
|
||||
pub struct Mut<'a>(PhantomData<&'a mut ()>);
|
||||
pub struct ValMut<'a>(PhantomData<&'a mut ()>);
|
||||
|
||||
pub enum KV {}
|
||||
pub enum Edge {}
|
||||
|
Loading…
Reference in New Issue
Block a user