@@ -10,10 +10,10 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less};
1010use crate :: intrinsics:: { exact_div, select_unpredictable, unchecked_sub} ;
1111use crate :: mem:: { self , SizedTypeProperties } ;
1212use crate :: num:: NonZero ;
13- use crate :: ops:: { Bound , OneSidedRange , Range , RangeBounds } ;
13+ use crate :: ops:: { Bound , OneSidedRange , Range , RangeBounds , RangeInclusive } ;
1414use crate :: simd:: { self , Simd } ;
1515use crate :: ub_checks:: assert_unsafe_precondition;
16- use crate :: { fmt, hint, ptr, slice} ;
16+ use crate :: { fmt, hint, ptr, range , slice} ;
1717
1818#[ unstable(
1919 feature = "slice_internals" ,
@@ -4467,6 +4467,12 @@ impl<T> [T] {
44674467
44684468 /// Returns mutable references to many indices at once, without doing any checks.
44694469 ///
4470+ /// An index can be either a `usize` or a [`Range`] or a [`RangeInclusive`] (note
4471+ /// that this method takes an array, so all indices must be of the same type).
4472+ /// If passed an array of `usize`s this method gives back an array of mutable references
4473+ /// to single elements, while if passed an array of ranges it gives back an array of
4474+ /// mutable references to slices.
4475+ ///
44704476 /// For a safe alternative see [`get_many_mut`].
44714477 ///
44724478 /// # Safety
@@ -4487,39 +4493,68 @@ impl<T> [T] {
44874493 /// *b *= 100;
44884494 /// }
44894495 /// assert_eq!(x, &[10, 2, 400]);
4496+ ///
4497+ /// unsafe {
4498+ /// let [a, b] = x.get_many_unchecked_mut([0..1, 1..3]);
4499+ /// a[0] = 8;
4500+ /// b[0] = 88;
4501+ /// b[1] = 888;
4502+ /// }
4503+ /// assert_eq!(x, &[8, 88, 888]);
4504+ ///
4505+ /// unsafe {
4506+ /// let [a, b] = x.get_many_unchecked_mut([1..=2, 0..=0]);
4507+ /// a[0] = 11;
4508+ /// a[1] = 111;
4509+ /// b[0] = 1;
4510+ /// }
4511+ /// assert_eq!(x, &[1, 11, 111]);
44904512 /// ```
44914513 ///
44924514 /// [`get_many_mut`]: slice::get_many_mut
44934515 /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
44944516 #[ unstable( feature = "get_many_mut" , issue = "104642" ) ]
44954517 #[ inline]
4496- pub unsafe fn get_many_unchecked_mut < const N : usize > (
4518+ pub unsafe fn get_many_unchecked_mut < I , const N : usize > (
44974519 & mut self ,
4498- indices : [ usize ; N ] ,
4499- ) -> [ & mut T ; N ] {
4520+ indices : [ I ; N ] ,
4521+ ) -> [ & mut I :: Output ; N ]
4522+ where
4523+ I : GetManyMutIndex + SliceIndex < Self > ,
4524+ {
45004525 // NB: This implementation is written as it is because any variation of
45014526 // `indices.map(|i| self.get_unchecked_mut(i))` would make miri unhappy,
45024527 // or generate worse code otherwise. This is also why we need to go
45034528 // through a raw pointer here.
45044529 let slice: * mut [ T ] = self ;
4505- let mut arr: mem:: MaybeUninit < [ & mut T ; N ] > = mem:: MaybeUninit :: uninit ( ) ;
4530+ let mut arr: mem:: MaybeUninit < [ & mut I :: Output ; N ] > = mem:: MaybeUninit :: uninit ( ) ;
45064531 let arr_ptr = arr. as_mut_ptr ( ) ;
45074532
45084533 // SAFETY: We expect `indices` to contain disjunct values that are
45094534 // in bounds of `self`.
45104535 unsafe {
45114536 for i in 0 ..N {
4512- let idx = * indices. get_unchecked ( i) ;
4513- * ( * arr_ptr) . get_unchecked_mut ( i) = & mut * slice. get_unchecked_mut ( idx) ;
4537+ let idx = indices. get_unchecked ( i) . clone ( ) ;
4538+ arr_ptr. cast :: < & mut I :: Output > ( ) . add ( i) . write ( & mut * slice. get_unchecked_mut ( idx) ) ;
45144539 }
45154540 arr. assume_init ( )
45164541 }
45174542 }
45184543
45194544 /// Returns mutable references to many indices at once.
45204545 ///
4521- /// Returns an error if any index is out-of-bounds, or if the same index was
4522- /// passed more than once.
4546+ /// An index can be either a `usize` or a [`Range`] or a [`RangeInclusive`] (note
4547+ /// that this method takes an array, so all indices must be of the same type).
4548+ /// If passed an array of `usize`s this method gives back an array of mutable references
4549+ /// to single elements, while if passed an array of ranges it gives back an array of
4550+ /// mutable references to slices.
4551+ ///
4552+ /// Returns an error if any index is out-of-bounds, or if there are overlapping indices.
4553+ /// An empty range is not considered to overlap if it is located at the beginning or at
4554+ /// the end of another range, but is considered to overlap if it is located in the middle.
4555+ ///
4556+ /// This method does a O(n^2) check to check that there are no overlapping indices, so be careful
4557+ /// when passing many indices.
45234558 ///
45244559 /// # Examples
45254560 ///
@@ -4532,13 +4567,30 @@ impl<T> [T] {
45324567 /// *b = 612;
45334568 /// }
45344569 /// assert_eq!(v, &[413, 2, 612]);
4570+ ///
4571+ /// if let Ok([a, b]) = v.get_many_mut([0..1, 1..3]) {
4572+ /// a[0] = 8;
4573+ /// b[0] = 88;
4574+ /// b[1] = 888;
4575+ /// }
4576+ /// assert_eq!(v, &[8, 88, 888]);
4577+ ///
4578+ /// if let Ok([a, b]) = v.get_many_mut([1..=2, 0..=0]) {
4579+ /// a[0] = 11;
4580+ /// a[1] = 111;
4581+ /// b[0] = 1;
4582+ /// }
4583+ /// assert_eq!(v, &[1, 11, 111]);
45354584 /// ```
45364585 #[ unstable( feature = "get_many_mut" , issue = "104642" ) ]
45374586 #[ inline]
4538- pub fn get_many_mut < const N : usize > (
4587+ pub fn get_many_mut < I , const N : usize > (
45394588 & mut self ,
4540- indices : [ usize ; N ] ,
4541- ) -> Result < [ & mut T ; N ] , GetManyMutError < N > > {
4589+ indices : [ I ; N ] ,
4590+ ) -> Result < [ & mut I :: Output ; N ] , GetManyMutError < N > >
4591+ where
4592+ I : GetManyMutIndex + SliceIndex < Self > ,
4593+ {
45424594 if !get_many_check_valid ( & indices, self . len ( ) ) {
45434595 return Err ( GetManyMutError { _private : ( ) } ) ;
45444596 }
@@ -4883,14 +4935,15 @@ impl<T, const N: usize> SlicePattern for [T; N] {
48834935///
48844936/// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..`
48854937/// comparison operations.
4886- fn get_many_check_valid < const N : usize > ( indices : & [ usize ; N ] , len : usize ) -> bool {
4938+ #[ inline]
4939+ fn get_many_check_valid < I : GetManyMutIndex , const N : usize > ( indices : & [ I ; N ] , len : usize ) -> bool {
48874940 // NB: The optimizer should inline the loops into a sequence
48884941 // of instructions without additional branching.
48894942 let mut valid = true ;
4890- for ( i, & idx) in indices. iter ( ) . enumerate ( ) {
4891- valid &= idx < len;
4892- for & idx2 in & indices[ ..i] {
4893- valid &= idx != idx2;
4943+ for ( i, idx) in indices. iter ( ) . enumerate ( ) {
4944+ valid &= idx. is_in_bounds ( len) ;
4945+ for idx2 in & indices[ ..i] {
4946+ valid &= !idx . is_overlapping ( idx2) ;
48944947 }
48954948 }
48964949 valid
@@ -4914,6 +4967,7 @@ fn get_many_check_valid<const N: usize>(indices: &[usize; N], len: usize) -> boo
49144967#[ unstable( feature = "get_many_mut" , issue = "104642" ) ]
49154968// NB: The N here is there to be forward-compatible with adding more details
49164969// to the error type at a later point
4970+ #[ derive( Clone , PartialEq , Eq ) ]
49174971pub struct GetManyMutError < const N : usize > {
49184972 _private : ( ) ,
49194973}
@@ -4931,3 +4985,93 @@ impl<const N: usize> fmt::Display for GetManyMutError<N> {
49314985 fmt:: Display :: fmt ( "an index is out of bounds or appeared multiple times in the array" , f)
49324986 }
49334987}
4988+
4989+ /// A helper trait for `<[T]>::get_many_mut()`.
4990+ ///
4991+ /// # Safety
4992+ ///
4993+ /// If `is_in_bounds()` returns `true` and `is_overlapping()` returns `false`,
4994+ /// it must be safe to index the slice with the indices.
4995+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
4996+ pub unsafe trait GetManyMutIndex : Clone {
4997+ /// Returns `true` if `self` is in bounds for `len` slice elements.
4998+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
4999+ fn is_in_bounds ( & self , len : usize ) -> bool ;
5000+
5001+ /// Returns `true` if `self` overlaps with `other`.
5002+ ///
5003+ /// Note that we don't consider zero-length ranges to overlap at the beginning or the end,
5004+ /// but do consider them to overlap in the middle.
5005+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5006+ fn is_overlapping ( & self , other : & Self ) -> bool ;
5007+ }
5008+
5009+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5010+ // SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
5011+ unsafe impl GetManyMutIndex for usize {
5012+ #[ inline]
5013+ fn is_in_bounds ( & self , len : usize ) -> bool {
5014+ * self < len
5015+ }
5016+
5017+ #[ inline]
5018+ fn is_overlapping ( & self , other : & Self ) -> bool {
5019+ * self == * other
5020+ }
5021+ }
5022+
5023+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5024+ // SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
5025+ unsafe impl GetManyMutIndex for Range < usize > {
5026+ #[ inline]
5027+ fn is_in_bounds ( & self , len : usize ) -> bool {
5028+ ( self . start <= self . end ) & ( self . end <= len)
5029+ }
5030+
5031+ #[ inline]
5032+ fn is_overlapping ( & self , other : & Self ) -> bool {
5033+ ( self . start < other. end ) & ( other. start < self . end )
5034+ }
5035+ }
5036+
5037+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5038+ // SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
5039+ unsafe impl GetManyMutIndex for RangeInclusive < usize > {
5040+ #[ inline]
5041+ fn is_in_bounds ( & self , len : usize ) -> bool {
5042+ ( self . start <= self . end ) & ( self . end < len)
5043+ }
5044+
5045+ #[ inline]
5046+ fn is_overlapping ( & self , other : & Self ) -> bool {
5047+ ( self . start <= other. end ) & ( other. start <= self . end )
5048+ }
5049+ }
5050+
5051+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5052+ // SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
5053+ unsafe impl GetManyMutIndex for range:: Range < usize > {
5054+ #[ inline]
5055+ fn is_in_bounds ( & self , len : usize ) -> bool {
5056+ Range :: from ( * self ) . is_in_bounds ( len)
5057+ }
5058+
5059+ #[ inline]
5060+ fn is_overlapping ( & self , other : & Self ) -> bool {
5061+ Range :: from ( * self ) . is_overlapping ( & Range :: from ( * other) )
5062+ }
5063+ }
5064+
5065+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5066+ // SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
5067+ unsafe impl GetManyMutIndex for range:: RangeInclusive < usize > {
5068+ #[ inline]
5069+ fn is_in_bounds ( & self , len : usize ) -> bool {
5070+ RangeInclusive :: from ( * self ) . is_in_bounds ( len)
5071+ }
5072+
5073+ #[ inline]
5074+ fn is_overlapping ( & self , other : & Self ) -> bool {
5075+ RangeInclusive :: from ( * self ) . is_overlapping ( & RangeInclusive :: from ( * other) )
5076+ }
5077+ }
0 commit comments