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

BTree: lighten the load on Miri #68781

Merged
merged 2 commits into from
Feb 17, 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: 4 additions & 5 deletions src/liballoc/collections/btree/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ impl<K: Clone, V: Clone> BTreeClone for BTreeMap<K, V> {
impl<K: Clone + Ord, V: Clone> BTreeClone for BTreeMap<K, V> {
fn clone_from(&mut self, other: &Self) {
// This truncates `self` to `other.len()` by calling `split_off` on
// the first key after `other.len()` elements if it exists
// the first key after `other.len()` elements if it exists.
let split_off_key = if self.len() > other.len() {
let diff = self.len() - other.len();
if diff <= other.len() {
Expand All @@ -247,19 +247,18 @@ impl<K: Clone + Ord, V: Clone> BTreeClone for BTreeMap<K, V> {
// After truncation, `self` is at most as long as `other` so this loop
// replaces every key-value pair in `self`. Since `oiter` is in sorted
// order and the structure of the `BTreeMap` stays the same,
// the BTree invariants are maintained at the end of the loop
// the BTree invariants are maintained at the end of the loop.
while !siter.is_empty() {
if let Some((ok, ov)) = oiter.next() {
// SAFETY: This is safe because the `siter.front != siter.back` check
// ensures that `siter` is nonempty
// SAFETY: This is safe because `siter` is nonempty.
let (sk, sv) = unsafe { siter.next_unchecked() };
sk.clone_from(ok);
sv.clone_from(ov);
} else {
break;
}
}
// If `other` is longer than `self`, the remaining elements are inserted
// If `other` is longer than `self`, the remaining elements are inserted.
self.extend(oiter.map(|(k, v)| ((*k).clone(), (*v).clone())));
}
}
Expand Down
52 changes: 32 additions & 20 deletions src/liballoc/tests/btree/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn test_basic_large() {
#[cfg(not(miri))] // Miri is too slow
let size = 10000;
#[cfg(miri)]
let size = 200;
let size = 144; // to obtain height 3 tree (having edges to both kinds of nodes)
assert_eq!(map.len(), 0);

for i in 0..size {
Expand Down Expand Up @@ -381,8 +381,8 @@ fn test_range_small() {
}

#[test]
fn test_range_depth_2() {
// Assuming that node.CAPACITY is 11, having 12 pairs implies a depth 2 tree
fn test_range_height_2() {
// Assuming that node.CAPACITY is 11, having 12 pairs implies a height 2 tree
// with 2 leaves. Depending on details we don't want or need to rely upon,
// the single key at the root will be 6 or 7.

Expand Down Expand Up @@ -524,7 +524,7 @@ fn test_range_1000() {
#[cfg(not(miri))] // Miri is too slow
let size = 1000;
#[cfg(miri)]
let size = 200;
let size = 144; // to obtain height 3 tree (having edges to both kinds of nodes)
let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect();

fn test(map: &BTreeMap<u32, u32>, size: u32, min: Bound<&u32>, max: Bound<&u32>) {
Expand Down Expand Up @@ -561,14 +561,15 @@ fn test_range_borrowed_key() {

#[test]
fn test_range() {
#[cfg(not(miri))] // Miri is too slow
let size = 200;
#[cfg(not(miri))] // Miri is too slow
let step = 1;
#[cfg(miri)]
let size = 30;
let step = 66;
let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect();

for i in 0..size {
for j in i..size {
for i in (0..size).step_by(step) {
for j in (i..size).step_by(step) {
let mut kvs = map.range((Included(&i), Included(&j))).map(|(&k, &v)| (k, v));
let mut pairs = (i..=j).map(|i| (i, i));

Expand All @@ -583,14 +584,15 @@ fn test_range() {

#[test]
fn test_range_mut() {
#[cfg(not(miri))] // Miri is too slow
let size = 200;
#[cfg(not(miri))] // Miri is too slow
let step = 1;
#[cfg(miri)]
let size = 30;
let step = 66;
let mut map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect();

for i in 0..size {
for j in i..size {
for i in (0..size).step_by(step) {
for j in (i..size).step_by(step) {
let mut kvs = map.range_mut((Included(&i), Included(&j))).map(|(&k, &mut v)| (k, v));
let mut pairs = (i..=j).map(|i| (i, i));

Expand Down Expand Up @@ -758,10 +760,7 @@ fn test_bad_zst() {
#[test]
fn test_clone() {
let mut map = BTreeMap::new();
#[cfg(not(miri))] // Miri is too slow
let size = 100;
#[cfg(miri)]
let size = 30;
let size = 12; // to obtain height 2 tree (having edges to leaf nodes)
assert_eq!(map.len(), 0);

for i in 0..size {
ssomers marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -788,24 +787,36 @@ fn test_clone() {
assert_eq!(map.len(), size / 2 - i - 1);
assert_eq!(map, map.clone());
}

// Full 2-level and minimal 3-level tree (sizes 143, 144 -- the only ones we clone for).
for i in 1..=144 {
assert_eq!(map.insert(i, i), None);
assert_eq!(map.len(), i);
if i >= 143 {
assert_eq!(map, map.clone());
}
}
}

#[test]
fn test_clone_from() {
let mut map1 = BTreeMap::new();
let size = 30;
let max_size = 12; // to obtain height 2 tree (having edges to leaf nodes)

for i in 0..size {
// Range to max_size inclusive, because i is the size of map1 being tested.
for i in 0..=max_size {
let mut map2 = BTreeMap::new();
for j in 0..i {
let mut map1_copy = map2.clone();
map1_copy.clone_from(&map1);
map1_copy.clone_from(&map1); // small cloned from large
assert_eq!(map1_copy, map1);
let mut map2_copy = map1.clone();
map2_copy.clone_from(&map2);
map2_copy.clone_from(&map2); // large cloned from small
assert_eq!(map2_copy, map2);
map2.insert(100 * j + 1, 2 * j + 1);
}
map2.clone_from(&map1); // same length
assert_eq!(map2, map1);
map1.insert(i, 10 * i);
}
}
Expand Down Expand Up @@ -956,6 +967,7 @@ create_append_test!(test_append_145, 145);
// Tests for several randomly chosen sizes.
create_append_test!(test_append_170, 170);
create_append_test!(test_append_181, 181);
#[cfg(not(miri))] // Miri is too slow
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
create_append_test!(test_append_239, 239);
#[cfg(not(miri))] // Miri is too slow
create_append_test!(test_append_1700, 1700);
Expand Down