diff options
| author | Dylan DPC <dylan.dpc@gmail.com> | 2020-12-28 14:13:14 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-12-28 14:13:14 +0100 |
| commit | cefe40bb0c15d87a730b723e5cf24dfe7def5e57 (patch) | |
| tree | ec6452655a4bf1d822590d3b52f84a87b0b0df36 | |
| parent | c51172f38a901ab170432330dd943c5a9b1adb53 (diff) | |
| parent | d473cbe75b50dd583b582d0e99ba0c17228c1f86 (diff) | |
| download | rust-cefe40bb0c15d87a730b723e5cf24dfe7def5e57.tar.gz rust-cefe40bb0c15d87a730b723e5cf24dfe7def5e57.zip | |
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``
| -rw-r--r-- | library/alloc/src/collections/btree/append.rs | 9 | ||||
| -rw-r--r-- | library/alloc/src/collections/btree/map/tests.rs | 20 | ||||
| -rw-r--r-- | library/alloc/src/collections/btree/mod.rs | 7 | ||||
| -rw-r--r-- | library/alloc/src/collections/btree/set/tests.rs | 4 | ||||
| -rw-r--r-- | library/alloc/src/collections/btree/split.rs | 5 |
5 files changed, 38 insertions, 7 deletions
diff --git a/library/alloc/src/collections/btree/append.rs b/library/alloc/src/collections/btree/append.rs index 9c53c84f5b2..1d6488dd2df 100644 --- a/library/alloc/src/collections/btree/append.rs +++ b/library/alloc/src/collections/btree/append.rs @@ -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. diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 26f8f9da7ec..f92aed8ce15 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1821,7 +1821,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()))) } @@ -1887,6 +1886,25 @@ fn test_split_off_tiny_right_height_2() { } #[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 let mut data = if cfg!(miri) { rand_data(529) } else { rand_data(1529) }; diff --git a/library/alloc/src/collections/btree/mod.rs b/library/alloc/src/collections/btree/mod.rs index ebcbb0e467c..cdb39104047 100644 --- a/library/alloc/src/collections/btree/mod.rs +++ b/library/alloc/src/collections/btree/mod.rs @@ -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; diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs index 4d05bc4ebfa..fd19c0078a7 100644 --- a/library/alloc/src/collections/btree/set/tests.rs +++ b/library/alloc/src/collections/btree/set/tests.rs @@ -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())) } diff --git a/library/alloc/src/collections/btree/split.rs b/library/alloc/src/collections/btree/split.rs index 6108c139bb3..4561c8eaf47 100644 --- a/library/alloc/src/collections/btree/split.rs +++ b/library/alloc/src/collections/btree/split.rs @@ -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); } } |
