]> git.lizzy.rs Git - rust.git/blobdiff - library/core/src/slice/mod.rs
Rollup merge of #88041 - Aaron1011:deny-proc-macro-hack, r=wesleywiser
[rust.git] / library / core / src / slice / mod.rs
index 53b8b343238d5f1b10b7c4065e6f2ce0d32a71ac..aaa00653b99c274cc6fda272fe74402d3143bfaa 100644 (file)
@@ -560,15 +560,52 @@ pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn swap(&mut self, a: usize, b: usize) {
-        // Can't take two mutable loans from one vector, so instead use raw pointers.
-        let pa = ptr::addr_of_mut!(self[a]);
-        let pb = ptr::addr_of_mut!(self[b]);
-        // SAFETY: `pa` and `pb` have been created from safe mutable references and refer
-        // to elements in the slice and therefore are guaranteed to be valid and aligned.
-        // Note that accessing the elements behind `a` and `b` is checked and will
-        // panic when out of bounds.
+        let _ = &self[a];
+        let _ = &self[b];
+
+        // SAFETY: we just checked that both `a` and `b` are in bounds
+        unsafe { self.swap_unchecked(a, b) }
+    }
+
+    /// Swaps two elements in the slice, without doing bounds checking.
+    ///
+    /// For a safe alternative see [`swap`].
+    ///
+    /// # Arguments
+    ///
+    /// * a - The index of the first element
+    /// * b - The index of the second element
+    ///
+    /// # Safety
+    ///
+    /// Calling this method with an out-of-bounds index is *[undefined behavior]*.
+    /// The caller has to ensure that `a < self.len()` and `b < self.len()`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(slice_swap_unchecked)]
+    ///
+    /// let mut v = ["a", "b", "c", "d"];
+    /// // SAFETY: we know that 1 and 3 are both indices of the slice
+    /// unsafe { v.swap_unchecked(1, 3) };
+    /// assert!(v == ["a", "d", "c", "b"]);
+    /// ```
+    ///
+    /// [`swap`]: slice::swap
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    #[unstable(feature = "slice_swap_unchecked", issue = "88539")]
+    pub unsafe fn swap_unchecked(&mut self, a: usize, b: usize) {
+        #[cfg(debug_assertions)]
+        {
+            let _ = &self[a];
+            let _ = &self[b];
+        }
+
+        let ptr = self.as_mut_ptr();
+        // SAFETY: caller has to guarantee that `a < self.len()` and `b < self.len()`
         unsafe {
-            ptr::swap(pa, pb);
+            ptr::swap(ptr.add(a), ptr.add(b));
         }
     }
 
@@ -675,11 +712,7 @@ pub fn reverse(&mut self) {
             // The resulting pointers `pa` and `pb` are therefore valid and
             // aligned, and can be read from and written to.
             unsafe {
-                // Unsafe swap to avoid the bounds check in safe swap.
-                let ptr = self.as_mut_ptr();
-                let pa = ptr.add(i);
-                let pb = ptr.add(ln - i - 1);
-                ptr::swap(pa, pb);
+                self.swap_unchecked(i, ln - i - 1);
             }
             i += 1;
         }
@@ -1632,6 +1665,80 @@ pub unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [
         unsafe { (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) }
     }
 
+    /// Divides one slice into an array and a remainder slice at an index.
+    ///
+    /// The array will contain all indices from `[0, N)` (excluding
+    /// the index `N` itself) and the slice will contain all
+    /// indices from `[N, len)` (excluding the index `len` itself).
+    ///
+    /// # Panics
+    ///
+    /// Panics if `N > len`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(split_array)]
+    ///
+    /// let v = &[1, 2, 3, 4, 5, 6][..];
+    ///
+    /// {
+    ///    let (left, right) = v.split_array_ref::<0>();
+    ///    assert_eq!(left, &[]);
+    ///    assert_eq!(right, [1, 2, 3, 4, 5, 6]);
+    /// }
+    ///
+    /// {
+    ///     let (left, right) = v.split_array_ref::<2>();
+    ///     assert_eq!(left, &[1, 2]);
+    ///     assert_eq!(right, [3, 4, 5, 6]);
+    /// }
+    ///
+    /// {
+    ///     let (left, right) = v.split_array_ref::<6>();
+    ///     assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
+    ///     assert_eq!(right, []);
+    /// }
+    /// ```
+    #[unstable(feature = "split_array", reason = "new API", issue = "90091")]
+    #[inline]
+    pub fn split_array_ref<const N: usize>(&self) -> (&[T; N], &[T]) {
+        let (a, b) = self.split_at(N);
+        // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at)
+        unsafe { (&*(a.as_ptr() as *const [T; N]), b) }
+    }
+
+    /// Divides one mutable slice into an array and a remainder slice at an index.
+    ///
+    /// The array will contain all indices from `[0, N)` (excluding
+    /// the index `N` itself) and the slice will contain all
+    /// indices from `[N, len)` (excluding the index `len` itself).
+    ///
+    /// # Panics
+    ///
+    /// Panics if `N > len`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(split_array)]
+    ///
+    /// let mut v = &mut [1, 0, 3, 0, 5, 6][..];
+    /// let (left, right) = v.split_array_mut::<2>();
+    /// assert_eq!(left, &mut [1, 0]);
+    /// assert_eq!(right, [3, 0, 5, 6]);
+    /// left[1] = 2;
+    /// right[1] = 4;
+    /// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
+    /// ```
+    #[unstable(feature = "split_array", reason = "new API", issue = "90091")]
+    #[inline]
+    pub fn split_array_mut<const N: usize>(&mut self) -> (&mut [T; N], &mut [T]) {
+        let (a, b) = self.split_at_mut(N);
+        // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at_mut)
+        unsafe { (&mut *(a.as_mut_ptr() as *mut [T; N]), b) }
+    }
+
     /// Returns an iterator over subslices separated by elements that match
     /// `pred`. The matched element is not contained in the subslices.
     ///
@@ -2920,9 +3027,6 @@ pub fn fill_with<F>(&mut self, mut f: F)
     ///
     /// The length of `src` must be the same as `self`.
     ///
-    /// If `T` implements `Copy`, it can be more performant to use
-    /// [`copy_from_slice`].
-    ///
     /// # Panics
     ///
     /// This function will panic if the two slices have different lengths.