Skip to main content

alloc/collections/btree/
remove.rs

1use core::alloc::AllocatorClone;
2
3use super::map::MIN_LEN;
4use super::node::ForceResult::*;
5use super::node::LeftOrRight::*;
6use super::node::{Handle, NodeRef, marker};
7
8impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV> {
9    /// Removes a key-value pair from the tree, and returns that pair, as well as
10    /// the leaf edge corresponding to that former pair. It's possible this empties
11    /// a root node that is internal, which the caller should pop from the map
12    /// holding the tree. The caller should also decrement the map's length.
13    pub(super) fn remove_kv_tracking<F: FnOnce(), A: AllocatorClone>(
14        self,
15        handle_emptied_internal_root: F,
16        alloc: A,
17    ) -> ((K, V), Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>) {
18        match self.force() {
19            Leaf(node) => node.remove_leaf_kv(handle_emptied_internal_root, alloc),
20            Internal(node) => node.remove_internal_kv(handle_emptied_internal_root, alloc),
21        }
22    }
23}
24
25impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV> {
26    fn remove_leaf_kv<F: FnOnce(), A: AllocatorClone>(
27        self,
28        handle_emptied_internal_root: F,
29        alloc: A,
30    ) -> ((K, V), Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>) {
31        let (old_kv, mut pos) = self.remove();
32        let len = pos.reborrow().into_node().len();
33        if len < MIN_LEN {
34            let idx = pos.idx();
35            // We have to temporarily forget the child type, because there is no
36            // distinct node type for the immediate parents of a leaf.
37            let new_pos = match pos.into_node().forget_type().choose_parent_kv() {
38                Ok(Left(left_parent_kv)) => {
39                    if true {
    if !(left_parent_kv.right_child_len() == MIN_LEN - 1) {
        ::core::panicking::panic("assertion failed: left_parent_kv.right_child_len() == MIN_LEN - 1")
    };
};debug_assert!(left_parent_kv.right_child_len() == MIN_LEN - 1);
40                    if left_parent_kv.can_merge() {
41                        left_parent_kv.merge_tracking_child_edge(Right(idx), alloc.clone())
42                    } else {
43                        if true {
    if !(left_parent_kv.left_child_len() > MIN_LEN) {
        ::core::panicking::panic("assertion failed: left_parent_kv.left_child_len() > MIN_LEN")
    };
};debug_assert!(left_parent_kv.left_child_len() > MIN_LEN);
44                        left_parent_kv.steal_left(idx)
45                    }
46                }
47                Ok(Right(right_parent_kv)) => {
48                    if true {
    if !(right_parent_kv.left_child_len() == MIN_LEN - 1) {
        ::core::panicking::panic("assertion failed: right_parent_kv.left_child_len() == MIN_LEN - 1")
    };
};debug_assert!(right_parent_kv.left_child_len() == MIN_LEN - 1);
49                    if right_parent_kv.can_merge() {
50                        right_parent_kv.merge_tracking_child_edge(Left(idx), alloc.clone())
51                    } else {
52                        if true {
    if !(right_parent_kv.right_child_len() > MIN_LEN) {
        ::core::panicking::panic("assertion failed: right_parent_kv.right_child_len() > MIN_LEN")
    };
};debug_assert!(right_parent_kv.right_child_len() > MIN_LEN);
53                        right_parent_kv.steal_right(idx)
54                    }
55                }
56                // ignore-tidy-undocumented-unsafe
57                Err(pos) => unsafe { Handle::new_edge(pos, idx) },
58            };
59            // SAFETY: `new_pos` is the leaf we started from or a sibling.
60            pos = unsafe { new_pos.cast_to_leaf_unchecked() };
61
62            // Only if we merged, the parent (if any) has shrunk, but skipping
63            // the following step otherwise does not pay off in benchmarks.
64            //
65            // SAFETY: We won't destroy or rearrange the leaf where `pos` is at
66            // by handling its parent recursively; at worst we will destroy or
67            // rearrange the parent through the grandparent, thus change the
68            // link to the parent inside the leaf.
69            if let Ok(parent) = unsafe { pos.reborrow_mut() }.into_node().ascend() {
70                if !parent.into_node().forget_type().fix_node_and_affected_ancestors(alloc) {
71                    handle_emptied_internal_root();
72                }
73            }
74        }
75        (old_kv, pos)
76    }
77}
78
79impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::KV> {
80    fn remove_internal_kv<F: FnOnce(), A: AllocatorClone>(
81        self,
82        handle_emptied_internal_root: F,
83        alloc: A,
84    ) -> ((K, V), Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>) {
85        // Remove an adjacent KV from its leaf and then put it back in place of
86        // the element we were asked to remove. Prefer the left adjacent KV,
87        // for the reasons listed in `choose_parent_kv`.
88        let left_leaf_kv = self.left_edge().descend().last_leaf_edge().left_kv();
89        // ignore-tidy-undocumented-unsafe
90        let left_leaf_kv = unsafe { left_leaf_kv.ok().unwrap_unchecked() };
91        let (left_kv, left_hole) = left_leaf_kv.remove_leaf_kv(handle_emptied_internal_root, alloc);
92
93        // The internal node may have been stolen from or merged. Go back right
94        // to find where the original KV ended up.
95        // ignore-tidy-undocumented-unsafe
96        let mut internal = unsafe { left_hole.next_kv().ok().unwrap_unchecked() };
97        let old_kv = internal.replace_kv(left_kv.0, left_kv.1);
98        let pos = internal.next_leaf_edge();
99        (old_kv, pos)
100    }
101}