Skip to content

Commit 2ec0e14

Browse files
authored
Rollup merge of #70795 - Amanieu:btree_remove_tracking, r=Mark-Simulacrum
Keep track of position when deleting from a BTreeMap This improves the performance of drain_filter and is needed for future Cursor support for BTreeMap. cc @ssomers r? @Mark-Simulacrum
2 parents c259553 + 51357cf commit 2ec0e14

File tree

2 files changed

+64
-49
lines changed

2 files changed

+64
-49
lines changed

src/liballoc/collections/btree/map.rs

+59-49
Original file line numberDiff line numberDiff line change
@@ -1780,18 +1780,12 @@ where
17801780
where
17811781
F: FnMut(&K, &mut V) -> bool,
17821782
{
1783-
while let Some(kv) = unsafe { self.next_kv() } {
1784-
let (k, v) = unsafe { ptr::read(&kv) }.into_kv_mut();
1783+
while let Some(mut kv) = unsafe { self.next_kv() } {
1784+
let (k, v) = kv.kv_mut();
17851785
if pred(k, v) {
17861786
*self.length -= 1;
17871787
let (k, v, leaf_edge_location) = kv.remove_kv_tracking();
1788-
// `remove_kv_tracking` has either preserved or invalidated `self.cur_leaf_edge`
1789-
if let Some(node) = leaf_edge_location {
1790-
match search::search_tree(node, &k) {
1791-
search::SearchResult::Found(_) => unreachable!(),
1792-
search::SearchResult::GoDown(leaf) => self.cur_leaf_edge = Some(leaf),
1793-
}
1794-
};
1788+
self.cur_leaf_edge = Some(leaf_edge_location);
17951789
return Some((k, v));
17961790
}
17971791
self.cur_leaf_edge = Some(kv.next_leaf_edge());
@@ -2698,108 +2692,124 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
26982692

26992693
impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV> {
27002694
/// Removes a key/value-pair from the map, and returns that pair, as well as
2701-
/// the whereabouts of the leaf edge corresponding to that former pair:
2702-
/// if None is returned, the leaf edge is still the left leaf edge of the KV handle;
2703-
/// if a node is returned, it heads the subtree where the leaf edge may be found.
2695+
/// the leaf edge corresponding to that former pair.
27042696
fn remove_kv_tracking(
27052697
self,
2706-
) -> (K, V, Option<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>>) {
2707-
let mut levels_down_handled: isize;
2708-
let (small_leaf, old_key, old_val) = match self.force() {
2698+
) -> (K, V, Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>) {
2699+
let (mut pos, old_key, old_val, was_internal) = match self.force() {
27092700
Leaf(leaf) => {
2710-
levels_down_handled = 1; // handled at same level, but affects only the right side
27112701
let (hole, old_key, old_val) = leaf.remove();
2712-
(hole.into_node(), old_key, old_val)
2702+
(hole, old_key, old_val, false)
27132703
}
27142704
Internal(mut internal) => {
27152705
// Replace the location freed in the internal node with the next KV,
27162706
// and remove that next KV from its leaf.
2717-
levels_down_handled = unsafe { ptr::read(&internal).into_node().height() } as isize;
27182707

27192708
let key_loc = internal.kv_mut().0 as *mut K;
27202709
let val_loc = internal.kv_mut().1 as *mut V;
27212710

2722-
let to_remove = internal.right_edge().descend().first_leaf_edge().right_kv().ok();
2711+
// Deleting from the left side is typically faster since we can
2712+
// just pop an element from the end of the KV array without
2713+
// needing to shift the other values.
2714+
let to_remove = internal.left_edge().descend().last_leaf_edge().left_kv().ok();
27232715
let to_remove = unsafe { unwrap_unchecked(to_remove) };
27242716

27252717
let (hole, key, val) = to_remove.remove();
27262718

27272719
let old_key = unsafe { mem::replace(&mut *key_loc, key) };
27282720
let old_val = unsafe { mem::replace(&mut *val_loc, val) };
27292721

2730-
(hole.into_node(), old_key, old_val)
2722+
(hole, old_key, old_val, true)
27312723
}
27322724
};
27332725

27342726
// Handle underflow
2735-
let mut cur_node = small_leaf.forget_type();
2727+
let mut cur_node = unsafe { ptr::read(&pos).into_node().forget_type() };
2728+
let mut at_leaf = true;
27362729
while cur_node.len() < node::MIN_LEN {
27372730
match handle_underfull_node(cur_node) {
2738-
AtRoot(root) => {
2739-
cur_node = root;
2740-
break;
2741-
}
2742-
EmptyParent(_) => unreachable!(),
2743-
Merged(parent) => {
2744-
levels_down_handled -= 1;
2731+
AtRoot => break,
2732+
Merged(edge, merged_with_left, offset) => {
2733+
// If we merged with our right sibling then our tracked
2734+
// position has not changed. However if we merged with our
2735+
// left sibling then our tracked position is now dangling.
2736+
if at_leaf && merged_with_left {
2737+
let idx = pos.idx() + offset;
2738+
let node = match unsafe { ptr::read(&edge).descend().force() } {
2739+
Leaf(leaf) => leaf,
2740+
Internal(_) => unreachable!(),
2741+
};
2742+
pos = unsafe { Handle::new_edge(node, idx) };
2743+
}
2744+
2745+
let parent = edge.into_node();
27452746
if parent.len() == 0 {
27462747
// We must be at the root
2747-
let root = parent.into_root_mut();
2748-
root.pop_level();
2749-
cur_node = root.as_mut();
2748+
parent.into_root_mut().pop_level();
27502749
break;
27512750
} else {
27522751
cur_node = parent.forget_type();
2752+
at_leaf = false;
27532753
}
27542754
}
2755-
Stole(internal_node) => {
2756-
levels_down_handled -= 1;
2757-
cur_node = internal_node.forget_type();
2755+
Stole(stole_from_left) => {
2756+
// Adjust the tracked position if we stole from a left sibling
2757+
if stole_from_left && at_leaf {
2758+
// SAFETY: This is safe since we just added an element to our node.
2759+
unsafe {
2760+
pos.next_unchecked();
2761+
}
2762+
}
2763+
27582764
// This internal node might be underfull, but only if it's the root.
27592765
break;
27602766
}
27612767
}
27622768
}
27632769

2764-
let leaf_edge_location = if levels_down_handled > 0 { None } else { Some(cur_node) };
2765-
(old_key, old_val, leaf_edge_location)
2770+
// If we deleted from an internal node then we need to compensate for
2771+
// the earlier swap and adjust the tracked position to point to the
2772+
// next element.
2773+
if was_internal {
2774+
pos = unsafe { unwrap_unchecked(pos.next_kv().ok()).next_leaf_edge() };
2775+
}
2776+
2777+
(old_key, old_val, pos)
27662778
}
27672779
}
27682780

27692781
enum UnderflowResult<'a, K, V> {
2770-
AtRoot(NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>),
2771-
EmptyParent(NodeRef<marker::Mut<'a>, K, V, marker::Internal>),
2772-
Merged(NodeRef<marker::Mut<'a>, K, V, marker::Internal>),
2773-
Stole(NodeRef<marker::Mut<'a>, K, V, marker::Internal>),
2782+
AtRoot,
2783+
Merged(Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::Edge>, bool, usize),
2784+
Stole(bool),
27742785
}
27752786

27762787
fn handle_underfull_node<K, V>(
27772788
node: NodeRef<marker::Mut<'_>, K, V, marker::LeafOrInternal>,
27782789
) -> UnderflowResult<'_, K, V> {
27792790
let parent = match node.ascend() {
27802791
Ok(parent) => parent,
2781-
Err(root) => return AtRoot(root),
2792+
Err(_) => return AtRoot,
27822793
};
27832794

27842795
let (is_left, mut handle) = match parent.left_kv() {
27852796
Ok(left) => (true, left),
2786-
Err(parent) => match parent.right_kv() {
2787-
Ok(right) => (false, right),
2788-
Err(parent) => {
2789-
return EmptyParent(parent.into_node());
2790-
}
2791-
},
2797+
Err(parent) => {
2798+
let right = unsafe { unwrap_unchecked(parent.right_kv().ok()) };
2799+
(false, right)
2800+
}
27922801
};
27932802

27942803
if handle.can_merge() {
2795-
Merged(handle.merge().into_node())
2804+
let offset = if is_left { handle.reborrow().left_edge().descend().len() + 1 } else { 0 };
2805+
Merged(handle.merge(), is_left, offset)
27962806
} else {
27972807
if is_left {
27982808
handle.steal_left();
27992809
} else {
28002810
handle.steal_right();
28012811
}
2802-
Stole(handle.into_node())
2812+
Stole(is_left)
28032813
}
28042814
}
28052815

src/liballoc/collections/btree/node.rs

+5
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,11 @@ impl<Node, Type> Handle<Node, Type> {
723723
pub fn into_node(self) -> Node {
724724
self.node
725725
}
726+
727+
/// Returns the position of this handle in the node.
728+
pub fn idx(&self) -> usize {
729+
self.idx
730+
}
726731
}
727732

728733
impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, marker::KV> {

0 commit comments

Comments
 (0)