Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 8b6838b

Browse files
committedSep 12, 2020
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`
2 parents 94a7ea2 + 86b9f71 commit 8b6838b

File tree

3 files changed

+242
-5
lines changed

3 files changed

+242
-5
lines changed
 

‎library/alloc/src/slice.rs

+2
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ use crate::vec::Vec;
9393

9494
#[unstable(feature = "array_chunks", issue = "74985")]
9595
pub use core::slice::ArrayChunks;
96+
#[unstable(feature = "array_chunks", issue = "74985")]
97+
pub use core::slice::ArrayChunksMut;
9698
#[stable(feature = "slice_get_slice", since = "1.28.0")]
9799
pub use core::slice::SliceIndex;
98100
#[stable(feature = "from_ref", since = "1.28.0")]

‎library/core/src/slice/mod.rs

+147-5
Original file line numberDiff line numberDiff line change
@@ -996,9 +996,9 @@ impl<T> [T] {
996996
/// Returns an iterator over `N` elements of the slice at a time, starting at the
997997
/// beginning of the slice.
998998
///
999-
/// The chunks are slices and do not overlap. If `N` does not divide the length of the
1000-
/// slice, then the last up to `N-1` elements will be omitted and can be retrieved
1001-
/// from the `remainder` function of the iterator.
999+
/// The chunks are array references and do not overlap. If `N` does not divide the
1000+
/// length of the slice, then the last up to `N-1` elements will be omitted and can be
1001+
/// retrieved from the `remainder` function of the iterator.
10021002
///
10031003
/// This method is the const generic equivalent of [`chunks_exact`].
10041004
///
@@ -1032,6 +1032,49 @@ impl<T> [T] {
10321032
ArrayChunks { iter: array_slice.iter(), rem: snd }
10331033
}
10341034

1035+
/// Returns an iterator over `N` elements of the slice at a time, starting at the
1036+
/// beginning of the slice.
1037+
///
1038+
/// The chunks are mutable array references and do not overlap. If `N` does not divide
1039+
/// the length of the slice, then the last up to `N-1` elements will be omitted and
1040+
/// can be retrieved from the `into_remainder` function of the iterator.
1041+
///
1042+
/// This method is the const generic equivalent of [`chunks_exact_mut`].
1043+
///
1044+
/// # Panics
1045+
///
1046+
/// Panics if `N` is 0. This check will most probably get changed to a compile time
1047+
/// error before this method gets stabilized.
1048+
///
1049+
/// # Examples
1050+
///
1051+
/// ```
1052+
/// #![feature(array_chunks)]
1053+
/// let v = &mut [0, 0, 0, 0, 0];
1054+
/// let mut count = 1;
1055+
///
1056+
/// for chunk in v.array_chunks_mut() {
1057+
/// *chunk = [count; 2];
1058+
/// count += 1;
1059+
/// }
1060+
/// assert_eq!(v, &[1, 1, 2, 2, 0]);
1061+
/// ```
1062+
///
1063+
/// [`chunks_exact_mut`]: #method.chunks_exact_mut
1064+
#[unstable(feature = "array_chunks", issue = "74985")]
1065+
#[inline]
1066+
pub fn array_chunks_mut<const N: usize>(&mut self) -> ArrayChunksMut<'_, T, N> {
1067+
assert_ne!(N, 0);
1068+
let len = self.len() / N;
1069+
let (fst, snd) = self.split_at_mut(len * N);
1070+
// SAFETY: We cast a slice of `len * N` elements into
1071+
// a slice of `len` many `N` elements chunks.
1072+
unsafe {
1073+
let array_slice: &mut [[T; N]] = from_raw_parts_mut(fst.as_mut_ptr().cast(), len);
1074+
ArrayChunksMut { iter: array_slice.iter_mut(), rem: snd }
1075+
}
1076+
}
1077+
10351078
/// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end
10361079
/// of the slice.
10371080
///
@@ -5826,7 +5869,7 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> {
58265869
/// time), starting at the beginning of the slice.
58275870
///
58285871
/// When the slice len is not evenly divided by the chunk size, the last
5829-
/// up to `chunk_size-1` elements will be omitted but can be retrieved from
5872+
/// up to `N-1` elements will be omitted but can be retrieved from
58305873
/// the [`remainder`] function from the iterator.
58315874
///
58325875
/// This struct is created by the [`array_chunks`] method on [slices].
@@ -5843,7 +5886,7 @@ pub struct ArrayChunks<'a, T: 'a, const N: usize> {
58435886

58445887
impl<'a, T, const N: usize> ArrayChunks<'a, T, N> {
58455888
/// Returns the remainder of the original slice that is not going to be
5846-
/// returned by the iterator. The returned slice has at most `chunk_size-1`
5889+
/// returned by the iterator. The returned slice has at most `N-1`
58475890
/// elements.
58485891
#[unstable(feature = "array_chunks", issue = "74985")]
58495892
pub fn remainder(&self) -> &'a [T] {
@@ -5929,6 +5972,105 @@ unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N>
59295972
}
59305973
}
59315974

5975+
/// An iterator over a slice in (non-overlapping) mutable chunks (`N` elements
5976+
/// at a time), starting at the beginning of the slice.
5977+
///
5978+
/// When the slice len is not evenly divided by the chunk size, the last
5979+
/// up to `N-1` elements will be omitted but can be retrieved from
5980+
/// the [`into_remainder`] function from the iterator.
5981+
///
5982+
/// This struct is created by the [`array_chunks_mut`] method on [slices].
5983+
///
5984+
/// [`array_chunks_mut`]: ../../std/primitive.slice.html#method.array_chunks_mut
5985+
/// [`into_remainder`]: ../../std/slice/struct.ArrayChunksMut.html#method.into_remainder
5986+
/// [slices]: ../../std/primitive.slice.html
5987+
#[derive(Debug)]
5988+
#[unstable(feature = "array_chunks", issue = "74985")]
5989+
pub struct ArrayChunksMut<'a, T: 'a, const N: usize> {
5990+
iter: IterMut<'a, [T; N]>,
5991+
rem: &'a mut [T],
5992+
}
5993+
5994+
impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> {
5995+
/// Returns the remainder of the original slice that is not going to be
5996+
/// returned by the iterator. The returned slice has at most `N-1`
5997+
/// elements.
5998+
#[unstable(feature = "array_chunks", issue = "74985")]
5999+
pub fn into_remainder(self) -> &'a mut [T] {
6000+
self.rem
6001+
}
6002+
}
6003+
6004+
#[unstable(feature = "array_chunks", issue = "74985")]
6005+
impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> {
6006+
type Item = &'a mut [T; N];
6007+
6008+
#[inline]
6009+
fn next(&mut self) -> Option<&'a mut [T; N]> {
6010+
self.iter.next()
6011+
}
6012+
6013+
#[inline]
6014+
fn size_hint(&self) -> (usize, Option<usize>) {
6015+
self.iter.size_hint()
6016+
}
6017+
6018+
#[inline]
6019+
fn count(self) -> usize {
6020+
self.iter.count()
6021+
}
6022+
6023+
#[inline]
6024+
fn nth(&mut self, n: usize) -> Option<Self::Item> {
6025+
self.iter.nth(n)
6026+
}
6027+
6028+
#[inline]
6029+
fn last(self) -> Option<Self::Item> {
6030+
self.iter.last()
6031+
}
6032+
6033+
unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T; N] {
6034+
// SAFETY: The safety guarantees of `get_unchecked` are transferred to
6035+
// the caller.
6036+
unsafe { self.iter.get_unchecked(i) }
6037+
}
6038+
}
6039+
6040+
#[unstable(feature = "array_chunks", issue = "74985")]
6041+
impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunksMut<'a, T, N> {
6042+
#[inline]
6043+
fn next_back(&mut self) -> Option<&'a mut [T; N]> {
6044+
self.iter.next_back()
6045+
}
6046+
6047+
#[inline]
6048+
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
6049+
self.iter.nth_back(n)
6050+
}
6051+
}
6052+
6053+
#[unstable(feature = "array_chunks", issue = "74985")]
6054+
impl<T, const N: usize> ExactSizeIterator for ArrayChunksMut<'_, T, N> {
6055+
fn is_empty(&self) -> bool {
6056+
self.iter.is_empty()
6057+
}
6058+
}
6059+
6060+
#[unstable(feature = "trusted_len", issue = "37572")]
6061+
unsafe impl<T, const N: usize> TrustedLen for ArrayChunksMut<'_, T, N> {}
6062+
6063+
#[unstable(feature = "array_chunks", issue = "74985")]
6064+
impl<T, const N: usize> FusedIterator for ArrayChunksMut<'_, T, N> {}
6065+
6066+
#[doc(hidden)]
6067+
#[unstable(feature = "array_chunks", issue = "74985")]
6068+
unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> {
6069+
fn may_have_side_effect() -> bool {
6070+
false
6071+
}
6072+
}
6073+
59326074
/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
59336075
/// time), starting at the end of the slice.
59346076
///

‎library/core/tests/slice.rs

+93
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,99 @@ fn test_array_chunks_zip() {
564564
assert_eq!(res, vec![14, 22]);
565565
}
566566

567+
#[test]
568+
fn test_array_chunks_mut_infer() {
569+
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
570+
for a in v.array_chunks_mut() {
571+
let sum = a.iter().sum::<i32>();
572+
*a = [sum; 3];
573+
}
574+
assert_eq!(v, &[3, 3, 3, 12, 12, 12, 6]);
575+
576+
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
577+
v2.array_chunks_mut().for_each(|[a, b]| core::mem::swap(a, b));
578+
assert_eq!(v2, &[1, 0, 3, 2, 5, 4, 6]);
579+
}
580+
581+
#[test]
582+
fn test_array_chunks_mut_count() {
583+
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
584+
let c = v.array_chunks_mut::<3>();
585+
assert_eq!(c.count(), 2);
586+
587+
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
588+
let c2 = v2.array_chunks_mut::<2>();
589+
assert_eq!(c2.count(), 2);
590+
591+
let v3: &mut [i32] = &mut [];
592+
let c3 = v3.array_chunks_mut::<2>();
593+
assert_eq!(c3.count(), 0);
594+
}
595+
596+
#[test]
597+
fn test_array_chunks_mut_nth() {
598+
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
599+
let mut c = v.array_chunks_mut::<2>();
600+
assert_eq!(c.nth(1).unwrap(), &[2, 3]);
601+
assert_eq!(c.next().unwrap(), &[4, 5]);
602+
603+
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
604+
let mut c2 = v2.array_chunks_mut::<3>();
605+
assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]);
606+
assert_eq!(c2.next(), None);
607+
}
608+
609+
#[test]
610+
fn test_array_chunks_mut_nth_back() {
611+
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
612+
let mut c = v.array_chunks_mut::<2>();
613+
assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
614+
assert_eq!(c.next().unwrap(), &[0, 1]);
615+
assert_eq!(c.next(), None);
616+
617+
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
618+
let mut c2 = v2.array_chunks_mut::<3>();
619+
assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]);
620+
assert_eq!(c2.next(), None);
621+
assert_eq!(c2.next_back(), None);
622+
623+
let v3: &mut [i32] = &mut [0, 1, 2, 3, 4];
624+
let mut c3 = v3.array_chunks_mut::<10>();
625+
assert_eq!(c3.nth_back(0), None);
626+
}
627+
628+
#[test]
629+
fn test_array_chunks_mut_last() {
630+
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
631+
let c = v.array_chunks_mut::<2>();
632+
assert_eq!(c.last().unwrap(), &[4, 5]);
633+
634+
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
635+
let c2 = v2.array_chunks_mut::<2>();
636+
assert_eq!(c2.last().unwrap(), &[2, 3]);
637+
}
638+
639+
#[test]
640+
fn test_array_chunks_mut_remainder() {
641+
let v: &mut [i32] = &mut [0, 1, 2, 3, 4];
642+
let c = v.array_chunks_mut::<2>();
643+
assert_eq!(c.into_remainder(), &[4]);
644+
}
645+
646+
#[test]
647+
fn test_array_chunks_mut_zip() {
648+
let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
649+
let v2: &[i32] = &[6, 7, 8, 9, 10];
650+
651+
for (a, b) in v1.array_chunks_mut::<2>().zip(v2.array_chunks::<2>()) {
652+
let sum = b.iter().sum::<i32>();
653+
for v in a {
654+
*v += sum;
655+
}
656+
}
657+
assert_eq!(v1, [13, 14, 19, 20, 4]);
658+
}
659+
567660
#[test]
568661
fn test_rchunks_count() {
569662
let v: &[i32] = &[0, 1, 2, 3, 4, 5];

0 commit comments

Comments
 (0)
Failed to load comments.