Skip to content

Commit cefe40b

Browse files
authored
Rollup merge of #80353 - ssomers:btree_test_split_off, r=Mark-Simulacrum
BTreeMap: test split_off (and append) more thoroughly Using DeterministicRng as a poor man's property based testing rig. r? ``@Mark-Simulacrum``
2 parents c51172f + d473cbe commit cefe40b

File tree

5 files changed

+38
-7
lines changed

5 files changed

+38
-7
lines changed

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

+6-3
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,18 @@ impl<K, V> Root<K, V> {
8181
// the appended elements even if advancing the iterator panicks.
8282
*length += 1;
8383
}
84-
self.fix_right_edge();
84+
self.fix_right_border_of_plentiful();
8585
}
8686

87-
fn fix_right_edge(&mut self) {
88-
// Handle underfull nodes, start from the top.
87+
/// Stock up any underfull nodes on the right border of the tree.
88+
/// The other nodes, those that are not the root nor a rightmost edge,
89+
/// must have MIN_LEN elements to spare.
90+
fn fix_right_border_of_plentiful(&mut self) {
8991
let mut cur_node = self.borrow_mut();
9092
while let Internal(internal) = cur_node.force() {
9193
// Check if right-most child is underfull.
9294
let mut last_kv = internal.last_kv().consider_for_balancing();
95+
debug_assert!(last_kv.left_child_len() >= MIN_LEN * 2);
9396
let right_child_len = last_kv.right_child_len();
9497
if right_child_len < MIN_LEN {
9598
// We need to steal.

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

+19-1
Original file line numberDiff line numberDiff line change
@@ -1821,7 +1821,6 @@ fn test_append_ord_chaos() {
18211821
}
18221822

18231823
fn rand_data(len: usize) -> Vec<(u32, u32)> {
1824-
assert!(len * 2 <= 70029); // from that point on numbers repeat
18251824
let mut rng = DeterministicRng::new();
18261825
Vec::from_iter((0..len).map(|_| (rng.next(), rng.next())))
18271826
}
@@ -1886,6 +1885,25 @@ fn test_split_off_tiny_right_height_2() {
18861885
assert_eq!(*right.last_key_value().unwrap().0, last);
18871886
}
18881887

1888+
#[test]
1889+
fn test_split_off_halfway() {
1890+
let mut rng = DeterministicRng::new();
1891+
for &len in &[NODE_CAPACITY, 25, 50, 75, 100] {
1892+
let mut data = Vec::from_iter((0..len).map(|_| (rng.next(), ())));
1893+
// Insertion in non-ascending order creates some variation in node length.
1894+
let mut map = BTreeMap::from_iter(data.iter().copied());
1895+
data.sort();
1896+
let small_keys = data.iter().take(len / 2).map(|kv| kv.0);
1897+
let large_keys = data.iter().skip(len / 2).map(|kv| kv.0);
1898+
let split_key = large_keys.clone().next().unwrap();
1899+
let right = map.split_off(&split_key);
1900+
map.check();
1901+
right.check();
1902+
assert!(map.keys().copied().eq(small_keys));
1903+
assert!(right.keys().copied().eq(large_keys));
1904+
}
1905+
}
1906+
18891907
#[test]
18901908
fn test_split_off_large_random_sorted() {
18911909
// Miri is too slow

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

+5-2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ pub unsafe fn unwrap_unchecked<T>(val: Option<T>) -> T {
3838
#[cfg(test)]
3939
/// XorShiftRng
4040
struct DeterministicRng {
41+
count: usize,
4142
x: u32,
4243
y: u32,
4344
z: u32,
@@ -47,11 +48,13 @@ struct DeterministicRng {
4748
#[cfg(test)]
4849
impl DeterministicRng {
4950
fn new() -> Self {
50-
DeterministicRng { x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
51+
DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
5152
}
5253

53-
/// Guarantees that the first 70029 results are unique.
54+
/// Guarantees that each returned number is unique.
5455
fn next(&mut self) -> u32 {
56+
self.count += 1;
57+
assert!(self.count <= 70029);
5558
let x = self.x;
5659
let t = x ^ (x << 11);
5760
self.x = self.y;

library/alloc/src/collections/btree/set/tests.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -696,8 +696,10 @@ fn test_first_last() {
696696
assert_eq!(a.pop_last(), None);
697697
}
698698

699+
// Unlike the function with the same name in map/tests, returns no values.
700+
// Which also means it returns different predetermined pseudo-random keys,
701+
// and the test cases using this function explore slightly different trees.
699702
fn rand_data(len: usize) -> Vec<u32> {
700-
assert!(len <= 70029); // from that point on numbers repeat
701703
let mut rng = DeterministicRng::new();
702704
Vec::from_iter((0..len).map(|_| rng.next()))
703705
}

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

+5
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ impl<K, V> Root<K, V> {
5353
}
5454
}
5555

56+
/// Stock up or merge away any underfull nodes on the right border of the
57+
/// tree. The other nodes, those that are not the root nor a rightmost edge,
58+
/// must already have at least MIN_LEN elements.
5659
fn fix_right_border(&mut self) {
5760
self.fix_top();
5861

@@ -72,6 +75,7 @@ impl<K, V> Root<K, V> {
7275
}
7376
cur_node = last_kv.into_right_child();
7477
}
78+
debug_assert!(cur_node.len() > MIN_LEN);
7579
}
7680
}
7781

@@ -98,6 +102,7 @@ impl<K, V> Root<K, V> {
98102
}
99103
cur_node = first_kv.into_left_child();
100104
}
105+
debug_assert!(cur_node.len() > MIN_LEN);
101106
}
102107
}
103108

0 commit comments

Comments
 (0)