summaryrefslogtreecommitdiffstats
path: root/library/core/src/slice
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /library/core/src/slice
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/core/src/slice')
-rw-r--r--library/core/src/slice/index.rs21
-rw-r--r--library/core/src/slice/iter.rs32
-rw-r--r--library/core/src/slice/mod.rs173
3 files changed, 197 insertions, 29 deletions
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index 6d2f7330d..c295a0e06 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -31,9 +31,8 @@ where
}
}
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[cold]
#[track_caller]
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
@@ -48,19 +47,20 @@ const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
}
// FIXME const-hack
+#[inline]
#[track_caller]
fn slice_start_index_len_fail_rt(index: usize, len: usize) -> ! {
panic!("range start index {index} out of range for slice of length {len}");
}
+#[inline]
#[track_caller]
const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! {
panic!("slice start index is out of range for slice");
}
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[cold]
#[track_caller]
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
@@ -71,19 +71,20 @@ const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
}
// FIXME const-hack
+#[inline]
#[track_caller]
fn slice_end_index_len_fail_rt(index: usize, len: usize) -> ! {
panic!("range end index {index} out of range for slice of length {len}");
}
+#[inline]
#[track_caller]
const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! {
panic!("slice end index is out of range for slice");
}
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[cold]
#[track_caller]
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
const fn slice_index_order_fail(index: usize, end: usize) -> ! {
@@ -92,27 +93,27 @@ const fn slice_index_order_fail(index: usize, end: usize) -> ! {
}
// FIXME const-hack
+#[inline]
#[track_caller]
fn slice_index_order_fail_rt(index: usize, end: usize) -> ! {
panic!("slice index starts at {index} but ends at {end}");
}
+#[inline]
#[track_caller]
const fn slice_index_order_fail_ct(_: usize, _: usize) -> ! {
panic!("slice index start is larger than end");
}
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[cold]
#[track_caller]
const fn slice_start_index_overflow_fail() -> ! {
panic!("attempted to index slice from after maximum usize");
}
-#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
-#[cold]
#[track_caller]
const fn slice_end_index_overflow_fail() -> ! {
panic!("attempted to index slice up to maximum usize");
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index 8a8962828..062289767 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -1834,6 +1834,20 @@ impl<'a, T> ChunksExact<'a, T> {
/// Returns the remainder of the original slice that is not going to be
/// returned by the iterator. The returned slice has at most `chunk_size-1`
/// elements.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// let slice = ['l', 'o', 'r', 'e', 'm'];
+ /// let mut iter = slice.chunks_exact(2);
+ /// assert_eq!(iter.remainder(), &['m'][..]);
+ /// assert_eq!(iter.next(), Some(&['l', 'o'][..]));
+ /// assert_eq!(iter.remainder(), &['m'][..]);
+ /// assert_eq!(iter.next(), Some(&['r', 'e'][..]));
+ /// assert_eq!(iter.remainder(), &['m'][..]);
+ /// assert_eq!(iter.next(), None);
+ /// assert_eq!(iter.remainder(), &['m'][..]);
+ /// ```
#[must_use]
#[stable(feature = "chunks_exact", since = "1.31.0")]
pub fn remainder(&self) -> &'a [T] {
@@ -2869,7 +2883,7 @@ unsafe impl<T> Sync for RChunksMut<'_, T> where T: Sync {}
/// ```
///
/// [`rchunks_exact`]: slice::rchunks_exact
-/// [`remainder`]: ChunksExact::remainder
+/// [`remainder`]: RChunksExact::remainder
/// [slices]: slice
#[derive(Debug)]
#[stable(feature = "rchunks", since = "1.31.0")]
@@ -2892,6 +2906,20 @@ impl<'a, T> RChunksExact<'a, T> {
/// Returns the remainder of the original slice that is not going to be
/// returned by the iterator. The returned slice has at most `chunk_size-1`
/// elements.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// let slice = ['l', 'o', 'r', 'e', 'm'];
+ /// let mut iter = slice.rchunks_exact(2);
+ /// assert_eq!(iter.remainder(), &['l'][..]);
+ /// assert_eq!(iter.next(), Some(&['e', 'm'][..]));
+ /// assert_eq!(iter.remainder(), &['l'][..]);
+ /// assert_eq!(iter.next(), Some(&['o', 'r'][..]));
+ /// assert_eq!(iter.remainder(), &['l'][..]);
+ /// assert_eq!(iter.next(), None);
+ /// assert_eq!(iter.remainder(), &['l'][..]);
+ /// ```
#[must_use]
#[stable(feature = "rchunks", since = "1.31.0")]
pub fn remainder(&self) -> &'a [T] {
@@ -3031,7 +3059,7 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExact<'a, T> {
/// ```
///
/// [`rchunks_exact_mut`]: slice::rchunks_exact_mut
-/// [`into_remainder`]: ChunksExactMut::into_remainder
+/// [`into_remainder`]: RChunksExactMut::into_remainder
/// [slices]: slice
#[derive(Debug)]
#[stable(feature = "rchunks", since = "1.31.0")]
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)
+ }
+}