summaryrefslogtreecommitdiffstats
path: root/library/core/src/slice/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/core/src/slice/mod.rs')
-rw-r--r--library/core/src/slice/mod.rs173
1 files changed, 156 insertions, 17 deletions
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 4f1bb1734..d9281a925 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -7,6 +7,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
use crate::cmp::Ordering::{self, Greater, Less};
+use crate::fmt;
use crate::intrinsics::{assert_unsafe_precondition, exact_div};
use crate::marker::Copy;
use crate::mem::{self, SizedTypeProperties};
@@ -464,7 +465,7 @@ impl<T> [T] {
/// [`as_mut_ptr`]: slice::as_mut_ptr
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")]
- #[inline]
+ #[inline(always)]
#[must_use]
pub const fn as_ptr(&self) -> *const T {
self as *const [T] as *const T
@@ -494,7 +495,7 @@ impl<T> [T] {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
#[rustc_allow_const_fn_unstable(const_mut_refs)]
- #[inline]
+ #[inline(always)]
#[must_use]
pub const fn as_mut_ptr(&mut self) -> *mut T {
self as *mut [T] as *mut T
@@ -3467,10 +3468,11 @@ impl<T> [T] {
/// maintained.
///
/// This method splits the slice into three distinct slices: prefix, correctly aligned middle
- /// slice of a new type, and the suffix slice. The method may make the middle slice the greatest
- /// length possible for a given type and input slice, but only your algorithm's performance
- /// should depend on that, not its correctness. It is permissible for all of the input data to
- /// be returned as the prefix or suffix slice.
+ /// slice of a new type, and the suffix slice. How exactly the slice is split up is not
+ /// specified; the middle part may be smaller than necessary. However, if this fails to return a
+ /// maximal middle part, that is because code is running in a context where performance does not
+ /// matter, such as a sanitizer attempting to find alignment bugs. Regular code running
+ /// in a default (debug or release) execution *will* return a maximal middle part.
///
/// This method has no purpose when either input element `T` or output element `U` are
/// zero-sized and will return the original slice without splitting anything.
@@ -3524,14 +3526,15 @@ impl<T> [T] {
}
}
- /// Transmute the slice to a slice of another type, ensuring alignment of the types is
- /// maintained.
+ /// Transmute the mutable slice to a mutable slice of another type, ensuring alignment of the
+ /// types is maintained.
///
/// This method splits the slice into three distinct slices: prefix, correctly aligned middle
- /// slice of a new type, and the suffix slice. The method may make the middle slice the greatest
- /// length possible for a given type and input slice, but only your algorithm's performance
- /// should depend on that, not its correctness. It is permissible for all of the input data to
- /// be returned as the prefix or suffix slice.
+ /// slice of a new type, and the suffix slice. How exactly the slice is split up is not
+ /// specified; the middle part may be smaller than necessary. However, if this fails to return a
+ /// maximal middle part, that is because code is running in a context where performance does not
+ /// matter, such as a sanitizer attempting to find alignment bugs. Regular code running
+ /// in a default (debug or release) execution *will* return a maximal middle part.
///
/// This method has no purpose when either input element `T` or output element `U` are
/// zero-sized and will return the original slice without splitting anything.
@@ -3667,7 +3670,8 @@ impl<T> [T] {
unsafe { self.align_to() }
}
- /// Split a slice into a prefix, a middle of aligned SIMD types, and a suffix.
+ /// Split a mutable slice into a mutable prefix, a middle of aligned SIMD types,
+ /// and a mutable suffix.
///
/// This is a safe wrapper around [`slice::align_to_mut`], so has the same weak
/// postconditions as that method. You're only assured that
@@ -3751,9 +3755,9 @@ impl<T> [T] {
/// [`is_sorted`]: slice::is_sorted
#[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
#[must_use]
- pub fn is_sorted_by<F>(&self, mut compare: F) -> bool
+ pub fn is_sorted_by<'a, F>(&'a self, mut compare: F) -> bool
where
- F: FnMut(&T, &T) -> Option<Ordering>,
+ F: FnMut(&'a T, &'a T) -> Option<Ordering>,
{
self.iter().is_sorted_by(|a, b| compare(*a, *b))
}
@@ -3777,9 +3781,9 @@ impl<T> [T] {
#[inline]
#[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
#[must_use]
- pub fn is_sorted_by_key<F, K>(&self, f: F) -> bool
+ pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool
where
- F: FnMut(&T) -> K,
+ F: FnMut(&'a T) -> K,
K: PartialOrd,
{
self.iter().is_sorted_by_key(f)
@@ -4081,6 +4085,88 @@ impl<T> [T] {
*self = rem;
Some(last)
}
+
+ /// Returns mutable references to many indices at once, without doing any checks.
+ ///
+ /// For a safe alternative see [`get_many_mut`].
+ ///
+ /// # Safety
+ ///
+ /// Calling this method with overlapping or out-of-bounds indices is *[undefined behavior]*
+ /// even if the resulting references are not used.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(get_many_mut)]
+ ///
+ /// let x = &mut [1, 2, 4];
+ ///
+ /// unsafe {
+ /// let [a, b] = x.get_many_unchecked_mut([0, 2]);
+ /// *a *= 10;
+ /// *b *= 100;
+ /// }
+ /// assert_eq!(x, &[10, 2, 400]);
+ /// ```
+ ///
+ /// [`get_many_mut`]: slice::get_many_mut
+ /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+ #[unstable(feature = "get_many_mut", issue = "104642")]
+ #[inline]
+ pub unsafe fn get_many_unchecked_mut<const N: usize>(
+ &mut self,
+ indices: [usize; N],
+ ) -> [&mut T; N] {
+ // NB: This implementation is written as it is because any variation of
+ // `indices.map(|i| self.get_unchecked_mut(i))` would make miri unhappy,
+ // or generate worse code otherwise. This is also why we need to go
+ // through a raw pointer here.
+ let slice: *mut [T] = self;
+ let mut arr: mem::MaybeUninit<[&mut T; N]> = mem::MaybeUninit::uninit();
+ let arr_ptr = arr.as_mut_ptr();
+
+ // SAFETY: We expect `indices` to contain disjunct values that are
+ // in bounds of `self`.
+ unsafe {
+ for i in 0..N {
+ let idx = *indices.get_unchecked(i);
+ *(*arr_ptr).get_unchecked_mut(i) = &mut *slice.get_unchecked_mut(idx);
+ }
+ arr.assume_init()
+ }
+ }
+
+ /// Returns mutable references to many indices at once.
+ ///
+ /// Returns an error if any index is out-of-bounds, or if the same index was
+ /// passed more than once.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(get_many_mut)]
+ ///
+ /// let v = &mut [1, 2, 3];
+ /// if let Ok([a, b]) = v.get_many_mut([0, 2]) {
+ /// *a = 413;
+ /// *b = 612;
+ /// }
+ /// assert_eq!(v, &[413, 2, 612]);
+ /// ```
+ #[unstable(feature = "get_many_mut", issue = "104642")]
+ #[inline]
+ pub fn get_many_mut<const N: usize>(
+ &mut self,
+ indices: [usize; N],
+ ) -> Result<[&mut T; N], GetManyMutError<N>> {
+ if !get_many_check_valid(&indices, self.len()) {
+ return Err(GetManyMutError { _private: () });
+ }
+ // SAFETY: The `get_many_check_valid()` call checked that all indices
+ // are disjunct and in bounds.
+ unsafe { Ok(self.get_many_unchecked_mut(indices)) }
+ }
}
impl<T, const N: usize> [[T; N]] {
@@ -4303,3 +4389,56 @@ impl<T, const N: usize> SlicePattern for [T; N] {
self
}
}
+
+/// This checks every index against each other, and against `len`.
+///
+/// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..`
+/// comparison operations.
+fn get_many_check_valid<const N: usize>(indices: &[usize; N], len: usize) -> bool {
+ // NB: The optimzer should inline the loops into a sequence
+ // of instructions without additional branching.
+ let mut valid = true;
+ for (i, &idx) in indices.iter().enumerate() {
+ valid &= idx < len;
+ for &idx2 in &indices[..i] {
+ valid &= idx != idx2;
+ }
+ }
+ valid
+}
+
+/// The error type returned by [`get_many_mut<N>`][`slice::get_many_mut`].
+///
+/// It indicates one of two possible errors:
+/// - An index is out-of-bounds.
+/// - The same index appeared multiple times in the array.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(get_many_mut)]
+///
+/// let v = &mut [1, 2, 3];
+/// assert!(v.get_many_mut([0, 999]).is_err());
+/// assert!(v.get_many_mut([1, 1]).is_err());
+/// ```
+#[unstable(feature = "get_many_mut", issue = "104642")]
+// NB: The N here is there to be forward-compatible with adding more details
+// to the error type at a later point
+pub struct GetManyMutError<const N: usize> {
+ _private: (),
+}
+
+#[unstable(feature = "get_many_mut", issue = "104642")]
+impl<const N: usize> fmt::Debug for GetManyMutError<N> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("GetManyMutError").finish_non_exhaustive()
+ }
+}
+
+#[unstable(feature = "get_many_mut", issue = "104642")]
+impl<const N: usize> fmt::Display for GetManyMutError<N> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt("an index is out of bounds or appeared multiple times in the array", f)
+ }
+}