Skip to content

Commit 577a229

Browse files
committed
BTreeMap: pull the map's root out of NodeRef
1 parent 443e177 commit 577a229

File tree

5 files changed

+162
-111
lines changed

5 files changed

+162
-111
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use core::marker::PhantomData;
2+
use core::ptr::NonNull;
3+
4+
/// Models a reborrow of some unique reference, when you know that the reborrow
5+
/// and all its descendants (i.e., all pointers and references derived from it)
6+
/// will not be used any more at some point, after which you want to use the
7+
/// original unique reference again.
8+
///
9+
/// The borrow checker usually handles this stacking of borrows for you, but
10+
/// some control flows that accomplish this stacking are too complicated for
11+
/// the compiler to follow. A `DormantMutRef` allows you to check borrowing
12+
/// yourself, while still expressing its stacked nature, and encapsulating
13+
/// the raw pointer code needed to do this without undefined behavior.
14+
pub struct DormantMutRef<'a, T> {
15+
ptr: NonNull<T>,
16+
_marker: PhantomData<&'a mut T>,
17+
}
18+
19+
impl<'a, T> DormantMutRef<'a, T> {
20+
/// Capture a unique borrow, and immediately reborrow it. For the compiler,
21+
/// the lifetime of the new reference is the same as the lifetime of the
22+
/// original reference, but you promise to use it for a shorter period.
23+
pub fn new(t: &'a mut T) -> (&'a mut T, Self) {
24+
let ptr = NonNull::from(t);
25+
// SAFETY: we hold the borrow throughout 'a via `_marker`, and we expose
26+
// only this reference, so it is unique.
27+
let new_ref = unsafe { &mut *ptr.as_ptr() };
28+
(new_ref, Self { ptr, _marker: PhantomData })
29+
}
30+
31+
/// Revert to the unique borrow initially captured.
32+
///
33+
/// # Safety
34+
///
35+
/// The reborrow must have ended, i.e., the reference returned by `new` and
36+
/// all pointers and references derived from it, must not be used anymore.
37+
pub unsafe fn awaken(self) -> &'a mut T {
38+
// SAFETY: our own safety conditions imply this reference is again unique.
39+
unsafe { &mut *self.ptr.as_ptr() }
40+
}
41+
}
42+
43+
#[cfg(test)]
44+
mod tests;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use super::DormantMutRef;
2+
3+
#[test]
4+
fn test_borrow() {
5+
let mut data = 1;
6+
let mut stack = vec![];
7+
let mut rr = &mut data;
8+
for factor in [2, 3, 7].iter() {
9+
let (r, dormant_r) = DormantMutRef::new(rr);
10+
rr = r;
11+
assert_eq!(*rr, 1);
12+
stack.push((factor, dormant_r));
13+
}
14+
while let Some((factor, dormant_r)) = stack.pop() {
15+
let r = unsafe { dormant_r.awaken() };
16+
*r *= factor;
17+
}
18+
assert_eq!(data, 42);
19+
}

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

+72-49
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use core::ops::Bound::{Excluded, Included, Unbounded};
99
use core::ops::{Index, RangeBounds};
1010
use core::ptr;
1111

12+
use super::borrow::DormantMutRef;
1213
use super::node::{self, marker, ForceResult::*, Handle, InsertResult::*, NodeRef};
1314
use super::search::{self, SearchResult::*};
1415
use super::unwrap_unchecked;
@@ -229,24 +230,23 @@ where
229230
}
230231

231232
fn take(&mut self, key: &Q) -> Option<K> {
232-
let root_node = self.root.as_mut()?.node_as_mut();
233+
let (map, dormant_map) = DormantMutRef::new(self);
234+
let root_node = map.root.as_mut()?.node_as_mut();
233235
match search::search_tree(root_node, key) {
234-
Found(handle) => Some(
235-
OccupiedEntry { handle, length: &mut self.length, _marker: PhantomData }
236-
.remove_kv()
237-
.0,
238-
),
236+
Found(handle) => {
237+
Some(OccupiedEntry { handle, dormant_map, _marker: PhantomData }.remove_kv().0)
238+
}
239239
GoDown(_) => None,
240240
}
241241
}
242242

243243
fn replace(&mut self, key: K) -> Option<K> {
244-
let root = Self::ensure_is_owned(&mut self.root);
245-
match search::search_tree::<marker::Mut<'_>, K, (), K>(root.node_as_mut(), &key) {
244+
let (map, dormant_map) = DormantMutRef::new(self);
245+
let root_node = Self::ensure_is_owned(&mut map.root).node_as_mut();
246+
match search::search_tree::<marker::Mut<'_>, K, (), K>(root_node, &key) {
246247
Found(handle) => Some(mem::replace(handle.into_key_mut(), key)),
247248
GoDown(handle) => {
248-
VacantEntry { key, handle, length: &mut self.length, _marker: PhantomData }
249-
.insert(());
249+
VacantEntry { key, handle, dormant_map, _marker: PhantomData }.insert(());
250250
None
251251
}
252252
}
@@ -460,7 +460,7 @@ impl<K: Debug + Ord, V: Debug> Debug for Entry<'_, K, V> {
460460
pub struct VacantEntry<'a, K: 'a, V: 'a> {
461461
key: K,
462462
handle: Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>,
463-
length: &'a mut usize,
463+
dormant_map: DormantMutRef<'a, BTreeMap<K, V>>,
464464

465465
// Be invariant in `K` and `V`
466466
_marker: PhantomData<&'a mut (K, V)>,
@@ -480,8 +480,7 @@ impl<K: Debug + Ord, V> Debug for VacantEntry<'_, K, V> {
480480
#[stable(feature = "rust1", since = "1.0.0")]
481481
pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
482482
handle: Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>,
483-
484-
length: &'a mut usize,
483+
dormant_map: DormantMutRef<'a, BTreeMap<K, V>>,
485484

486485
// Be invariant in `K` and `V`
487486
_marker: PhantomData<&'a mut (K, V)>,
@@ -645,13 +644,10 @@ impl<K: Ord, V> BTreeMap<K, V> {
645644
/// ```
646645
#[unstable(feature = "map_first_last", issue = "62924")]
647646
pub fn first_entry(&mut self) -> Option<OccupiedEntry<'_, K, V>> {
648-
let root_node = self.root.as_mut()?.node_as_mut();
647+
let (map, dormant_map) = DormantMutRef::new(self);
648+
let root_node = map.root.as_mut()?.node_as_mut();
649649
let kv = root_node.first_leaf_edge().right_kv().ok()?;
650-
Some(OccupiedEntry {
651-
handle: kv.forget_node_type(),
652-
length: &mut self.length,
653-
_marker: PhantomData,
654-
})
650+
Some(OccupiedEntry { handle: kv.forget_node_type(), dormant_map, _marker: PhantomData })
655651
}
656652

657653
/// Removes and returns the first element in the map.
@@ -722,13 +718,10 @@ impl<K: Ord, V> BTreeMap<K, V> {
722718
/// ```
723719
#[unstable(feature = "map_first_last", issue = "62924")]
724720
pub fn last_entry(&mut self) -> Option<OccupiedEntry<'_, K, V>> {
725-
let root_node = self.root.as_mut()?.node_as_mut();
721+
let (map, dormant_map) = DormantMutRef::new(self);
722+
let root_node = map.root.as_mut()?.node_as_mut();
726723
let kv = root_node.last_leaf_edge().left_kv().ok()?;
727-
Some(OccupiedEntry {
728-
handle: kv.forget_node_type(),
729-
length: &mut self.length,
730-
_marker: PhantomData,
731-
})
724+
Some(OccupiedEntry { handle: kv.forget_node_type(), dormant_map, _marker: PhantomData })
732725
}
733726

734727
/// Removes and returns the last element in the map.
@@ -902,12 +895,12 @@ impl<K: Ord, V> BTreeMap<K, V> {
902895
K: Borrow<Q>,
903896
Q: Ord,
904897
{
905-
let root_node = self.root.as_mut()?.node_as_mut();
898+
let (map, dormant_map) = DormantMutRef::new(self);
899+
let root_node = map.root.as_mut()?.node_as_mut();
906900
match search::search_tree(root_node, key) {
907-
Found(handle) => Some(
908-
OccupiedEntry { handle, length: &mut self.length, _marker: PhantomData }
909-
.remove_entry(),
910-
),
901+
Found(handle) => {
902+
Some(OccupiedEntry { handle, dormant_map, _marker: PhantomData }.remove_entry())
903+
}
911904
GoDown(_) => None,
912905
}
913906
}
@@ -1074,13 +1067,12 @@ impl<K: Ord, V> BTreeMap<K, V> {
10741067
#[stable(feature = "rust1", since = "1.0.0")]
10751068
pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
10761069
// FIXME(@porglezomp) Avoid allocating if we don't insert
1077-
let root = Self::ensure_is_owned(&mut self.root);
1078-
match search::search_tree(root.node_as_mut(), &key) {
1079-
Found(handle) => {
1080-
Occupied(OccupiedEntry { handle, length: &mut self.length, _marker: PhantomData })
1081-
}
1070+
let (map, dormant_map) = DormantMutRef::new(self);
1071+
let root_node = Self::ensure_is_owned(&mut map.root).node_as_mut();
1072+
match search::search_tree(root_node, &key) {
1073+
Found(handle) => Occupied(OccupiedEntry { handle, dormant_map, _marker: PhantomData }),
10821074
GoDown(handle) => {
1083-
Vacant(VacantEntry { key, handle, length: &mut self.length, _marker: PhantomData })
1075+
Vacant(VacantEntry { key, handle, dormant_map, _marker: PhantomData })
10841076
}
10851077
}
10861078
}
@@ -1285,9 +1277,17 @@ impl<K: Ord, V> BTreeMap<K, V> {
12851277
}
12861278

12871279
pub(super) fn drain_filter_inner(&mut self) -> DrainFilterInner<'_, K, V> {
1288-
let root_node = self.root.as_mut().map(|r| r.node_as_mut());
1289-
let front = root_node.map(|rn| rn.first_leaf_edge());
1290-
DrainFilterInner { length: &mut self.length, cur_leaf_edge: front }
1280+
if let Some(root) = self.root.as_mut() {
1281+
let (root, dormant_root) = DormantMutRef::new(root);
1282+
let front = root.node_as_mut().first_leaf_edge();
1283+
DrainFilterInner {
1284+
length: &mut self.length,
1285+
dormant_root: Some(dormant_root),
1286+
cur_leaf_edge: Some(front),
1287+
}
1288+
} else {
1289+
DrainFilterInner { length: &mut self.length, dormant_root: None, cur_leaf_edge: None }
1290+
}
12911291
}
12921292

12931293
/// Creates a consuming iterator visiting all the keys, in sorted order.
@@ -1672,6 +1672,9 @@ where
16721672
/// of the predicate, thus also serving for BTreeSet::DrainFilter.
16731673
pub(super) struct DrainFilterInner<'a, K: 'a, V: 'a> {
16741674
length: &'a mut usize,
1675+
// dormant_root is wrapped in an Option to be able to `take` it.
1676+
dormant_root: Option<DormantMutRef<'a, node::Root<K, V>>>,
1677+
// cur_leaf_edge is wrapped in an Option because maps without root lack a leaf edge.
16751678
cur_leaf_edge: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
16761679
}
16771680

@@ -1729,7 +1732,13 @@ impl<'a, K: 'a, V: 'a> DrainFilterInner<'a, K, V> {
17291732
let (k, v) = kv.kv_mut();
17301733
if pred(k, v) {
17311734
*self.length -= 1;
1732-
let (kv, pos) = kv.remove_kv_tracking();
1735+
let (kv, pos) = kv.remove_kv_tracking(|| {
1736+
// SAFETY: we will touch the root in a way that will not
1737+
// invalidate the position returned.
1738+
let root = unsafe { self.dormant_root.take().unwrap().awaken() };
1739+
root.pop_internal_level();
1740+
self.dormant_root = Some(DormantMutRef::new(root).1);
1741+
});
17331742
self.cur_leaf_edge = Some(pos);
17341743
return Some(kv);
17351744
}
@@ -2570,13 +2579,20 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
25702579
/// ```
25712580
#[stable(feature = "rust1", since = "1.0.0")]
25722581
pub fn insert(self, value: V) -> &'a mut V {
2573-
*self.length += 1;
2574-
25752582
let out_ptr = match self.handle.insert_recursing(self.key, value) {
2576-
(Fit(_), val_ptr) => val_ptr,
2583+
(Fit(_), val_ptr) => {
2584+
// Safety: We have consumed self.handle and the handle returned.
2585+
let map = unsafe { self.dormant_map.awaken() };
2586+
map.length += 1;
2587+
val_ptr
2588+
}
25772589
(Split(ins), val_ptr) => {
2578-
let root = ins.left.into_root_mut();
2590+
drop(ins.left);
2591+
// Safety: We have consumed self.handle and the reference returned.
2592+
let map = unsafe { self.dormant_map.awaken() };
2593+
let root = map.root.as_mut().unwrap();
25792594
root.push_internal_level().push(ins.k, ins.v, ins.right);
2595+
map.length += 1;
25802596
val_ptr
25812597
}
25822598
};
@@ -2750,18 +2766,25 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
27502766

27512767
// Body of `remove_entry`, separate to keep the above implementations short.
27522768
fn remove_kv(self) -> (K, V) {
2753-
*self.length -= 1;
2754-
2755-
let (old_kv, _) = self.handle.remove_kv_tracking();
2769+
let mut emptied_internal_root = false;
2770+
let (old_kv, _) = self.handle.remove_kv_tracking(|| emptied_internal_root = true);
2771+
// SAFETY: we consumed the intermediate root borrow, `self.handle`.
2772+
let map = unsafe { self.dormant_map.awaken() };
2773+
map.length -= 1;
2774+
if emptied_internal_root {
2775+
let root = map.root.as_mut().unwrap();
2776+
root.pop_internal_level();
2777+
}
27562778
old_kv
27572779
}
27582780
}
27592781

27602782
impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV> {
27612783
/// Removes a key/value-pair from the map, and returns that pair, as well as
27622784
/// the leaf edge corresponding to that former pair.
2763-
fn remove_kv_tracking(
2785+
fn remove_kv_tracking<F: FnOnce()>(
27642786
self,
2787+
handle_emptied_internal_root: F,
27652788
) -> ((K, V), Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>) {
27662789
let (old_kv, mut pos, was_internal) = match self.force() {
27672790
Leaf(leaf) => {
@@ -2814,7 +2837,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInter
28142837
// The parent that was just emptied must be the root,
28152838
// because nodes on a lower level would not have been
28162839
// left with a single child.
2817-
parent.into_root_mut().pop_internal_level();
2840+
handle_emptied_internal_root();
28182841
break;
28192842
} else {
28202843
cur_node = parent.forget_type();

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

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod borrow;
12
pub mod map;
23
mod navigate;
34
mod node;

0 commit comments

Comments
 (0)