Skip to content

Commit

Permalink
Auto merge of #134633 - GrigorenkoPV:get_disjoint_mut, r=cuviper
Browse files Browse the repository at this point in the history
Stabilize `get_many_mut` as `get_disjoint_mut`

Tracking issue: #104642

Closes #104642

FCP completed in #104642 (comment)
  • Loading branch information
bors committed Feb 13, 2025
2 parents c241e14 + 1abc853 commit a567209
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 103 deletions.
4 changes: 2 additions & 2 deletions library/alloc/src/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ pub use core::slice::ArrayChunksMut;
pub use core::slice::ArrayWindows;
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
pub use core::slice::EscapeAscii;
#[unstable(feature = "get_many_mut", issue = "104642")]
pub use core::slice::GetManyMutError;
#[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")]
pub use core::slice::GetDisjointMutError;
#[stable(feature = "slice_get_slice", since = "1.28.0")]
pub use core::slice::SliceIndex;
#[cfg(not(no_global_oom_handling))]
Expand Down
4 changes: 2 additions & 2 deletions library/core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1075,5 +1075,5 @@ impl Error for crate::time::TryFromFloatSecsError {}
#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
impl Error for crate::ffi::FromBytesUntilNulError {}

#[unstable(feature = "get_many_mut", issue = "104642")]
impl Error for crate::slice::GetManyMutError {}
#[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")]
impl Error for crate::slice::GetDisjointMutError {}
115 changes: 56 additions & 59 deletions library/core/src/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4531,7 +4531,7 @@ impl<T> [T] {
/// to single elements, while if passed an array of ranges it gives back an array of
/// mutable references to slices.
///
/// For a safe alternative see [`get_many_mut`].
/// For a safe alternative see [`get_disjoint_mut`].
///
/// # Safety
///
Expand All @@ -4541,44 +4541,42 @@ impl<T> [T] {
/// # Examples
///
/// ```
/// #![feature(get_many_mut)]
///
/// let x = &mut [1, 2, 4];
///
/// unsafe {
/// let [a, b] = x.get_many_unchecked_mut([0, 2]);
/// let [a, b] = x.get_disjoint_unchecked_mut([0, 2]);
/// *a *= 10;
/// *b *= 100;
/// }
/// assert_eq!(x, &[10, 2, 400]);
///
/// unsafe {
/// let [a, b] = x.get_many_unchecked_mut([0..1, 1..3]);
/// let [a, b] = x.get_disjoint_unchecked_mut([0..1, 1..3]);
/// a[0] = 8;
/// b[0] = 88;
/// b[1] = 888;
/// }
/// assert_eq!(x, &[8, 88, 888]);
///
/// unsafe {
/// let [a, b] = x.get_many_unchecked_mut([1..=2, 0..=0]);
/// let [a, b] = x.get_disjoint_unchecked_mut([1..=2, 0..=0]);
/// a[0] = 11;
/// a[1] = 111;
/// b[0] = 1;
/// }
/// assert_eq!(x, &[1, 11, 111]);
/// ```
///
/// [`get_many_mut`]: slice::get_many_mut
/// [`get_disjoint_mut`]: slice::get_disjoint_mut
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
#[unstable(feature = "get_many_mut", issue = "104642")]
#[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub unsafe fn get_many_unchecked_mut<I, const N: usize>(
pub unsafe fn get_disjoint_unchecked_mut<I, const N: usize>(
&mut self,
indices: [I; N],
) -> [&mut I::Output; N]
where
I: GetManyMutIndex + SliceIndex<Self>,
I: GetDisjointMutIndex + SliceIndex<Self>,
{
// NB: This implementation is written as it is because any variation of
// `indices.map(|i| self.get_unchecked_mut(i))` would make miri unhappy,
Expand Down Expand Up @@ -4617,42 +4615,40 @@ impl<T> [T] {
/// # Examples
///
/// ```
/// #![feature(get_many_mut)]
///
/// let v = &mut [1, 2, 3];
/// if let Ok([a, b]) = v.get_many_mut([0, 2]) {
/// if let Ok([a, b]) = v.get_disjoint_mut([0, 2]) {
/// *a = 413;
/// *b = 612;
/// }
/// assert_eq!(v, &[413, 2, 612]);
///
/// if let Ok([a, b]) = v.get_many_mut([0..1, 1..3]) {
/// if let Ok([a, b]) = v.get_disjoint_mut([0..1, 1..3]) {
/// a[0] = 8;
/// b[0] = 88;
/// b[1] = 888;
/// }
/// assert_eq!(v, &[8, 88, 888]);
///
/// if let Ok([a, b]) = v.get_many_mut([1..=2, 0..=0]) {
/// if let Ok([a, b]) = v.get_disjoint_mut([1..=2, 0..=0]) {
/// a[0] = 11;
/// a[1] = 111;
/// b[0] = 1;
/// }
/// assert_eq!(v, &[1, 11, 111]);
/// ```
#[unstable(feature = "get_many_mut", issue = "104642")]
#[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub fn get_many_mut<I, const N: usize>(
pub fn get_disjoint_mut<I, const N: usize>(
&mut self,
indices: [I; N],
) -> Result<[&mut I::Output; N], GetManyMutError>
) -> Result<[&mut I::Output; N], GetDisjointMutError>
where
I: GetManyMutIndex + SliceIndex<Self>,
I: GetDisjointMutIndex + SliceIndex<Self>,
{
get_many_check_valid(&indices, self.len())?;
// SAFETY: The `get_many_check_valid()` call checked that all indices
get_disjoint_check_valid(&indices, self.len())?;
// SAFETY: The `get_disjoint_check_valid()` call checked that all indices
// are disjunct and in bounds.
unsafe { Ok(self.get_many_unchecked_mut(indices)) }
unsafe { Ok(self.get_disjoint_unchecked_mut(indices)) }
}

/// Returns the index that an element reference points to.
Expand Down Expand Up @@ -4994,26 +4990,26 @@ impl<T, const N: usize> SlicePattern for [T; N] {
/// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..`
/// comparison operations.
#[inline]
fn get_many_check_valid<I: GetManyMutIndex, const N: usize>(
fn get_disjoint_check_valid<I: GetDisjointMutIndex, const N: usize>(
indices: &[I; N],
len: usize,
) -> Result<(), GetManyMutError> {
) -> Result<(), GetDisjointMutError> {
// NB: The optimizer should inline the loops into a sequence
// of instructions without additional branching.
for (i, idx) in indices.iter().enumerate() {
if !idx.is_in_bounds(len) {
return Err(GetManyMutError::IndexOutOfBounds);
return Err(GetDisjointMutError::IndexOutOfBounds);
}
for idx2 in &indices[..i] {
if idx.is_overlapping(idx2) {
return Err(GetManyMutError::OverlappingIndices);
return Err(GetDisjointMutError::OverlappingIndices);
}
}
}
Ok(())
}

/// The error type returned by [`get_many_mut`][`slice::get_many_mut`].
/// The error type returned by [`get_disjoint_mut`][`slice::get_disjoint_mut`].
///
/// It indicates one of two possible errors:
/// - An index is out-of-bounds.
Expand All @@ -5023,74 +5019,75 @@ fn get_many_check_valid<I: GetManyMutIndex, const N: usize>(
/// # Examples
///
/// ```
/// #![feature(get_many_mut)]
/// use std::slice::GetManyMutError;
/// use std::slice::GetDisjointMutError;
///
/// let v = &mut [1, 2, 3];
/// assert_eq!(v.get_many_mut([0, 999]), Err(GetManyMutError::IndexOutOfBounds));
/// assert_eq!(v.get_many_mut([1, 1]), Err(GetManyMutError::OverlappingIndices));
/// assert_eq!(v.get_disjoint_mut([0, 999]), Err(GetDisjointMutError::IndexOutOfBounds));
/// assert_eq!(v.get_disjoint_mut([1, 1]), Err(GetDisjointMutError::OverlappingIndices));
/// ```
#[unstable(feature = "get_many_mut", issue = "104642")]
#[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GetManyMutError {
pub enum GetDisjointMutError {
/// An index provided was out-of-bounds for the slice.
IndexOutOfBounds,
/// Two indices provided were overlapping.
OverlappingIndices,
}

#[unstable(feature = "get_many_mut", issue = "104642")]
impl fmt::Display for GetManyMutError {
#[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")]
impl fmt::Display for GetDisjointMutError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let msg = match self {
GetManyMutError::IndexOutOfBounds => "an index is out of bounds",
GetManyMutError::OverlappingIndices => "there were overlapping indices",
GetDisjointMutError::IndexOutOfBounds => "an index is out of bounds",
GetDisjointMutError::OverlappingIndices => "there were overlapping indices",
};
fmt::Display::fmt(msg, f)
}
}

mod private_get_many_mut_index {
mod private_get_disjoint_mut_index {
use super::{Range, RangeInclusive, range};

#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
pub trait Sealed {}

#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
impl Sealed for usize {}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
impl Sealed for Range<usize> {}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
impl Sealed for RangeInclusive<usize> {}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
impl Sealed for range::Range<usize> {}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
impl Sealed for range::RangeInclusive<usize> {}
}

/// A helper trait for `<[T]>::get_many_mut()`.
/// A helper trait for `<[T]>::get_disjoint_mut()`.
///
/// # Safety
///
/// If `is_in_bounds()` returns `true` and `is_overlapping()` returns `false`,
/// it must be safe to index the slice with the indices.
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
pub unsafe trait GetManyMutIndex: Clone + private_get_many_mut_index::Sealed {
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
pub unsafe trait GetDisjointMutIndex:
Clone + private_get_disjoint_mut_index::Sealed
{
/// Returns `true` if `self` is in bounds for `len` slice elements.
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
fn is_in_bounds(&self, len: usize) -> bool;

/// Returns `true` if `self` overlaps with `other`.
///
/// Note that we don't consider zero-length ranges to overlap at the beginning or the end,
/// but do consider them to overlap in the middle.
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
fn is_overlapping(&self, other: &Self) -> bool;
}

#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
unsafe impl GetManyMutIndex for usize {
unsafe impl GetDisjointMutIndex for usize {
#[inline]
fn is_in_bounds(&self, len: usize) -> bool {
*self < len
Expand All @@ -5102,9 +5099,9 @@ unsafe impl GetManyMutIndex for usize {
}
}

#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
unsafe impl GetManyMutIndex for Range<usize> {
unsafe impl GetDisjointMutIndex for Range<usize> {
#[inline]
fn is_in_bounds(&self, len: usize) -> bool {
(self.start <= self.end) & (self.end <= len)
Expand All @@ -5116,9 +5113,9 @@ unsafe impl GetManyMutIndex for Range<usize> {
}
}

#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
unsafe impl GetManyMutIndex for RangeInclusive<usize> {
unsafe impl GetDisjointMutIndex for RangeInclusive<usize> {
#[inline]
fn is_in_bounds(&self, len: usize) -> bool {
(self.start <= self.end) & (self.end < len)
Expand All @@ -5130,9 +5127,9 @@ unsafe impl GetManyMutIndex for RangeInclusive<usize> {
}
}

#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
unsafe impl GetManyMutIndex for range::Range<usize> {
unsafe impl GetDisjointMutIndex for range::Range<usize> {
#[inline]
fn is_in_bounds(&self, len: usize) -> bool {
Range::from(*self).is_in_bounds(len)
Expand All @@ -5144,9 +5141,9 @@ unsafe impl GetManyMutIndex for range::Range<usize> {
}
}

#[unstable(feature = "get_many_mut_helpers", issue = "none")]
#[unstable(feature = "get_disjoint_mut_helpers", issue = "none")]
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
unsafe impl GetManyMutIndex for range::RangeInclusive<usize> {
unsafe impl GetDisjointMutIndex for range::RangeInclusive<usize> {
#[inline]
fn is_in_bounds(&self, len: usize) -> bool {
RangeInclusive::from(*self).is_in_bounds(len)
Expand Down
1 change: 0 additions & 1 deletion library/coretests/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
#![feature(freeze)]
#![feature(future_join)]
#![feature(generic_assert_internals)]
#![feature(get_many_mut)]
#![feature(hasher_prefixfree_extras)]
#![feature(hashmap_internals)]
#![feature(inline_const_pat)]
Expand Down
Loading

0 comments on commit a567209

Please sign in to comment.