Skip to content

Commit 70c5f6e

Browse files
committed
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
2 parents c59199e + e5f9d7f commit 70c5f6e

File tree

3 files changed

+319
-171
lines changed

3 files changed

+319
-171
lines changed

library/alloc/src/collections/btree/map.rs

+10-124
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use core::hash::{Hash, Hasher};
55
use core::iter::{FromIterator, FusedIterator, Peekable};
66
use core::marker::PhantomData;
77
use core::mem::{self, ManuallyDrop};
8-
use core::ops::Bound::{Excluded, Included, Unbounded};
98
use core::ops::{Index, RangeBounds};
109
use core::ptr;
1110

@@ -408,8 +407,8 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for Range<'_, K, V> {
408407
/// [`range_mut`]: BTreeMap::range_mut
409408
#[stable(feature = "btree_range", since = "1.17.0")]
410409
pub struct RangeMut<'a, K: 'a, V: 'a> {
411-
front: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
412-
back: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
410+
front: Option<Handle<NodeRef<marker::ValMut<'a>, K, V, marker::Leaf>, marker::Edge>>,
411+
back: Option<Handle<NodeRef<marker::ValMut<'a>, K, V, marker::Leaf>, marker::Edge>>,
413412

414413
// Be invariant in `K` and `V`
415414
_marker: PhantomData<&'a mut (K, V)>,
@@ -999,7 +998,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
999998
R: RangeBounds<T>,
1000999
{
10011000
if let Some(root) = &self.root {
1002-
let (f, b) = range_search(root.node_as_ref(), range);
1001+
let (f, b) = root.node_as_ref().range_search(range);
10031002

10041003
Range { front: Some(f), back: Some(b) }
10051004
} else {
@@ -1045,7 +1044,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
10451044
R: RangeBounds<T>,
10461045
{
10471046
if let Some(root) = &mut self.root {
1048-
let (f, b) = range_search(root.node_as_mut(), range);
1047+
let (f, b) = root.node_as_valmut().range_search(range);
10491048

10501049
RangeMut { front: Some(f), back: Some(b), _marker: PhantomData }
10511050
} else {
@@ -1478,7 +1477,7 @@ impl<K, V> IntoIterator for BTreeMap<K, V> {
14781477
fn into_iter(self) -> IntoIter<K, V> {
14791478
let mut me = ManuallyDrop::new(self);
14801479
if let Some(root) = me.root.take() {
1481-
let (f, b) = full_range_search(root.into_ref());
1480+
let (f, b) = root.into_ref().full_range();
14821481

14831482
IntoIter { front: Some(f), back: Some(b), length: me.length }
14841483
} else {
@@ -1942,7 +1941,7 @@ impl<'a, K, V> RangeMut<'a, K, V> {
19421941
self.front == self.back
19431942
}
19441943

1945-
unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
1944+
unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) {
19461945
unsafe { unwrap_unchecked(self.front.as_mut()).next_unchecked() }
19471946
}
19481947
}
@@ -1963,7 +1962,7 @@ impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> {
19631962
impl<K, V> FusedIterator for RangeMut<'_, K, V> {}
19641963

19651964
impl<'a, K, V> RangeMut<'a, K, V> {
1966-
unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
1965+
unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) {
19671966
unsafe { unwrap_unchecked(self.back.as_mut()).next_back_unchecked() }
19681967
}
19691968
}
@@ -2073,119 +2072,6 @@ where
20732072
}
20742073
}
20752074

2076-
/// Finds the leaf edges delimiting a specified range in or underneath a node.
2077-
fn range_search<BorrowType, K, V, Q: ?Sized, R: RangeBounds<Q>>(
2078-
root: NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
2079-
range: R,
2080-
) -> (
2081-
Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>,
2082-
Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>,
2083-
)
2084-
where
2085-
Q: Ord,
2086-
K: Borrow<Q>,
2087-
{
2088-
match (range.start_bound(), range.end_bound()) {
2089-
(Excluded(s), Excluded(e)) if s == e => {
2090-
panic!("range start and end are equal and excluded in BTreeMap")
2091-
}
2092-
(Included(s) | Excluded(s), Included(e) | Excluded(e)) if s > e => {
2093-
panic!("range start is greater than range end in BTreeMap")
2094-
}
2095-
_ => {}
2096-
};
2097-
2098-
// We duplicate the root NodeRef here -- we will never access it in a way
2099-
// that overlaps references obtained from the root.
2100-
let mut min_node = unsafe { ptr::read(&root) };
2101-
let mut max_node = root;
2102-
let mut min_found = false;
2103-
let mut max_found = false;
2104-
2105-
loop {
2106-
let front = match (min_found, range.start_bound()) {
2107-
(false, Included(key)) => match search::search_node(min_node, key) {
2108-
Found(kv) => {
2109-
min_found = true;
2110-
kv.left_edge()
2111-
}
2112-
GoDown(edge) => edge,
2113-
},
2114-
(false, Excluded(key)) => match search::search_node(min_node, key) {
2115-
Found(kv) => {
2116-
min_found = true;
2117-
kv.right_edge()
2118-
}
2119-
GoDown(edge) => edge,
2120-
},
2121-
(true, Included(_)) => min_node.last_edge(),
2122-
(true, Excluded(_)) => min_node.first_edge(),
2123-
(_, Unbounded) => min_node.first_edge(),
2124-
};
2125-
2126-
let back = match (max_found, range.end_bound()) {
2127-
(false, Included(key)) => match search::search_node(max_node, key) {
2128-
Found(kv) => {
2129-
max_found = true;
2130-
kv.right_edge()
2131-
}
2132-
GoDown(edge) => edge,
2133-
},
2134-
(false, Excluded(key)) => match search::search_node(max_node, key) {
2135-
Found(kv) => {
2136-
max_found = true;
2137-
kv.left_edge()
2138-
}
2139-
GoDown(edge) => edge,
2140-
},
2141-
(true, Included(_)) => max_node.first_edge(),
2142-
(true, Excluded(_)) => max_node.last_edge(),
2143-
(_, Unbounded) => max_node.last_edge(),
2144-
};
2145-
2146-
if front.partial_cmp(&back) == Some(Ordering::Greater) {
2147-
panic!("Ord is ill-defined in BTreeMap range");
2148-
}
2149-
match (front.force(), back.force()) {
2150-
(Leaf(f), Leaf(b)) => {
2151-
return (f, b);
2152-
}
2153-
(Internal(min_int), Internal(max_int)) => {
2154-
min_node = min_int.descend();
2155-
max_node = max_int.descend();
2156-
}
2157-
_ => unreachable!("BTreeMap has different depths"),
2158-
};
2159-
}
2160-
}
2161-
2162-
/// Equivalent to `range_search(k, v, ..)` without the `Ord` bound.
2163-
fn full_range_search<BorrowType, K, V>(
2164-
root: NodeRef<BorrowType, K, V, marker::LeafOrInternal>,
2165-
) -> (
2166-
Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>,
2167-
Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>,
2168-
) {
2169-
// We duplicate the root NodeRef here -- we will never access it in a way
2170-
// that overlaps references obtained from the root.
2171-
let mut min_node = unsafe { ptr::read(&root) };
2172-
let mut max_node = root;
2173-
loop {
2174-
let front = min_node.first_edge();
2175-
let back = max_node.last_edge();
2176-
match (front.force(), back.force()) {
2177-
(Leaf(f), Leaf(b)) => {
2178-
return (f, b);
2179-
}
2180-
(Internal(min_int), Internal(max_int)) => {
2181-
min_node = min_int.descend();
2182-
max_node = max_int.descend();
2183-
}
2184-
_ => unreachable!("BTreeMap has different depths"),
2185-
};
2186-
}
2187-
}
2188-
21892075
impl<K, V> BTreeMap<K, V> {
21902076
/// Gets an iterator over the entries of the map, sorted by key.
21912077
///
@@ -2211,7 +2097,7 @@ impl<K, V> BTreeMap<K, V> {
22112097
#[stable(feature = "rust1", since = "1.0.0")]
22122098
pub fn iter(&self) -> Iter<'_, K, V> {
22132099
if let Some(root) = &self.root {
2214-
let (f, b) = full_range_search(root.node_as_ref());
2100+
let (f, b) = root.node_as_ref().full_range();
22152101

22162102
Iter { range: Range { front: Some(f), back: Some(b) }, length: self.length }
22172103
} else {
@@ -2243,7 +2129,7 @@ impl<K, V> BTreeMap<K, V> {
22432129
#[stable(feature = "rust1", since = "1.0.0")]
22442130
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
22452131
if let Some(root) = &mut self.root {
2246-
let (f, b) = full_range_search(root.node_as_mut());
2132+
let (f, b) = root.node_as_valmut().full_range();
22472133

22482134
IterMut {
22492135
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
28262712
if stole_from_left && at_leaf {
28272713
// SAFETY: This is safe since we just added an element to our node.
28282714
unsafe {
2829-
pos.next_unchecked();
2715+
pos.move_next_unchecked();
28302716
}
28312717
}
28322718
break;

0 commit comments

Comments
 (0)