]> git.lizzy.rs Git - rust.git/commitdiff
define copy_within on slices
authorJack O'Connor <oconnor663@gmail.com>
Thu, 23 Aug 2018 22:22:53 +0000 (18:22 -0400)
committerJack O'Connor <oconnor663@gmail.com>
Thu, 20 Sep 2018 04:57:05 +0000 (00:57 -0400)
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.

src/libcore/slice/mod.rs

index da4a56cfecd6e5323c8cfc92a16f4213bc71cfe3..e4ac79a26d860957b48c83aac379bfc0dbbd6723 100644 (file)
@@ -1618,6 +1618,63 @@ pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy {
         }
     }
 
+    /// 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`.