diff options
| author | Ralf Jung <post@ralfj.de> | 2020-05-30 13:45:06 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-05-30 13:45:06 +0200 |
| commit | 8d64fd80adef2c80325f7a5a545108035198daba (patch) | |
| tree | d4c7cc359f8fe829430ca74ed89883f1b0aa72e2 /src/liballoc | |
| parent | 49ca99de93f8ed26b16ac2ef70c61c7ed2267754 (diff) | |
| parent | dbf32e2270f82601bd2816da270ce70269cc59ba (diff) | |
| download | rust-8d64fd80adef2c80325f7a5a545108035198daba.tar.gz rust-8d64fd80adef2c80325f7a5a545108035198daba.zip | |
Rollup merge of #72499 - mendess:master, r=dtolnay
Override Box::<[T]>::clone_from Avoid dropping and reallocating when cloning to an existing box if the lengths are the same. It would be nice if this could also be specialized for `Copy` but I don't know how that works since it's not on stable. Will gladly look into it if it's deemed as a good idea. This is my first PR with code, hope I did everything right :smile:
Diffstat (limited to 'src/liballoc')
| -rw-r--r-- | src/liballoc/boxed.rs | 8 | ||||
| -rw-r--r-- | src/liballoc/tests/boxed.rs | 33 |
2 files changed, 41 insertions, 0 deletions
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 8cc6f04c065..22c344323a2 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -1109,6 +1109,14 @@ impl<T: Clone> Clone for Box<[T]> { fn clone(&self) -> Self { self.to_vec().into_boxed_slice() } + + fn clone_from(&mut self, other: &Self) { + if self.len() == other.len() { + self.clone_from_slice(&other); + } else { + *self = other.clone(); + } + } } #[stable(feature = "box_borrow", since = "1.1.0")] diff --git a/src/liballoc/tests/boxed.rs b/src/liballoc/tests/boxed.rs index 66782ecbeb7..5377485da8f 100644 --- a/src/liballoc/tests/boxed.rs +++ b/src/liballoc/tests/boxed.rs @@ -16,3 +16,36 @@ fn unitialized_zero_size_box() { NonNull::<MaybeUninit<String>>::dangling().as_ptr(), ); } + +#[derive(Clone, PartialEq, Eq, Debug)] +struct Dummy { + _data: u8, +} + +#[test] +fn box_clone_and_clone_from_equivalence() { + for size in (0..8).map(|i| 2usize.pow(i)) { + let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); + let clone = control.clone(); + let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice(); + copy.clone_from(&control); + assert_eq!(control, clone); + assert_eq!(control, copy); + } +} + +/// This test might give a false positive in case the box realocates, but the alocator keeps the +/// original pointer. +/// +/// On the other hand it won't give a false negative, if it fails than the memory was definitly not +/// reused +#[test] +fn box_clone_from_ptr_stability() { + for size in (0..8).map(|i| 2usize.pow(i)) { + let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); + let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice(); + let copy_raw = copy.as_ptr() as usize; + copy.clone_from(&control); + assert_eq!(copy.as_ptr() as usize, copy_raw); + } +} |
