BTreeMap: test split_off (and append) more thoroughly

This commit is contained in:
Stein Somers 2020-11-18 18:19:38 +01:00
parent c34c015fe2
commit d473cbe75b
5 changed files with 38 additions and 7 deletions

View File

@ -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.

View File

@ -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())))
}
@ -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

View File

@ -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,
@ -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;

View File

@ -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()))
}

View File

@ -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();
@ -72,6 +75,7 @@ impl<K, V> Root<K, V> {
}
cur_node = last_kv.into_right_child();
}
debug_assert!(cur_node.len() > MIN_LEN);
}
}
@ -98,6 +102,7 @@ impl<K, V> Root<K, V> {
}
cur_node = first_kv.into_left_child();
}
debug_assert!(cur_node.len() > MIN_LEN);
}
}