Skip to content

Commit f6a6d2f

Browse files
committed
Add slice::array_chunks_mut
1 parent 70c5f6e commit f6a6d2f

File tree

1 file changed

+146
-5
lines changed

1 file changed

+146
-5
lines changed

library/core/src/slice/mod.rs

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

1036+
/// Returns an iterator over `N` elements of the slice at a time, starting at the
1037+
/// beginning of the slice.
1038+
///
1039+
/// The chunks are mutable array references and do not overlap. If `N` does not divide
1040+
/// the length of the slice, then the last up to `N-1` elements will be omitted and
1041+
/// can be retrieved from the `into_remainder` function of the iterator.
1042+
///
1043+
/// This method is the const generic equivalent of [`chunks_exact_mut`].
1044+
///
1045+
/// # Panics
1046+
///
1047+
/// Panics if `N` is 0. This check will most probably get changed to a compile time
1048+
/// error before this method gets stabilized.
1049+
///
1050+
/// # Examples
1051+
///
1052+
/// ```
1053+
/// #![feature(array_chunks)]
1054+
/// let v = &mut [0, 0, 0, 0, 0];
1055+
/// let mut count = 1;
1056+
///
1057+
/// for chunk in v.array_chunks_mut() {
1058+
/// *chunk = [count; 2];
1059+
/// count += 1;
1060+
/// }
1061+
/// assert_eq!(v, &[1, 1, 2, 2, 0]);
1062+
/// ```
1063+
///
1064+
/// [`chunks_exact_mut`]: #method.chunks_exact_mut
1065+
#[unstable(feature = "array_chunks", issue = "74985")]
1066+
#[inline]
1067+
pub fn array_chunks_mut<const N: usize>(&mut self) -> ArrayChunksMut<'_, T, N> {
1068+
assert_ne!(N, 0);
1069+
let len = self.len() / N;
1070+
let (fst_ptr, snd) = {
1071+
// Scope the first slice into a pointer to avoid aliasing the new slice below.
1072+
let (fst, snd) = self.split_at_mut(len * N);
1073+
(fst.as_mut_ptr(), snd)
1074+
};
1075+
// SAFETY: We cast a slice of `len * N` elements into
1076+
// a slice of `len` many `N` elements chunks.
1077+
let array_slice: &mut [[T; N]] = unsafe { from_raw_parts_mut(fst_ptr.cast(), len) };
1078+
ArrayChunksMut { iter: array_slice.iter_mut(), rem: snd }
1079+
}
1080+
10361081
/// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end
10371082
/// of the slice.
10381083
///
@@ -5826,7 +5871,7 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> {
58265871
/// time), starting at the beginning of the slice.
58275872
///
58285873
/// 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
5874+
/// up to `N-1` elements will be omitted but can be retrieved from
58305875
/// the [`remainder`] function from the iterator.
58315876
///
58325877
/// This struct is created by the [`array_chunks`] method on [slices].
@@ -5843,7 +5888,7 @@ pub struct ArrayChunks<'a, T: 'a, const N: usize> {
58435888

58445889
impl<'a, T, const N: usize> ArrayChunks<'a, T, N> {
58455890
/// 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`
5891+
/// returned by the iterator. The returned slice has at most `N-1`
58475892
/// elements.
58485893
#[unstable(feature = "array_chunks", issue = "74985")]
58495894
pub fn remainder(&self) -> &'a [T] {
@@ -5929,6 +5974,102 @@ unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N>
59295974
}
59305975
}
59315976

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

0 commit comments

Comments
 (0)