Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BTreeMap: test split_off (and append) more thoroughly #80353

Merged
merged 1 commit into from
Dec 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions library/alloc/src/collections/btree/append.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,18 @@ impl<K, V> Root<K, V> {
// the appended elements even if advancing the iterator panicks.
*length += 1;
}
self.fix_right_edge();
self.fix_right_border_of_plentiful();
}

fn fix_right_edge(&mut self) {
// Handle underfull nodes, start from the top.
/// Stock up any underfull nodes on the right border of the tree.
/// The other nodes, those that are not the root nor a rightmost edge,
/// must have MIN_LEN elements to spare.
fn fix_right_border_of_plentiful(&mut self) {
let mut cur_node = self.borrow_mut();
while let Internal(internal) = cur_node.force() {
// Check if right-most child is underfull.
let mut last_kv = internal.last_kv().consider_for_balancing();
debug_assert!(last_kv.left_child_len() >= MIN_LEN * 2);
let right_child_len = last_kv.right_child_len();
if right_child_len < MIN_LEN {
// We need to steal.
Expand Down
20 changes: 19 additions & 1 deletion library/alloc/src/collections/btree/map/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1797,7 +1797,6 @@ fn test_append_ord_chaos() {
}

fn rand_data(len: usize) -> Vec<(u32, u32)> {
assert!(len * 2 <= 70029); // from that point on numbers repeat
let mut rng = DeterministicRng::new();
Vec::from_iter((0..len).map(|_| (rng.next(), rng.next())))
}
Expand Down Expand Up @@ -1862,6 +1861,25 @@ fn test_split_off_tiny_right_height_2() {
assert_eq!(*right.last_key_value().unwrap().0, last);
}

#[test]
fn test_split_off_halfway() {
let mut rng = DeterministicRng::new();
for &len in &[NODE_CAPACITY, 25, 50, 75, 100] {
let mut data = Vec::from_iter((0..len).map(|_| (rng.next(), ())));
// Insertion in non-ascending order creates some variation in node length.
let mut map = BTreeMap::from_iter(data.iter().copied());
data.sort();
let small_keys = data.iter().take(len / 2).map(|kv| kv.0);
let large_keys = data.iter().skip(len / 2).map(|kv| kv.0);
let split_key = large_keys.clone().next().unwrap();
let right = map.split_off(&split_key);
map.check();
right.check();
assert!(map.keys().copied().eq(small_keys));
assert!(right.keys().copied().eq(large_keys));
}
}

#[test]
fn test_split_off_large_random_sorted() {
// Miri is too slow
Expand Down
7 changes: 5 additions & 2 deletions library/alloc/src/collections/btree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub unsafe fn unwrap_unchecked<T>(val: Option<T>) -> T {
#[cfg(test)]
/// XorShiftRng
struct DeterministicRng {
count: usize,
x: u32,
y: u32,
z: u32,
Expand All @@ -47,11 +48,13 @@ struct DeterministicRng {
#[cfg(test)]
impl DeterministicRng {
fn new() -> Self {
DeterministicRng { x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
}

/// Guarantees that the first 70029 results are unique.
/// Guarantees that each returned number is unique.
fn next(&mut self) -> u32 {
self.count += 1;
assert!(self.count <= 70029);
let x = self.x;
let t = x ^ (x << 11);
self.x = self.y;
Expand Down
4 changes: 3 additions & 1 deletion library/alloc/src/collections/btree/set/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -696,8 +696,10 @@ fn test_first_last() {
assert_eq!(a.pop_last(), None);
}

// Unlike the function with the same name in map/tests, returns no values.
// Which also means it returns different predetermined pseudo-random keys,
// and the test cases using this function explore slightly different trees.
fn rand_data(len: usize) -> Vec<u32> {
assert!(len <= 70029); // from that point on numbers repeat
let mut rng = DeterministicRng::new();
Vec::from_iter((0..len).map(|_| rng.next()))
}
Expand Down
5 changes: 5 additions & 0 deletions library/alloc/src/collections/btree/split.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ impl<K, V> Root<K, V> {
}
}

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

Expand All @@ -72,6 +75,7 @@ impl<K, V> Root<K, V> {
}
cur_node = last_kv.into_right_child();
}
debug_assert!(cur_node.len() > MIN_LEN);
}
}

Expand All @@ -98,6 +102,7 @@ impl<K, V> Root<K, V> {
}
cur_node = first_kv.into_left_child();
}
debug_assert!(cur_node.len() > MIN_LEN);
}
}

Expand Down