Skip to content

Commit d19d7e2

Browse files
committed
Auto merge of rust-lang#75257 - ssomers:btree_74762_again, r=Mark-Simulacrum
BTreeMap: better way to postpone root access in DrainFilter A slightly more elegant (in my opinion) adaptation of rust-lang#74762. Benchmarks seem irrationally pleased to: ``` benchcmp old new --threshold 5 name old ns/iter new ns/iter diff ns/iter diff % speedup btree::map::clone_fat_100_and_remove_all 215,182 185,052 -30,130 -14.00% x 1.16 btree::map::clone_fat_100_and_remove_half 139,667 127,945 -11,722 -8.39% x 1.09 btree::map::clone_fat_val_100_and_remove_all 96,755 81,279 -15,476 -16.00% x 1.19 btree::map::clone_fat_val_100_and_remove_half 64,678 56,911 -7,767 -12.01% x 1.14 btree::map::find_rand_100 18 17 -1 -5.56% x 1.06 btree::map::first_and_last_0 33 35 2 6.06% x 0.94 btree::map::first_and_last_100 40 54 14 35.00% x 0.74 btree::map::insert_rand_100 45 42 -3 -6.67% x 1.07 btree::map::insert_rand_10_000 45 41 -4 -8.89% x 1.10 btree::map::iter_0 2,010 1,759 -251 -12.49% x 1.14 btree::map::iter_100 3,514 2,764 -750 -21.34% x 1.27 btree::map::iter_10k 4,018 3,768 -250 -6.22% x 1.07 btree::map::range_unbounded_unbounded 37,269 28,929 -8,340 -22.38% x 1.29 btree::map::range_unbounded_vs_iter 31,518 28,814 -2,704 -8.58% x 1.09 ``` r? @Mark-Simulacrum
2 parents e61621c + 85a7879 commit d19d7e2

File tree

2 files changed

+25
-32
lines changed

2 files changed

+25
-32
lines changed

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

+23-30
Original file line numberDiff line numberDiff line change
@@ -1697,10 +1697,9 @@ impl<'a, K: 'a, V: 'a> DrainFilterInner<'a, K, V> {
16971697
let (k, v) = kv.kv_mut();
16981698
if pred(k, v) {
16991699
*self.length -= 1;
1700-
let RemoveResult { old_kv, pos, emptied_internal_root } = kv.remove_kv_tracking();
1700+
let (kv, pos) = kv.remove_kv_tracking(|_| self.emptied_internal_root = true);
17011701
self.cur_leaf_edge = Some(pos);
1702-
self.emptied_internal_root |= emptied_internal_root;
1703-
return Some(old_kv);
1702+
return Some(kv);
17041703
}
17051704
self.cur_leaf_edge = Some(kv.next_leaf_edge());
17061705
}
@@ -2645,35 +2644,28 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
26452644
fn remove_kv(self) -> (K, V) {
26462645
*self.length -= 1;
26472646

2648-
let RemoveResult { old_kv, pos, emptied_internal_root } = self.handle.remove_kv_tracking();
2649-
let root = pos.into_node().into_root_mut();
2650-
if emptied_internal_root {
2651-
root.pop_internal_level();
2652-
}
2647+
let (old_kv, _) =
2648+
self.handle.remove_kv_tracking(|root| root.into_root_mut().pop_internal_level());
26532649
old_kv
26542650
}
26552651
}
26562652

2657-
struct RemoveResult<'a, K, V> {
2658-
// Key and value removed.
2659-
old_kv: (K, V),
2660-
// Unique location at the leaf level that the removed KV lopgically collapsed into.
2661-
pos: Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>,
2662-
// Whether the remove left behind and empty internal root node, that should be removed
2663-
// using `pop_internal_level`.
2664-
emptied_internal_root: bool,
2665-
}
2666-
26672653
impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV> {
26682654
/// Removes a key/value-pair from the tree, and returns that pair, as well as
26692655
/// the leaf edge corresponding to that former pair. It's possible this leaves
26702656
/// an empty internal root node, which the caller should subsequently pop from
26712657
/// the map holding the tree. The caller should also decrement the map's length.
2672-
fn remove_kv_tracking(self) -> RemoveResult<'a, K, V> {
2673-
let (mut pos, old_key, old_val, was_internal) = match self.force() {
2658+
fn remove_kv_tracking<F>(
2659+
self,
2660+
handle_emptied_internal_root: F,
2661+
) -> ((K, V), Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>)
2662+
where
2663+
F: FnOnce(NodeRef<marker::Mut<'a>, K, V, marker::Internal>),
2664+
{
2665+
let (old_kv, mut pos, was_internal) = match self.force() {
26742666
Leaf(leaf) => {
2675-
let (hole, old_key, old_val) = leaf.remove();
2676-
(hole, old_key, old_val, false)
2667+
let (old_kv, pos) = leaf.remove();
2668+
(old_kv, pos, false)
26772669
}
26782670
Internal(mut internal) => {
26792671
// Replace the location freed in the internal node with the next KV,
@@ -2688,17 +2680,16 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInter
26882680
let to_remove = internal.left_edge().descend().last_leaf_edge().left_kv().ok();
26892681
let to_remove = unsafe { unwrap_unchecked(to_remove) };
26902682

2691-
let (hole, key, val) = to_remove.remove();
2683+
let (kv, pos) = to_remove.remove();
26922684

2693-
let old_key = unsafe { mem::replace(&mut *key_loc, key) };
2694-
let old_val = unsafe { mem::replace(&mut *val_loc, val) };
2685+
let old_key = unsafe { mem::replace(&mut *key_loc, kv.0) };
2686+
let old_val = unsafe { mem::replace(&mut *val_loc, kv.1) };
26952687

2696-
(hole, old_key, old_val, true)
2688+
((old_key, old_val), pos, true)
26972689
}
26982690
};
26992691

27002692
// Handle underflow
2701-
let mut emptied_internal_root = false;
27022693
let mut cur_node = unsafe { ptr::read(&pos).into_node().forget_type() };
27032694
let mut at_leaf = true;
27042695
while cur_node.len() < node::MIN_LEN {
@@ -2719,8 +2710,10 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInter
27192710

27202711
let parent = edge.into_node();
27212712
if parent.len() == 0 {
2722-
// This empty parent must be the root, and should be popped off the tree.
2723-
emptied_internal_root = true;
2713+
// The parent that was just emptied must be the root,
2714+
// because nodes on a lower level would not have been
2715+
// left underfull. It has to be popped off the tree soon.
2716+
handle_emptied_internal_root(parent);
27242717
break;
27252718
} else {
27262719
cur_node = parent.forget_type();
@@ -2747,7 +2740,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInter
27472740
pos = unsafe { unwrap_unchecked(pos.next_kv().ok()).next_leaf_edge() };
27482741
}
27492742

2750-
RemoveResult { old_kv: (old_key, old_val), pos, emptied_internal_root }
2743+
(old_kv, pos)
27512744
}
27522745
}
27532746

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1083,12 +1083,12 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV>
10831083
/// between the now adjacent key/value pairs (if any) to the left and right of this handle.
10841084
pub fn remove(
10851085
mut self,
1086-
) -> (Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>, K, V) {
1086+
) -> ((K, V), Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>) {
10871087
unsafe {
10881088
let k = slice_remove(self.node.keys_mut(), self.idx);
10891089
let v = slice_remove(self.node.vals_mut(), self.idx);
10901090
(*self.node.as_leaf_mut()).len -= 1;
1091-
(self.left_edge(), k, v)
1091+
((k, v), self.left_edge())
10921092
}
10931093
}
10941094
}

0 commit comments

Comments
 (0)