Skip to content

Commit b3ffd33

Browse files
committed
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.
1 parent 1d33aed commit b3ffd33

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

src/libcore/slice/mod.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,6 +1618,63 @@ impl<T> [T] {
16181618
}
16191619
}
16201620

1621+
/// Copies elements from one part of the slice to another part of itself,
1622+
/// using a memmove.
1623+
///
1624+
/// `src` is the range within `self` to copy from. `dest` is the starting
1625+
/// index of the range within `self` to copy to, which will have the same
1626+
/// length as `src`. The two ranges may overlap. The ends of the two ranges
1627+
/// must be less than or equal to `self.len()`.
1628+
///
1629+
/// # Panics
1630+
///
1631+
/// This function will panic if either range exceeds the end of the slice,
1632+
/// or if the end of `src` is before the start.
1633+
///
1634+
/// # Examples
1635+
///
1636+
/// Copying four bytes within a slice:
1637+
///
1638+
/// ```
1639+
/// # #![feature(copy_within)]
1640+
/// let mut bytes = *b"Hello, World!";
1641+
///
1642+
/// bytes.copy_within(1..5, 8);
1643+
///
1644+
/// assert_eq!(&bytes, b"Hello, Wello!");
1645+
/// ```
1646+
#[unstable(feature = "copy_within", issue = "54236")]
1647+
pub fn copy_within<R: ops::RangeBounds<usize>>(&mut self, src: R, dest: usize)
1648+
where
1649+
T: Copy,
1650+
{
1651+
let src_start = match src.start_bound() {
1652+
ops::Bound::Included(&n) => n,
1653+
ops::Bound::Excluded(&n) => n
1654+
.checked_add(1)
1655+
.unwrap_or_else(|| slice_index_overflow_fail()),
1656+
ops::Bound::Unbounded => 0,
1657+
};
1658+
let src_end = match src.end_bound() {
1659+
ops::Bound::Included(&n) => n
1660+
.checked_add(1)
1661+
.unwrap_or_else(|| slice_index_overflow_fail()),
1662+
ops::Bound::Excluded(&n) => n,
1663+
ops::Bound::Unbounded => self.len(),
1664+
};
1665+
assert!(src_start <= src_end, "src end is before src start");
1666+
assert!(src_end <= self.len(), "src is out of bounds");
1667+
let count = src_end - src_start;
1668+
assert!(dest <= self.len() - count, "dest is out of bounds");
1669+
unsafe {
1670+
ptr::copy(
1671+
self.get_unchecked(src_start),
1672+
self.get_unchecked_mut(dest),
1673+
count,
1674+
);
1675+
}
1676+
}
1677+
16211678
/// Swaps all elements in `self` with those in `other`.
16221679
///
16231680
/// The length of `other` must be the same as `self`.

0 commit comments

Comments
 (0)