Skip to content

Commit 13e88d6

Browse files
authored
Rollup merge of #76635 - scottmcm:slice-as-chunks, r=LukasKalbertodt
Add [T]::as_chunks(_mut) Allows getting the slices directly, rather than just through an iterator as in `array_chunks(_mut)`. The constructors for those iterators are then written in terms of these methods, so the iterator constructors no longer have any `unsafe` of their own. Unstable, of course. #74985
2 parents fd54259 + 652f34d commit 13e88d6

File tree

2 files changed

+71
-15
lines changed

2 files changed

+71
-15
lines changed

library/core/src/slice/iter.rs

+4-15
Original file line numberDiff line numberDiff line change
@@ -2103,13 +2103,8 @@ pub struct ArrayChunks<'a, T: 'a, const N: usize> {
21032103
impl<'a, T, const N: usize> ArrayChunks<'a, T, N> {
21042104
#[inline]
21052105
pub(super) fn new(slice: &'a [T]) -> Self {
2106-
let len = slice.len() / N;
2107-
let (fst, snd) = slice.split_at(len * N);
2108-
// SAFETY: We cast a slice of `len * N` elements into
2109-
// a slice of `len` many `N` elements chunks.
2110-
let array_slice: &[[T; N]] = unsafe { from_raw_parts(fst.as_ptr().cast(), len) };
2111-
2112-
Self { iter: array_slice.iter(), rem: snd }
2106+
let (array_slice, rem) = slice.as_chunks();
2107+
Self { iter: array_slice.iter(), rem }
21132108
}
21142109

21152110
/// Returns the remainder of the original slice that is not going to be
@@ -2230,14 +2225,8 @@ pub struct ArrayChunksMut<'a, T: 'a, const N: usize> {
22302225
impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> {
22312226
#[inline]
22322227
pub(super) fn new(slice: &'a mut [T]) -> Self {
2233-
let len = slice.len() / N;
2234-
let (fst, snd) = slice.split_at_mut(len * N);
2235-
// SAFETY: We cast a slice of `len * N` elements into
2236-
// a slice of `len` many `N` elements chunks.
2237-
unsafe {
2238-
let array_slice: &mut [[T; N]] = from_raw_parts_mut(fst.as_mut_ptr().cast(), len);
2239-
Self { iter: array_slice.iter_mut(), rem: snd }
2240-
}
2228+
let (array_slice, rem) = slice.as_chunks_mut();
2229+
Self { iter: array_slice.iter_mut(), rem }
22412230
}
22422231

22432232
/// Returns the remainder of the original slice that is not going to be

library/core/src/slice/mod.rs

+67
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,36 @@ impl<T> [T] {
882882
ChunksExactMut::new(self, chunk_size)
883883
}
884884

885+
/// Splits the slice into a slice of `N`-element arrays,
886+
/// starting at the beginning of the slice,
887+
/// and a remainder slice with length strictly less than `N`.
888+
///
889+
/// # Panics
890+
///
891+
/// Panics if `N` is 0. This check will most probably get changed to a compile time
892+
/// error before this method gets stabilized.
893+
///
894+
/// # Examples
895+
///
896+
/// ```
897+
/// #![feature(slice_as_chunks)]
898+
/// let slice = ['l', 'o', 'r', 'e', 'm'];
899+
/// let (chunks, remainder) = slice.as_chunks();
900+
/// assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]);
901+
/// assert_eq!(remainder, &['m']);
902+
/// ```
903+
#[unstable(feature = "slice_as_chunks", issue = "74985")]
904+
#[inline]
905+
pub fn as_chunks<const N: usize>(&self) -> (&[[T; N]], &[T]) {
906+
assert_ne!(N, 0);
907+
let len = self.len() / N;
908+
let (multiple_of_n, remainder) = self.split_at(len * N);
909+
// SAFETY: We cast a slice of `len * N` elements into
910+
// a slice of `len` many `N` elements chunks.
911+
let array_slice: &[[T; N]] = unsafe { from_raw_parts(multiple_of_n.as_ptr().cast(), len) };
912+
(array_slice, remainder)
913+
}
914+
885915
/// Returns an iterator over `N` elements of the slice at a time, starting at the
886916
/// beginning of the slice.
887917
///
@@ -916,6 +946,43 @@ impl<T> [T] {
916946
ArrayChunks::new(self)
917947
}
918948

949+
/// Splits the slice into a slice of `N`-element arrays,
950+
/// starting at the beginning of the slice,
951+
/// and a remainder slice with length strictly less than `N`.
952+
///
953+
/// # Panics
954+
///
955+
/// Panics if `N` is 0. This check will most probably get changed to a compile time
956+
/// error before this method gets stabilized.
957+
///
958+
/// # Examples
959+
///
960+
/// ```
961+
/// #![feature(slice_as_chunks)]
962+
/// let v = &mut [0, 0, 0, 0, 0];
963+
/// let mut count = 1;
964+
///
965+
/// let (chunks, remainder) = v.as_chunks_mut();
966+
/// remainder[0] = 9;
967+
/// for chunk in chunks {
968+
/// *chunk = [count; 2];
969+
/// count += 1;
970+
/// }
971+
/// assert_eq!(v, &[1, 1, 2, 2, 9]);
972+
/// ```
973+
#[unstable(feature = "slice_as_chunks", issue = "74985")]
974+
#[inline]
975+
pub fn as_chunks_mut<const N: usize>(&mut self) -> (&mut [[T; N]], &mut [T]) {
976+
assert_ne!(N, 0);
977+
let len = self.len() / N;
978+
let (multiple_of_n, remainder) = self.split_at_mut(len * N);
979+
let array_slice: &mut [[T; N]] =
980+
// SAFETY: We cast a slice of `len * N` elements into
981+
// a slice of `len` many `N` elements chunks.
982+
unsafe { from_raw_parts_mut(multiple_of_n.as_mut_ptr().cast(), len) };
983+
(array_slice, remainder)
984+
}
985+
919986
/// Returns an iterator over `N` elements of the slice at a time, starting at the
920987
/// beginning of the slice.
921988
///

0 commit comments

Comments
 (0)