Skip to content

Commit a270444

Browse files
committed
Auto merge of #81361 - ssomers:btree_drainy_refactor_7, r=Mark-Simulacrum
BTreeMap: lightly refactor the split_off implementation r? `@Mark-Simulacrum`
2 parents 0fc6756 + b20f468 commit a270444

File tree

2 files changed

+67
-42
lines changed

2 files changed

+67
-42
lines changed

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

+12-12
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ use Entry::*;
2020
/// We might temporarily have fewer elements during methods.
2121
pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT;
2222

23+
// A tree in a `BTreeMap` is a tree in the `node` module with addtional invariants:
24+
// - Keys must appear in ascending order (according to the key's type).
25+
// - If the root node is internal, it must contain at least 1 element.
26+
// - Every non-root node contains at least MIN_LEN elements.
27+
//
28+
// An empty map may be represented both by the absense of a root node or by a
29+
// root node that is an empty leaf.
30+
2331
/// A map based on a B-Tree.
2432
///
2533
/// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing
@@ -1131,20 +1139,12 @@ impl<K, V> BTreeMap<K, V> {
11311139
let total_num = self.len();
11321140
let left_root = self.root.as_mut().unwrap(); // unwrap succeeds because not empty
11331141

1134-
let mut right = Self::new();
1135-
let right_root = Self::ensure_is_owned(&mut right.root);
1136-
1137-
left_root.split_off(right_root, key);
1142+
let right_root = left_root.split_off(key);
11381143

1139-
if left_root.height() < right_root.height() {
1140-
self.length = left_root.reborrow().calc_length();
1141-
right.length = total_num - self.len();
1142-
} else {
1143-
right.length = right_root.reborrow().calc_length();
1144-
self.length = total_num - right.len();
1145-
}
1144+
let (new_left_len, right_len) = Root::calc_split_length(total_num, &left_root, &right_root);
1145+
self.length = new_left_len;
11461146

1147-
right
1147+
BTreeMap { root: Some(right_root), length: right_len }
11481148
}
11491149

11501150
/// Creates an iterator that visits all elements (key-value pairs) in

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

+55-30
Original file line numberDiff line numberDiff line change
@@ -4,46 +4,71 @@ use super::search::SearchResult::*;
44
use core::borrow::Borrow;
55

66
impl<K, V> Root<K, V> {
7-
pub fn split_off<Q: ?Sized + Ord>(&mut self, right_root: &mut Self, key: &Q)
7+
/// Calculates the length of both trees that result from splitting up
8+
/// a given number of distinct key-value pairs.
9+
pub fn calc_split_length(
10+
total_num: usize,
11+
root_a: &Root<K, V>,
12+
root_b: &Root<K, V>,
13+
) -> (usize, usize) {
14+
let (length_a, length_b);
15+
if root_a.height() < root_b.height() {
16+
length_a = root_a.reborrow().calc_length();
17+
length_b = total_num - length_a;
18+
debug_assert_eq!(length_b, root_b.reborrow().calc_length());
19+
} else {
20+
length_b = root_b.reborrow().calc_length();
21+
length_a = total_num - length_b;
22+
debug_assert_eq!(length_a, root_a.reborrow().calc_length());
23+
}
24+
(length_a, length_b)
25+
}
26+
27+
/// Split off a tree with key-value pairs at and after the given key.
28+
/// The result is meaningful only if the tree is ordered by key,
29+
/// and if the ordering of `Q` corresponds to that of `K`.
30+
/// If `self` respects all `BTreeMap` tree invariants, then both
31+
/// `self` and the returned tree will respect those invariants.
32+
pub fn split_off<Q: ?Sized + Ord>(&mut self, key: &Q) -> Self
833
where
934
K: Borrow<Q>,
1035
{
11-
debug_assert!(right_root.height() == 0);
12-
debug_assert!(right_root.len() == 0);
13-
1436
let left_root = self;
15-
for _ in 0..left_root.height() {
16-
right_root.push_internal_level();
17-
}
18-
19-
{
20-
let mut left_node = left_root.borrow_mut();
21-
let mut right_node = right_root.borrow_mut();
22-
23-
loop {
24-
let mut split_edge = match left_node.search_node(key) {
25-
// key is going to the right tree
26-
Found(kv) => kv.left_edge(),
27-
GoDown(edge) => edge,
28-
};
29-
30-
split_edge.move_suffix(&mut right_node);
31-
32-
match (split_edge.force(), right_node.force()) {
33-
(Internal(edge), Internal(node)) => {
34-
left_node = edge.descend();
35-
right_node = node.first_edge().descend();
36-
}
37-
(Leaf(_), Leaf(_)) => {
38-
break;
39-
}
40-
_ => unreachable!(),
37+
let mut right_root = Root::new_pillar(left_root.height());
38+
let mut left_node = left_root.borrow_mut();
39+
let mut right_node = right_root.borrow_mut();
40+
41+
loop {
42+
let mut split_edge = match left_node.search_node(key) {
43+
// key is going to the right tree
44+
Found(kv) => kv.left_edge(),
45+
GoDown(edge) => edge,
46+
};
47+
48+
split_edge.move_suffix(&mut right_node);
49+
50+
match (split_edge.force(), right_node.force()) {
51+
(Internal(edge), Internal(node)) => {
52+
left_node = edge.descend();
53+
right_node = node.first_edge().descend();
4154
}
55+
(Leaf(_), Leaf(_)) => break,
56+
_ => unreachable!(),
4257
}
4358
}
4459

4560
left_root.fix_right_border();
4661
right_root.fix_left_border();
62+
right_root
63+
}
64+
65+
/// Creates a tree consisting of empty nodes.
66+
fn new_pillar(height: usize) -> Self {
67+
let mut root = Root::new();
68+
for _ in 0..height {
69+
root.push_internal_level();
70+
}
71+
root
4772
}
4873

4974
/// Removes empty levels on the top, but keeps an empty leaf if the entire tree is empty.

0 commit comments

Comments
 (0)