Rollup merge of #53652 - oconnor663:copy_in_place, r=alexcrichton
define copy_within on slices This is a safe wrapper around `ptr::copy`, for regions within a single slice. Previously, safe in-place copying was only available as a side effect of `Vec::drain`. I've wanted this API a couple times in the past, and I figured I'd just whip up a PR to help discuss it. It's possible something like this exists elsewhere and I just missed it. It might also be a big enough addition to warrant an RFC, I'm not sure.
This commit is contained in:
commit
e6ee4e056d
@ -1618,6 +1618,63 @@ impl<T> [T] {
|
||||
}
|
||||
}
|
||||
|
||||
/// Copies elements from one part of the slice to another part of itself,
|
||||
/// using a memmove.
|
||||
///
|
||||
/// `src` is the range within `self` to copy from. `dest` is the starting
|
||||
/// index of the range within `self` to copy to, which will have the same
|
||||
/// length as `src`. The two ranges may overlap. The ends of the two ranges
|
||||
/// must be less than or equal to `self.len()`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if either range exceeds the end of the slice,
|
||||
/// or if the end of `src` is before the start.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Copying four bytes within a slice:
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(copy_within)]
|
||||
/// let mut bytes = *b"Hello, World!";
|
||||
///
|
||||
/// bytes.copy_within(1..5, 8);
|
||||
///
|
||||
/// assert_eq!(&bytes, b"Hello, Wello!");
|
||||
/// ```
|
||||
#[unstable(feature = "copy_within", issue = "54236")]
|
||||
pub fn copy_within<R: ops::RangeBounds<usize>>(&mut self, src: R, dest: usize)
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
let src_start = match src.start_bound() {
|
||||
ops::Bound::Included(&n) => n,
|
||||
ops::Bound::Excluded(&n) => n
|
||||
.checked_add(1)
|
||||
.unwrap_or_else(|| slice_index_overflow_fail()),
|
||||
ops::Bound::Unbounded => 0,
|
||||
};
|
||||
let src_end = match src.end_bound() {
|
||||
ops::Bound::Included(&n) => n
|
||||
.checked_add(1)
|
||||
.unwrap_or_else(|| slice_index_overflow_fail()),
|
||||
ops::Bound::Excluded(&n) => n,
|
||||
ops::Bound::Unbounded => self.len(),
|
||||
};
|
||||
assert!(src_start <= src_end, "src end is before src start");
|
||||
assert!(src_end <= self.len(), "src is out of bounds");
|
||||
let count = src_end - src_start;
|
||||
assert!(dest <= self.len() - count, "dest is out of bounds");
|
||||
unsafe {
|
||||
ptr::copy(
|
||||
self.get_unchecked(src_start),
|
||||
self.get_unchecked_mut(dest),
|
||||
count,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Swaps all elements in `self` with those in `other`.
|
||||
///
|
||||
/// The length of `other` must be the same as `self`.
|
||||
|
@ -39,6 +39,7 @@
|
||||
#![feature(inner_deref)]
|
||||
#![feature(slice_internals)]
|
||||
#![feature(option_replace)]
|
||||
#![feature(copy_within)]
|
||||
|
||||
extern crate core;
|
||||
extern crate test;
|
||||
|
@ -1000,3 +1000,49 @@ fn test_align_to_empty_mid() {
|
||||
assert_eq!(mid.as_ptr() as usize % mem::align_of::<Chunk>(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy_within() {
|
||||
// Start to end, with a RangeTo.
|
||||
let mut bytes = *b"Hello, World!";
|
||||
bytes.copy_within(..3, 10);
|
||||
assert_eq!(&bytes, b"Hello, WorHel");
|
||||
|
||||
// End to start, with a RangeFrom.
|
||||
let mut bytes = *b"Hello, World!";
|
||||
bytes.copy_within(10.., 0);
|
||||
assert_eq!(&bytes, b"ld!lo, World!");
|
||||
|
||||
// Overlapping, with a RangeInclusive.
|
||||
let mut bytes = *b"Hello, World!";
|
||||
bytes.copy_within(0..=11, 1);
|
||||
assert_eq!(&bytes, b"HHello, World");
|
||||
|
||||
// Whole slice, with a RangeFull.
|
||||
let mut bytes = *b"Hello, World!";
|
||||
bytes.copy_within(.., 0);
|
||||
assert_eq!(&bytes, b"Hello, World!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "src is out of bounds")]
|
||||
fn test_copy_within_panics_src_too_long() {
|
||||
let mut bytes = *b"Hello, World!";
|
||||
// The length is only 13, so 14 is out of bounds.
|
||||
bytes.copy_within(10..14, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "dest is out of bounds")]
|
||||
fn test_copy_within_panics_dest_too_long() {
|
||||
let mut bytes = *b"Hello, World!";
|
||||
// The length is only 13, so a slice of length 4 starting at index 10 is out of bounds.
|
||||
bytes.copy_within(0..4, 10);
|
||||
}
|
||||
#[test]
|
||||
#[should_panic(expected = "src end is before src start")]
|
||||
fn test_copy_within_panics_src_inverted() {
|
||||
let mut bytes = *b"Hello, World!";
|
||||
// 2 is greater than 1, so this range is invalid.
|
||||
bytes.copy_within(2..1, 0);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user