|
7 | 7 | #![stable(feature = "rust1", since = "1.0.0")]
|
8 | 8 |
|
9 | 9 | use crate::cmp::Ordering::{self, Greater, Less};
|
| 10 | +use crate::fmt; |
10 | 11 | use crate::intrinsics::{assert_unsafe_precondition, exact_div};
|
11 | 12 | use crate::marker::Copy;
|
12 | 13 | use crate::mem::{self, SizedTypeProperties};
|
@@ -4082,6 +4083,88 @@ impl<T> [T] {
|
4082 | 4083 | *self = rem;
|
4083 | 4084 | Some(last)
|
4084 | 4085 | }
|
| 4086 | + |
| 4087 | + /// Returns mutable references to many indices at once, without doing any checks. |
| 4088 | + /// |
| 4089 | + /// For a safe alternative see [`get_many_mut`]. |
| 4090 | + /// |
| 4091 | + /// # Safety |
| 4092 | + /// |
| 4093 | + /// Calling this method with overlapping or out-of-bounds indices is *[undefined behavior]* |
| 4094 | + /// even if the resulting references are not used. |
| 4095 | + /// |
| 4096 | + /// # Examples |
| 4097 | + /// |
| 4098 | + /// ``` |
| 4099 | + /// #![feature(get_many_mut)] |
| 4100 | + /// |
| 4101 | + /// let x = &mut [1, 2, 4]; |
| 4102 | + /// |
| 4103 | + /// unsafe { |
| 4104 | + /// let [a, b] = x.get_many_unchecked_mut([0, 2]); |
| 4105 | + /// *a *= 10; |
| 4106 | + /// *b *= 100; |
| 4107 | + /// } |
| 4108 | + /// assert_eq!(x, &[10, 2, 400]); |
| 4109 | + /// ``` |
| 4110 | + /// |
| 4111 | + /// [`get_many_mut`]: slice::get_many_mut |
| 4112 | + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html |
| 4113 | + #[unstable(feature = "get_many_mut", issue = "104642")] |
| 4114 | + #[inline] |
| 4115 | + pub unsafe fn get_many_unchecked_mut<const N: usize>( |
| 4116 | + &mut self, |
| 4117 | + indices: [usize; N], |
| 4118 | + ) -> [&mut T; N] { |
| 4119 | + // NB: This implementation is written as it is because any variation of |
| 4120 | + // `indices.map(|i| self.get_unchecked_mut(i))` would make miri unhappy, |
| 4121 | + // or generate worse code otherwise. This is also why we need to go |
| 4122 | + // through a raw pointer here. |
| 4123 | + let slice: *mut [T] = self; |
| 4124 | + let mut arr: mem::MaybeUninit<[&mut T; N]> = mem::MaybeUninit::uninit(); |
| 4125 | + let arr_ptr = arr.as_mut_ptr(); |
| 4126 | + |
| 4127 | + // SAFETY: We expect `indices` to contain disjunct values that are |
| 4128 | + // in bounds of `self`. |
| 4129 | + unsafe { |
| 4130 | + for i in 0..N { |
| 4131 | + let idx = *indices.get_unchecked(i); |
| 4132 | + *(*arr_ptr).get_unchecked_mut(i) = &mut *slice.get_unchecked_mut(idx); |
| 4133 | + } |
| 4134 | + arr.assume_init() |
| 4135 | + } |
| 4136 | + } |
| 4137 | + |
| 4138 | + /// Returns mutable references to many indices at once. |
| 4139 | + /// |
| 4140 | + /// Returns an error if any index is out-of-bounds, or if the same index was |
| 4141 | + /// passed more than once. |
| 4142 | + /// |
| 4143 | + /// # Examples |
| 4144 | + /// |
| 4145 | + /// ``` |
| 4146 | + /// #![feature(get_many_mut)] |
| 4147 | + /// |
| 4148 | + /// let v = &mut [1, 2, 3]; |
| 4149 | + /// if let Ok([a, b]) = v.get_many_mut([0, 2]) { |
| 4150 | + /// *a = 413; |
| 4151 | + /// *b = 612; |
| 4152 | + /// } |
| 4153 | + /// assert_eq!(v, &[413, 2, 612]); |
| 4154 | + /// ``` |
| 4155 | + #[unstable(feature = "get_many_mut", issue = "104642")] |
| 4156 | + #[inline] |
| 4157 | + pub fn get_many_mut<const N: usize>( |
| 4158 | + &mut self, |
| 4159 | + indices: [usize; N], |
| 4160 | + ) -> Result<[&mut T; N], GetManyMutError<N>> { |
| 4161 | + if !get_many_check_valid(&indices, self.len()) { |
| 4162 | + return Err(GetManyMutError { _private: () }); |
| 4163 | + } |
| 4164 | + // SAFETY: The `get_many_check_valid()` call checked that all indices |
| 4165 | + // are disjunct and in bounds. |
| 4166 | + unsafe { Ok(self.get_many_unchecked_mut(indices)) } |
| 4167 | + } |
4085 | 4168 | }
|
4086 | 4169 |
|
4087 | 4170 | impl<T, const N: usize> [[T; N]] {
|
@@ -4304,3 +4387,56 @@ impl<T, const N: usize> SlicePattern for [T; N] {
|
4304 | 4387 | self
|
4305 | 4388 | }
|
4306 | 4389 | }
|
| 4390 | + |
| 4391 | +/// This checks every index against each other, and against `len`. |
| 4392 | +/// |
| 4393 | +/// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..` |
| 4394 | +/// comparison operations. |
| 4395 | +fn get_many_check_valid<const N: usize>(indices: &[usize; N], len: usize) -> bool { |
| 4396 | + // NB: The optimzer should inline the loops into a sequence |
| 4397 | + // of instructions without additional branching. |
| 4398 | + let mut valid = true; |
| 4399 | + for (i, &idx) in indices.iter().enumerate() { |
| 4400 | + valid &= idx < len; |
| 4401 | + for &idx2 in &indices[..i] { |
| 4402 | + valid &= idx != idx2; |
| 4403 | + } |
| 4404 | + } |
| 4405 | + valid |
| 4406 | +} |
| 4407 | + |
| 4408 | +/// The error type returned by [`get_many_mut<N>`][`slice::get_many_mut`]. |
| 4409 | +/// |
| 4410 | +/// It indicates one of two possible errors: |
| 4411 | +/// - An index is out-of-bounds. |
| 4412 | +/// - The same index appeared multiple times in the array. |
| 4413 | +/// |
| 4414 | +/// # Examples |
| 4415 | +/// |
| 4416 | +/// ``` |
| 4417 | +/// #![feature(get_many_mut)] |
| 4418 | +/// |
| 4419 | +/// let v = &mut [1, 2, 3]; |
| 4420 | +/// assert!(v.get_many_mut([0, 999]).is_err()); |
| 4421 | +/// assert!(v.get_many_mut([1, 1]).is_err()); |
| 4422 | +/// ``` |
| 4423 | +#[unstable(feature = "get_many_mut", issue = "104642")] |
| 4424 | +// NB: The N here is there to be forward-compatible with adding more details |
| 4425 | +// to the error type at a later point |
| 4426 | +pub struct GetManyMutError<const N: usize> { |
| 4427 | + _private: (), |
| 4428 | +} |
| 4429 | + |
| 4430 | +#[unstable(feature = "get_many_mut", issue = "104642")] |
| 4431 | +impl<const N: usize> fmt::Debug for GetManyMutError<N> { |
| 4432 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 4433 | + f.debug_struct("GetManyMutError").finish_non_exhaustive() |
| 4434 | + } |
| 4435 | +} |
| 4436 | + |
| 4437 | +#[unstable(feature = "get_many_mut", issue = "104642")] |
| 4438 | +impl<const N: usize> fmt::Display for GetManyMutError<N> { |
| 4439 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 4440 | + fmt::Display::fmt("an index is out of bounds or appeared multiple times in the array", f) |
| 4441 | + } |
| 4442 | +} |
0 commit comments