Auto merge of #75021 - cuviper:array_chunks_mut, r=scottmcm
Add `slice::array_chunks_mut` This follows `array_chunks` from #74373 with a mutable version, `array_chunks_mut`. The implementation is identical apart from mutability. The new tests are adaptations of the `chunks_exact_mut` tests, plus an inference test like the one for `array_chunks`. I reused the unstable feature `array_chunks` and tracking issue #74985, but I can separate that if desired. r? `@withoutboats` cc `@lcnr`
This commit is contained in:
commit
8b6838b6e1
@ -93,6 +93,8 @@
|
||||
|
||||
#[unstable(feature = "array_chunks", issue = "74985")]
|
||||
pub use core::slice::ArrayChunks;
|
||||
#[unstable(feature = "array_chunks", issue = "74985")]
|
||||
pub use core::slice::ArrayChunksMut;
|
||||
#[stable(feature = "slice_get_slice", since = "1.28.0")]
|
||||
pub use core::slice::SliceIndex;
|
||||
#[stable(feature = "from_ref", since = "1.28.0")]
|
||||
|
@ -996,9 +996,9 @@ pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> {
|
||||
/// Returns an iterator over `N` elements of the slice at a time, starting at the
|
||||
/// beginning of the slice.
|
||||
///
|
||||
/// The chunks are slices and do not overlap. If `N` does not divide the length of the
|
||||
/// slice, then the last up to `N-1` elements will be omitted and can be retrieved
|
||||
/// from the `remainder` function of the iterator.
|
||||
/// The chunks are array references and do not overlap. If `N` does not divide the
|
||||
/// length of the slice, then the last up to `N-1` elements will be omitted and can be
|
||||
/// retrieved from the `remainder` function of the iterator.
|
||||
///
|
||||
/// This method is the const generic equivalent of [`chunks_exact`].
|
||||
///
|
||||
@ -1032,6 +1032,49 @@ pub fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N> {
|
||||
ArrayChunks { iter: array_slice.iter(), rem: snd }
|
||||
}
|
||||
|
||||
/// Returns an iterator over `N` elements of the slice at a time, starting at the
|
||||
/// beginning of the slice.
|
||||
///
|
||||
/// The chunks are mutable array references and do not overlap. If `N` does not divide
|
||||
/// the length of the slice, then the last up to `N-1` elements will be omitted and
|
||||
/// can be retrieved from the `into_remainder` function of the iterator.
|
||||
///
|
||||
/// This method is the const generic equivalent of [`chunks_exact_mut`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `N` is 0. This check will most probably get changed to a compile time
|
||||
/// error before this method gets stabilized.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(array_chunks)]
|
||||
/// let v = &mut [0, 0, 0, 0, 0];
|
||||
/// let mut count = 1;
|
||||
///
|
||||
/// for chunk in v.array_chunks_mut() {
|
||||
/// *chunk = [count; 2];
|
||||
/// count += 1;
|
||||
/// }
|
||||
/// assert_eq!(v, &[1, 1, 2, 2, 0]);
|
||||
/// ```
|
||||
///
|
||||
/// [`chunks_exact_mut`]: #method.chunks_exact_mut
|
||||
#[unstable(feature = "array_chunks", issue = "74985")]
|
||||
#[inline]
|
||||
pub fn array_chunks_mut<const N: usize>(&mut self) -> ArrayChunksMut<'_, T, N> {
|
||||
assert_ne!(N, 0);
|
||||
let len = self.len() / N;
|
||||
let (fst, snd) = self.split_at_mut(len * N);
|
||||
// SAFETY: We cast a slice of `len * N` elements into
|
||||
// a slice of `len` many `N` elements chunks.
|
||||
unsafe {
|
||||
let array_slice: &mut [[T; N]] = from_raw_parts_mut(fst.as_mut_ptr().cast(), len);
|
||||
ArrayChunksMut { iter: array_slice.iter_mut(), rem: snd }
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end
|
||||
/// of the slice.
|
||||
///
|
||||
@ -5826,7 +5869,7 @@ fn may_have_side_effect() -> bool {
|
||||
/// time), starting at the beginning of the slice.
|
||||
///
|
||||
/// When the slice len is not evenly divided by the chunk size, the last
|
||||
/// up to `chunk_size-1` elements will be omitted but can be retrieved from
|
||||
/// up to `N-1` elements will be omitted but can be retrieved from
|
||||
/// the [`remainder`] function from the iterator.
|
||||
///
|
||||
/// This struct is created by the [`array_chunks`] method on [slices].
|
||||
@ -5843,7 +5886,7 @@ pub struct ArrayChunks<'a, T: 'a, const N: usize> {
|
||||
|
||||
impl<'a, T, const N: usize> ArrayChunks<'a, T, N> {
|
||||
/// 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`
|
||||
/// returned by the iterator. The returned slice has at most `N-1`
|
||||
/// elements.
|
||||
#[unstable(feature = "array_chunks", issue = "74985")]
|
||||
pub fn remainder(&self) -> &'a [T] {
|
||||
@ -5929,6 +5972,105 @@ fn may_have_side_effect() -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over a slice in (non-overlapping) mutable chunks (`N` elements
|
||||
/// at a time), starting at the beginning of the slice.
|
||||
///
|
||||
/// When the slice len is not evenly divided by the chunk size, the last
|
||||
/// up to `N-1` elements will be omitted but can be retrieved from
|
||||
/// the [`into_remainder`] function from the iterator.
|
||||
///
|
||||
/// This struct is created by the [`array_chunks_mut`] method on [slices].
|
||||
///
|
||||
/// [`array_chunks_mut`]: ../../std/primitive.slice.html#method.array_chunks_mut
|
||||
/// [`into_remainder`]: ../../std/slice/struct.ArrayChunksMut.html#method.into_remainder
|
||||
/// [slices]: ../../std/primitive.slice.html
|
||||
#[derive(Debug)]
|
||||
#[unstable(feature = "array_chunks", issue = "74985")]
|
||||
pub struct ArrayChunksMut<'a, T: 'a, const N: usize> {
|
||||
iter: IterMut<'a, [T; N]>,
|
||||
rem: &'a mut [T],
|
||||
}
|
||||
|
||||
impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> {
|
||||
/// Returns the remainder of the original slice that is not going to be
|
||||
/// returned by the iterator. The returned slice has at most `N-1`
|
||||
/// elements.
|
||||
#[unstable(feature = "array_chunks", issue = "74985")]
|
||||
pub fn into_remainder(self) -> &'a mut [T] {
|
||||
self.rem
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "array_chunks", issue = "74985")]
|
||||
impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> {
|
||||
type Item = &'a mut [T; N];
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a mut [T; N]> {
|
||||
self.iter.next()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn count(self) -> usize {
|
||||
self.iter.count()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
||||
self.iter.nth(n)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last(self) -> Option<Self::Item> {
|
||||
self.iter.last()
|
||||
}
|
||||
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T; N] {
|
||||
// SAFETY: The safety guarantees of `get_unchecked` are transferred to
|
||||
// the caller.
|
||||
unsafe { self.iter.get_unchecked(i) }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "array_chunks", issue = "74985")]
|
||||
impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunksMut<'a, T, N> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<&'a mut [T; N]> {
|
||||
self.iter.next_back()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
|
||||
self.iter.nth_back(n)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "array_chunks", issue = "74985")]
|
||||
impl<T, const N: usize> ExactSizeIterator for ArrayChunksMut<'_, T, N> {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.iter.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl<T, const N: usize> TrustedLen for ArrayChunksMut<'_, T, N> {}
|
||||
|
||||
#[unstable(feature = "array_chunks", issue = "74985")]
|
||||
impl<T, const N: usize> FusedIterator for ArrayChunksMut<'_, T, N> {}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "array_chunks", issue = "74985")]
|
||||
unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> {
|
||||
fn may_have_side_effect() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
|
||||
/// time), starting at the end of the slice.
|
||||
///
|
||||
|
@ -564,6 +564,99 @@ fn test_array_chunks_zip() {
|
||||
assert_eq!(res, vec![14, 22]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_chunks_mut_infer() {
|
||||
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
|
||||
for a in v.array_chunks_mut() {
|
||||
let sum = a.iter().sum::<i32>();
|
||||
*a = [sum; 3];
|
||||
}
|
||||
assert_eq!(v, &[3, 3, 3, 12, 12, 12, 6]);
|
||||
|
||||
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
|
||||
v2.array_chunks_mut().for_each(|[a, b]| core::mem::swap(a, b));
|
||||
assert_eq!(v2, &[1, 0, 3, 2, 5, 4, 6]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_chunks_mut_count() {
|
||||
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
|
||||
let c = v.array_chunks_mut::<3>();
|
||||
assert_eq!(c.count(), 2);
|
||||
|
||||
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
|
||||
let c2 = v2.array_chunks_mut::<2>();
|
||||
assert_eq!(c2.count(), 2);
|
||||
|
||||
let v3: &mut [i32] = &mut [];
|
||||
let c3 = v3.array_chunks_mut::<2>();
|
||||
assert_eq!(c3.count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_chunks_mut_nth() {
|
||||
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
|
||||
let mut c = v.array_chunks_mut::<2>();
|
||||
assert_eq!(c.nth(1).unwrap(), &[2, 3]);
|
||||
assert_eq!(c.next().unwrap(), &[4, 5]);
|
||||
|
||||
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
|
||||
let mut c2 = v2.array_chunks_mut::<3>();
|
||||
assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]);
|
||||
assert_eq!(c2.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_chunks_mut_nth_back() {
|
||||
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
|
||||
let mut c = v.array_chunks_mut::<2>();
|
||||
assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
|
||||
assert_eq!(c.next().unwrap(), &[0, 1]);
|
||||
assert_eq!(c.next(), None);
|
||||
|
||||
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
|
||||
let mut c2 = v2.array_chunks_mut::<3>();
|
||||
assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]);
|
||||
assert_eq!(c2.next(), None);
|
||||
assert_eq!(c2.next_back(), None);
|
||||
|
||||
let v3: &mut [i32] = &mut [0, 1, 2, 3, 4];
|
||||
let mut c3 = v3.array_chunks_mut::<10>();
|
||||
assert_eq!(c3.nth_back(0), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_chunks_mut_last() {
|
||||
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
|
||||
let c = v.array_chunks_mut::<2>();
|
||||
assert_eq!(c.last().unwrap(), &[4, 5]);
|
||||
|
||||
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
|
||||
let c2 = v2.array_chunks_mut::<2>();
|
||||
assert_eq!(c2.last().unwrap(), &[2, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_chunks_mut_remainder() {
|
||||
let v: &mut [i32] = &mut [0, 1, 2, 3, 4];
|
||||
let c = v.array_chunks_mut::<2>();
|
||||
assert_eq!(c.into_remainder(), &[4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_chunks_mut_zip() {
|
||||
let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
|
||||
let v2: &[i32] = &[6, 7, 8, 9, 10];
|
||||
|
||||
for (a, b) in v1.array_chunks_mut::<2>().zip(v2.array_chunks::<2>()) {
|
||||
let sum = b.iter().sum::<i32>();
|
||||
for v in a {
|
||||
*v += sum;
|
||||
}
|
||||
}
|
||||
assert_eq!(v1, [13, 14, 19, 20, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rchunks_count() {
|
||||
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
|
||||
|
Loading…
Reference in New Issue
Block a user