@@ -10,10 +10,10 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less};
10
10
use crate :: intrinsics:: { exact_div, select_unpredictable, unchecked_sub} ;
11
11
use crate :: mem:: { self , SizedTypeProperties } ;
12
12
use crate :: num:: NonZero ;
13
- use crate :: ops:: { Bound , OneSidedRange , Range , RangeBounds } ;
13
+ use crate :: ops:: { Bound , OneSidedRange , Range , RangeBounds , RangeInclusive } ;
14
14
use crate :: simd:: { self , Simd } ;
15
15
use crate :: ub_checks:: assert_unsafe_precondition;
16
- use crate :: { fmt, hint, ptr, slice} ;
16
+ use crate :: { fmt, hint, ptr, range , slice} ;
17
17
18
18
#[ unstable(
19
19
feature = "slice_internals" ,
@@ -4469,6 +4469,12 @@ impl<T> [T] {
4469
4469
4470
4470
/// Returns mutable references to many indices at once, without doing any checks.
4471
4471
///
4472
+ /// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note
4473
+ /// that this method takes an array, so all indices must be of the same type.
4474
+ /// If passed an array of `usize`s this method gives back an array of mutable references
4475
+ /// to single elements, while if passed an array of ranges it gives back an array of
4476
+ /// mutable references to slices.
4477
+ ///
4472
4478
/// For a safe alternative see [`get_many_mut`].
4473
4479
///
4474
4480
/// # Safety
@@ -4489,39 +4495,68 @@ impl<T> [T] {
4489
4495
/// *b *= 100;
4490
4496
/// }
4491
4497
/// assert_eq!(x, &[10, 2, 400]);
4498
+ ///
4499
+ /// unsafe {
4500
+ /// let [a, b] = x.get_many_unchecked_mut([0..1, 1..3]);
4501
+ /// a[0] = 8;
4502
+ /// b[0] = 88;
4503
+ /// b[1] = 888;
4504
+ /// }
4505
+ /// assert_eq!(x, &[8, 88, 888]);
4506
+ ///
4507
+ /// unsafe {
4508
+ /// let [a, b] = x.get_many_unchecked_mut([1..=2, 0..=0]);
4509
+ /// a[0] = 11;
4510
+ /// a[1] = 111;
4511
+ /// b[0] = 1;
4512
+ /// }
4513
+ /// assert_eq!(x, &[1, 11, 111]);
4492
4514
/// ```
4493
4515
///
4494
4516
/// [`get_many_mut`]: slice::get_many_mut
4495
4517
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
4496
4518
#[ unstable( feature = "get_many_mut" , issue = "104642" ) ]
4497
4519
#[ inline]
4498
- pub unsafe fn get_many_unchecked_mut < const N : usize > (
4520
+ pub unsafe fn get_many_unchecked_mut < I , const N : usize > (
4499
4521
& mut self ,
4500
- indices : [ usize ; N ] ,
4501
- ) -> [ & mut T ; N ] {
4522
+ indices : [ I ; N ] ,
4523
+ ) -> [ & mut I :: Output ; N ]
4524
+ where
4525
+ I : GetManyMutIndex + SliceIndex < Self > ,
4526
+ {
4502
4527
// NB: This implementation is written as it is because any variation of
4503
4528
// `indices.map(|i| self.get_unchecked_mut(i))` would make miri unhappy,
4504
4529
// or generate worse code otherwise. This is also why we need to go
4505
4530
// through a raw pointer here.
4506
4531
let slice: * mut [ T ] = self ;
4507
- let mut arr: mem:: MaybeUninit < [ & mut T ; N ] > = mem:: MaybeUninit :: uninit ( ) ;
4532
+ let mut arr: mem:: MaybeUninit < [ & mut I :: Output ; N ] > = mem:: MaybeUninit :: uninit ( ) ;
4508
4533
let arr_ptr = arr. as_mut_ptr ( ) ;
4509
4534
4510
4535
// SAFETY: We expect `indices` to contain disjunct values that are
4511
4536
// in bounds of `self`.
4512
4537
unsafe {
4513
4538
for i in 0 ..N {
4514
- let idx = * indices. get_unchecked ( i) ;
4515
- * ( * arr_ptr) . get_unchecked_mut ( i) = & mut * slice. get_unchecked_mut ( idx) ;
4539
+ let idx = indices. get_unchecked ( i) . clone ( ) ;
4540
+ arr_ptr. cast :: < & mut I :: Output > ( ) . add ( i) . write ( & mut * slice. get_unchecked_mut ( idx) ) ;
4516
4541
}
4517
4542
arr. assume_init ( )
4518
4543
}
4519
4544
}
4520
4545
4521
4546
/// Returns mutable references to many indices at once.
4522
4547
///
4523
- /// Returns an error if any index is out-of-bounds, or if the same index was
4524
- /// passed more than once.
4548
+ /// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note
4549
+ /// that this method takes an array, so all indices must be of the same type.
4550
+ /// If passed an array of `usize`s this method gives back an array of mutable references
4551
+ /// to single elements, while if passed an array of ranges it gives back an array of
4552
+ /// mutable references to slices.
4553
+ ///
4554
+ /// Returns an error if any index is out-of-bounds, or if there are overlapping indices.
4555
+ /// An empty range is not considered to overlap if it is located at the beginning or at
4556
+ /// the end of another range, but is considered to overlap if it is located in the middle.
4557
+ ///
4558
+ /// This method does a O(n^2) check to check that there are no overlapping indices, so be careful
4559
+ /// when passing many indices.
4525
4560
///
4526
4561
/// # Examples
4527
4562
///
@@ -4534,13 +4569,30 @@ impl<T> [T] {
4534
4569
/// *b = 612;
4535
4570
/// }
4536
4571
/// assert_eq!(v, &[413, 2, 612]);
4572
+ ///
4573
+ /// if let Ok([a, b]) = v.get_many_mut([0..1, 1..3]) {
4574
+ /// a[0] = 8;
4575
+ /// b[0] = 88;
4576
+ /// b[1] = 888;
4577
+ /// }
4578
+ /// assert_eq!(v, &[8, 88, 888]);
4579
+ ///
4580
+ /// if let Ok([a, b]) = v.get_many_mut([1..=2, 0..=0]) {
4581
+ /// a[0] = 11;
4582
+ /// a[1] = 111;
4583
+ /// b[0] = 1;
4584
+ /// }
4585
+ /// assert_eq!(v, &[1, 11, 111]);
4537
4586
/// ```
4538
4587
#[ unstable( feature = "get_many_mut" , issue = "104642" ) ]
4539
4588
#[ inline]
4540
- pub fn get_many_mut < const N : usize > (
4589
+ pub fn get_many_mut < I , const N : usize > (
4541
4590
& mut self ,
4542
- indices : [ usize ; N ] ,
4543
- ) -> Result < [ & mut T ; N ] , GetManyMutError < N > > {
4591
+ indices : [ I ; N ] ,
4592
+ ) -> Result < [ & mut I :: Output ; N ] , GetManyMutError < N > >
4593
+ where
4594
+ I : GetManyMutIndex + SliceIndex < Self > ,
4595
+ {
4544
4596
if !get_many_check_valid ( & indices, self . len ( ) ) {
4545
4597
return Err ( GetManyMutError { _private : ( ) } ) ;
4546
4598
}
@@ -4885,14 +4937,15 @@ impl<T, const N: usize> SlicePattern for [T; N] {
4885
4937
///
4886
4938
/// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..`
4887
4939
/// comparison operations.
4888
- fn get_many_check_valid < const N : usize > ( indices : & [ usize ; N ] , len : usize ) -> bool {
4940
+ #[ inline]
4941
+ fn get_many_check_valid < I : GetManyMutIndex , const N : usize > ( indices : & [ I ; N ] , len : usize ) -> bool {
4889
4942
// NB: The optimizer should inline the loops into a sequence
4890
4943
// of instructions without additional branching.
4891
4944
let mut valid = true ;
4892
- for ( i, & idx) in indices. iter ( ) . enumerate ( ) {
4893
- valid &= idx < len;
4894
- for & idx2 in & indices[ ..i] {
4895
- valid &= idx != idx2;
4945
+ for ( i, idx) in indices. iter ( ) . enumerate ( ) {
4946
+ valid &= idx. is_in_bounds ( len) ;
4947
+ for idx2 in & indices[ ..i] {
4948
+ valid &= !idx . is_overlapping ( idx2) ;
4896
4949
}
4897
4950
}
4898
4951
valid
@@ -4916,6 +4969,7 @@ fn get_many_check_valid<const N: usize>(indices: &[usize; N], len: usize) -> boo
4916
4969
#[ unstable( feature = "get_many_mut" , issue = "104642" ) ]
4917
4970
// NB: The N here is there to be forward-compatible with adding more details
4918
4971
// to the error type at a later point
4972
+ #[ derive( Clone , PartialEq , Eq ) ]
4919
4973
pub struct GetManyMutError < const N : usize > {
4920
4974
_private : ( ) ,
4921
4975
}
@@ -4933,3 +4987,111 @@ impl<const N: usize> fmt::Display for GetManyMutError<N> {
4933
4987
fmt:: Display :: fmt ( "an index is out of bounds or appeared multiple times in the array" , f)
4934
4988
}
4935
4989
}
4990
+
4991
+ mod private_get_many_mut_index {
4992
+ use super :: { Range , RangeInclusive , range} ;
4993
+
4994
+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
4995
+ pub trait Sealed { }
4996
+
4997
+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
4998
+ impl Sealed for usize { }
4999
+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5000
+ impl Sealed for Range < usize > { }
5001
+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5002
+ impl Sealed for RangeInclusive < usize > { }
5003
+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5004
+ impl Sealed for range:: Range < usize > { }
5005
+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5006
+ impl Sealed for range:: RangeInclusive < usize > { }
5007
+ }
5008
+
5009
+ /// A helper trait for `<[T]>::get_many_mut()`.
5010
+ ///
5011
+ /// # Safety
5012
+ ///
5013
+ /// If `is_in_bounds()` returns `true` and `is_overlapping()` returns `false`,
5014
+ /// it must be safe to index the slice with the indices.
5015
+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5016
+ pub unsafe trait GetManyMutIndex : Clone + private_get_many_mut_index:: Sealed {
5017
+ /// Returns `true` if `self` is in bounds for `len` slice elements.
5018
+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5019
+ fn is_in_bounds ( & self , len : usize ) -> bool ;
5020
+
5021
+ /// Returns `true` if `self` overlaps with `other`.
5022
+ ///
5023
+ /// Note that we don't consider zero-length ranges to overlap at the beginning or the end,
5024
+ /// but do consider them to overlap in the middle.
5025
+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5026
+ fn is_overlapping ( & self , other : & Self ) -> bool ;
5027
+ }
5028
+
5029
+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5030
+ // SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
5031
+ unsafe impl GetManyMutIndex for usize {
5032
+ #[ inline]
5033
+ fn is_in_bounds ( & self , len : usize ) -> bool {
5034
+ * self < len
5035
+ }
5036
+
5037
+ #[ inline]
5038
+ fn is_overlapping ( & self , other : & Self ) -> bool {
5039
+ * self == * other
5040
+ }
5041
+ }
5042
+
5043
+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5044
+ // SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
5045
+ unsafe impl GetManyMutIndex for Range < usize > {
5046
+ #[ inline]
5047
+ fn is_in_bounds ( & self , len : usize ) -> bool {
5048
+ ( self . start <= self . end ) & ( self . end <= len)
5049
+ }
5050
+
5051
+ #[ inline]
5052
+ fn is_overlapping ( & self , other : & Self ) -> bool {
5053
+ ( self . start < other. end ) & ( other. start < self . end )
5054
+ }
5055
+ }
5056
+
5057
+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5058
+ // SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
5059
+ unsafe impl GetManyMutIndex for RangeInclusive < usize > {
5060
+ #[ inline]
5061
+ fn is_in_bounds ( & self , len : usize ) -> bool {
5062
+ ( self . start <= self . end ) & ( self . end < len)
5063
+ }
5064
+
5065
+ #[ inline]
5066
+ fn is_overlapping ( & self , other : & Self ) -> bool {
5067
+ ( self . start <= other. end ) & ( other. start <= self . end )
5068
+ }
5069
+ }
5070
+
5071
+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5072
+ // SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
5073
+ unsafe impl GetManyMutIndex for range:: Range < usize > {
5074
+ #[ inline]
5075
+ fn is_in_bounds ( & self , len : usize ) -> bool {
5076
+ Range :: from ( * self ) . is_in_bounds ( len)
5077
+ }
5078
+
5079
+ #[ inline]
5080
+ fn is_overlapping ( & self , other : & Self ) -> bool {
5081
+ Range :: from ( * self ) . is_overlapping ( & Range :: from ( * other) )
5082
+ }
5083
+ }
5084
+
5085
+ #[ unstable( feature = "get_many_mut_helpers" , issue = "none" ) ]
5086
+ // SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
5087
+ unsafe impl GetManyMutIndex for range:: RangeInclusive < usize > {
5088
+ #[ inline]
5089
+ fn is_in_bounds ( & self , len : usize ) -> bool {
5090
+ RangeInclusive :: from ( * self ) . is_in_bounds ( len)
5091
+ }
5092
+
5093
+ #[ inline]
5094
+ fn is_overlapping ( & self , other : & Self ) -> bool {
5095
+ RangeInclusive :: from ( * self ) . is_overlapping ( & RangeInclusive :: from ( * other) )
5096
+ }
5097
+ }
0 commit comments