Skip to content

Commit 99398dd

Browse files
committed
BTreeMap::drain_filter no longer touches the root during iteration
1 parent 602f9aa commit 99398dd

File tree

2 files changed

+73
-30
lines changed

2 files changed

+73
-30
lines changed

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

+64-23
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> {
174174

175175
{
176176
let out_root = BTreeMap::ensure_is_owned(&mut out_tree.root);
177-
let mut out_node = out_root.push_level();
177+
let mut out_node = out_root.push_internal_level();
178178
let mut in_edge = internal.first_edge();
179179
while let Ok(kv) = in_edge.right_kv() {
180180
let (k, v) = kv.into_kv();
@@ -1080,9 +1080,9 @@ impl<K: Ord, V> BTreeMap<K, V> {
10801080
test_node = parent.forget_type();
10811081
}
10821082
}
1083-
Err(node) => {
1083+
Err(_) => {
10841084
// We are at the top, create a new root node and push there.
1085-
open_node = node.into_root_mut().push_level();
1085+
open_node = root.push_internal_level();
10861086
break;
10871087
}
10881088
}
@@ -1092,7 +1092,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
10921092
let tree_height = open_node.height() - 1;
10931093
let mut right_tree = node::Root::new_leaf();
10941094
for _ in 0..tree_height {
1095-
right_tree.push_level();
1095+
right_tree.push_internal_level();
10961096
}
10971097
open_node.push(key, value, right_tree);
10981098

@@ -1171,7 +1171,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
11711171
let mut right = Self::new();
11721172
let right_root = Self::ensure_is_owned(&mut right.root);
11731173
for _ in 0..left_root.height() {
1174-
right_root.push_level();
1174+
right_root.push_internal_level();
11751175
}
11761176

11771177
{
@@ -1255,7 +1255,11 @@ impl<K: Ord, V> BTreeMap<K, V> {
12551255
}
12561256
pub(super) fn drain_filter_inner(&mut self) -> DrainFilterInner<'_, K, V> {
12571257
let front = self.root.as_mut().map(|r| r.as_mut().first_leaf_edge());
1258-
DrainFilterInner { length: &mut self.length, cur_leaf_edge: front }
1258+
DrainFilterInner {
1259+
length: &mut self.length,
1260+
cur_leaf_edge: front,
1261+
emptied_internal_root: false,
1262+
}
12591263
}
12601264

12611265
/// Calculates the number of elements if it is incorrect.
@@ -1625,6 +1629,7 @@ where
16251629
pub(super) struct DrainFilterInner<'a, K: 'a, V: 'a> {
16261630
length: &'a mut usize,
16271631
cur_leaf_edge: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
1632+
emptied_internal_root: bool,
16281633
}
16291634

16301635
#[unstable(feature = "btree_drain_filter", issue = "70530")]
@@ -1665,6 +1670,17 @@ where
16651670
}
16661671
}
16671672

1673+
impl<K, V> Drop for DrainFilterInner<'_, K, V> {
1674+
fn drop(&mut self) {
1675+
if self.emptied_internal_root {
1676+
if let Some(handle) = self.cur_leaf_edge.take() {
1677+
let root = handle.into_node().into_root_mut();
1678+
root.pop_internal_level();
1679+
}
1680+
}
1681+
}
1682+
}
1683+
16681684
impl<'a, K: 'a, V: 'a> DrainFilterInner<'a, K, V> {
16691685
/// Allow Debug implementations to predict the next element.
16701686
pub(super) fn peek(&self) -> Option<(&K, &V)> {
@@ -1681,9 +1697,10 @@ impl<'a, K: 'a, V: 'a> DrainFilterInner<'a, K, V> {
16811697
let (k, v) = kv.kv_mut();
16821698
if pred(k, v) {
16831699
*self.length -= 1;
1684-
let (k, v, leaf_edge_location) = kv.remove_kv_tracking();
1685-
self.cur_leaf_edge = Some(leaf_edge_location);
1686-
return Some((k, v));
1700+
let RemoveResult { old_kv, pos, emptied_internal_root } = kv.remove_kv_tracking();
1701+
self.cur_leaf_edge = Some(pos);
1702+
self.emptied_internal_root |= emptied_internal_root;
1703+
return Some(old_kv);
16871704
}
16881705
self.cur_leaf_edge = Some(kv.next_leaf_edge());
16891706
}
@@ -2477,7 +2494,7 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
24772494
}
24782495
},
24792496
Err(root) => {
2480-
root.push_level().push(ins_k, ins_v, ins_edge);
2497+
root.push_internal_level().push(ins_k, ins_v, ins_edge);
24812498
return unsafe { &mut *out_ptr };
24822499
}
24832500
}
@@ -2647,20 +2664,35 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
26472664
self.remove_kv().1
26482665
}
26492666

2667+
// Body of `remove_entry`, separate to keep the above implementations short.
26502668
fn remove_kv(self) -> (K, V) {
26512669
*self.length -= 1;
26522670

2653-
let (old_key, old_val, _) = self.handle.remove_kv_tracking();
2654-
(old_key, old_val)
2671+
let RemoveResult { old_kv, pos, emptied_internal_root } = self.handle.remove_kv_tracking();
2672+
let root = pos.into_node().into_root_mut();
2673+
if emptied_internal_root {
2674+
root.pop_internal_level();
2675+
}
2676+
old_kv
26552677
}
26562678
}
26572679

2680+
struct RemoveResult<'a, K, V> {
2681+
// Key and value removed.
2682+
old_kv: (K, V),
2683+
// Unique location at the leaf level that the removed KV lopgically collapsed into.
2684+
pos: Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>,
2685+
// Whether the remove left behind and empty internal root node, that should be removed
2686+
// using `pop_internal_level`.
2687+
emptied_internal_root: bool,
2688+
}
2689+
26582690
impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV> {
2659-
/// Removes a key/value-pair from the map, and returns that pair, as well as
2660-
/// the leaf edge corresponding to that former pair.
2661-
fn remove_kv_tracking(
2662-
self,
2663-
) -> (K, V, Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>) {
2691+
/// Removes a key/value-pair from the tree, and returns that pair, as well as
2692+
/// the leaf edge corresponding to that former pair. It's possible this leaves
2693+
/// an empty internal root node, which the caller should subsequently pop from
2694+
/// the map holding the tree. The caller should also decrement the map's length.
2695+
fn remove_kv_tracking(self) -> RemoveResult<'a, K, V> {
26642696
let (mut pos, old_key, old_val, was_internal) = match self.force() {
26652697
Leaf(leaf) => {
26662698
let (hole, old_key, old_val) = leaf.remove();
@@ -2689,6 +2721,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInter
26892721
};
26902722

26912723
// Handle underflow
2724+
let mut emptied_internal_root = false;
26922725
let mut cur_node = unsafe { ptr::read(&pos).into_node().forget_type() };
26932726
let mut at_leaf = true;
26942727
while cur_node.len() < node::MIN_LEN {
@@ -2709,8 +2742,8 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInter
27092742

27102743
let parent = edge.into_node();
27112744
if parent.len() == 0 {
2712-
// We must be at the root
2713-
parent.into_root_mut().pop_level();
2745+
// This empty parent must be the root, and should be popped off the tree.
2746+
emptied_internal_root = true;
27142747
break;
27152748
} else {
27162749
cur_node = parent.forget_type();
@@ -2737,15 +2770,15 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInter
27372770
pos = unsafe { unwrap_unchecked(pos.next_kv().ok()).next_leaf_edge() };
27382771
}
27392772

2740-
(old_key, old_val, pos)
2773+
RemoveResult { old_kv: (old_key, old_val), pos, emptied_internal_root }
27412774
}
27422775
}
27432776

27442777
impl<K, V> node::Root<K, V> {
27452778
/// Removes empty levels on the top, but keep an empty leaf if the entire tree is empty.
27462779
fn fix_top(&mut self) {
27472780
while self.height() > 0 && self.as_ref().len() == 0 {
2748-
self.pop_level();
2781+
self.pop_internal_level();
27492782
}
27502783
}
27512784

@@ -2817,8 +2850,16 @@ fn handle_underfull_node<K, V>(
28172850
let (is_left, mut handle) = match parent.left_kv() {
28182851
Ok(left) => (true, left),
28192852
Err(parent) => {
2820-
let right = unsafe { unwrap_unchecked(parent.right_kv().ok()) };
2821-
(false, right)
2853+
match parent.right_kv() {
2854+
Ok(right) => (false, right),
2855+
Err(_) => {
2856+
// The underfull node has an empty parent, so it is the only child
2857+
// of an empty root. It is destined to become the new root, thus
2858+
// allowed to be underfull. The empty parent should be removed later
2859+
// by `pop_internal_level`.
2860+
return AtRoot;
2861+
}
2862+
}
28222863
}
28232864
};
28242865

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

+9-7
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,9 @@ impl<K, V> Root<K, V> {
191191
}
192192

193193
/// Adds a new internal node with a single edge, pointing to the previous root, and make that
194-
/// new node the root. This increases the height by 1 and is the opposite of `pop_level`.
195-
pub fn push_level(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Internal> {
194+
/// new node the root. This increases the height by 1 and is the opposite of
195+
/// `pop_internal_level`.
196+
pub fn push_internal_level(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Internal> {
196197
let mut new_node = Box::new(unsafe { InternalNode::new() });
197198
new_node.edges[0].write(unsafe { BoxedNode::from_ptr(self.node.as_ptr()) });
198199

@@ -213,11 +214,12 @@ impl<K, V> Root<K, V> {
213214
ret
214215
}
215216

216-
/// Removes the root node, using its first child as the new root. This cannot be called when
217-
/// the tree consists only of a leaf node. As it is intended only to be called when the root
218-
/// has only one edge, no cleanup is done on any of the other children of the root.
219-
/// This decreases the height by 1 and is the opposite of `push_level`.
220-
pub fn pop_level(&mut self) {
217+
/// Removes the internal root node, using its first child as the new root.
218+
/// As it is intended only to be called when the root has only one child,
219+
/// no cleanup is done on any of the other children of the root.
220+
/// This decreases the height by 1 and is the opposite of `push_internal_level`.
221+
/// Panics if there is no internal level, i.e. if the root is a leaf.
222+
pub fn pop_internal_level(&mut self) {
221223
assert!(self.height > 0);
222224

223225
let top = self.node.ptr;

0 commit comments

Comments
 (0)