Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit d405347

Browse files
committed
adds slice::array_chunks
1 parent 870b7cb commit d405347

File tree

1 file changed

+180
-0
lines changed

1 file changed

+180
-0
lines changed

library/core/src/slice/mod.rs

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,41 @@ impl<T> [T] {
841841
ChunksExactMut { v: fst, rem: snd, chunk_size }
842842
}
843843

844+
/// Returns an iterator over `N` elements of the slice at a time, starting at the
845+
/// beginning of the slice.
846+
///
847+
/// The chunks are slices and do not overlap. If `N` does not divide the length of the
848+
/// slice, then the last up to `N-1` elements will be omitted and can be retrieved
849+
/// from the `remainder` function of the iterator.
850+
///
851+
/// # Panics
852+
///
853+
/// Panics if `N` is 0.
854+
///
855+
/// # Examples
856+
///
857+
/// ```
858+
/// #![feature(array_chunks)]
859+
/// let slice = ['l', 'o', 'r', 'e', 'm'];
860+
/// let mut iter = slice.array_chunks();
861+
/// assert_eq!(iter.next().unwrap(), &['l', 'o']);
862+
/// assert_eq!(iter.next().unwrap(), &['r', 'e']);
863+
/// assert!(iter.next().is_none());
864+
/// assert_eq!(iter.remainder(), &['m']);
865+
/// ```
866+
///
867+
/// [`chunks`]: #method.chunks
868+
/// [`rchunks_exact`]: #method.rchunks_exact
869+
#[unstable(feature = "array_chunks", issue = "none")]
870+
#[inline]
871+
pub fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N> {
872+
assert_ne!(N, 0);
873+
let rem = self.len() % N;
874+
let len = self.len() - rem;
875+
let (fst, snd) = self.split_at(len);
876+
ArrayChunks { v: fst, rem: snd }
877+
}
878+
844879
/// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end
845880
/// of the slice.
846881
///
@@ -5432,6 +5467,151 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> {
54325467
}
54335468
}
54345469

5470+
/// An iterator over a slice in (non-overlapping) chunks (`N` elements at a
5471+
/// time), starting at the beginning of the slice.
5472+
///
5473+
/// When the slice len is not evenly divided by the chunk size, the last
5474+
/// up to `chunk_size-1` elements will be omitted but can be retrieved from
5475+
/// the [`remainder`] function from the iterator.
5476+
///
5477+
/// This struct is created by the [`array_chunks`] method on [slices].
5478+
///
5479+
/// [`array_chunks`]: ../../std/primitive.slice.html#method.array_chunks
5480+
/// [`remainder`]: ../../std/slice/struct.ArrayChunks.html#method.remainder
5481+
/// [slices]: ../../std/primitive.slice.html
5482+
#[derive(Debug)]
5483+
#[unstable(feature = "array_chunks", issue = "none")]
5484+
pub struct ArrayChunks<'a, T: 'a, const N: usize> {
5485+
v: &'a [T],
5486+
rem: &'a [T],
5487+
}
5488+
5489+
impl<'a, T, const N: usize> ArrayChunks<'a, T, N> {
5490+
/// Returns the remainder of the original slice that is not going to be
5491+
/// returned by the iterator. The returned slice has at most `chunk_size-1`
5492+
/// elements.
5493+
#[unstable(feature = "array_chunks", issue = "none")]
5494+
pub fn remainder(&self) -> &'a [T] {
5495+
self.rem
5496+
}
5497+
}
5498+
5499+
// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
5500+
#[unstable(feature = "array_chunks", issue = "none")]
5501+
impl<T, const N: usize> Clone for ArrayChunks<'_, T, N> {
5502+
fn clone(&self) -> Self {
5503+
ArrayChunks { v: self.v, rem: self.rem }
5504+
}
5505+
}
5506+
5507+
#[unstable(feature = "array_chunks", issue = "none")]
5508+
impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> {
5509+
type Item = &'a [T; N];
5510+
5511+
#[inline]
5512+
fn next(&mut self) -> Option<&'a [T; N]> {
5513+
if self.v.len() < N {
5514+
None
5515+
} else {
5516+
let (fst, snd) = self.v.split_at(N);
5517+
self.v = snd;
5518+
// SAFETY: This is safe as fst is exactly N elements long.
5519+
let ptr = fst.as_ptr() as *const [T; N];
5520+
unsafe { Some(&*ptr) }
5521+
}
5522+
}
5523+
5524+
#[inline]
5525+
fn size_hint(&self) -> (usize, Option<usize>) {
5526+
let n = self.v.len() / N;
5527+
(n, Some(n))
5528+
}
5529+
5530+
#[inline]
5531+
fn count(self) -> usize {
5532+
self.len()
5533+
}
5534+
5535+
#[inline]
5536+
fn nth(&mut self, n: usize) -> Option<Self::Item> {
5537+
let (start, overflow) = n.overflowing_mul(N);
5538+
if start >= self.v.len() || overflow {
5539+
self.v = &[];
5540+
None
5541+
} else {
5542+
let (_, snd) = self.v.split_at(start);
5543+
self.v = snd;
5544+
self.next()
5545+
}
5546+
}
5547+
5548+
#[inline]
5549+
fn last(mut self) -> Option<Self::Item> {
5550+
self.next_back()
5551+
}
5552+
}
5553+
5554+
#[unstable(feature = "array_chunks", issue = "none")]
5555+
impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunks<'a, T, N> {
5556+
#[inline]
5557+
fn next_back(&mut self) -> Option<&'a [T; N]> {
5558+
if self.v.len() < N {
5559+
None
5560+
} else {
5561+
let (fst, snd) = self.v.split_at(self.v.len() - N);
5562+
self.v = fst;
5563+
// SAFETY: This is safe as snd is exactly N elements long.
5564+
let ptr = snd.as_ptr() as *const [T; N];
5565+
unsafe { Some(&*ptr) }
5566+
}
5567+
}
5568+
5569+
#[inline]
5570+
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
5571+
let len = self.len();
5572+
if n >= len {
5573+
self.v = &[];
5574+
None
5575+
} else {
5576+
let start = (len - 1 - n) * N;
5577+
let end = start + N;
5578+
let nth_back = &self.v[start..end];
5579+
self.v = &self.v[..start];
5580+
// SAFETY: This is safe as snd is exactly N elements long.
5581+
let ptr = nth_back.as_ptr() as *const [T; N];
5582+
unsafe { Some(&*ptr) }
5583+
}
5584+
}
5585+
}
5586+
5587+
#[unstable(feature = "array_chunks", issue = "none")]
5588+
impl<T, const N: usize> ExactSizeIterator for ArrayChunks<'_, T, N> {
5589+
fn is_empty(&self) -> bool {
5590+
self.v.is_empty()
5591+
}
5592+
}
5593+
5594+
#[unstable(feature = "trusted_len", issue = "37572")]
5595+
unsafe impl<T, const N: usize> TrustedLen for ArrayChunks<'_, T, N> {}
5596+
5597+
#[unstable(feature = "array_chunks", issue = "none")]
5598+
impl<T, const N: usize> FusedIterator for ArrayChunks<'_, T, N> {}
5599+
5600+
#[doc(hidden)]
5601+
#[unstable(feature = "array_chunks", issue = "none")]
5602+
unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> {
5603+
unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T; N] {
5604+
let start = i * N;
5605+
// SAFETY: This is safe as `i` must be less than `self.size_hint`.
5606+
let segment = unsafe { from_raw_parts(self.v.as_ptr().add(start), N) };
5607+
// SAFETY: This is safe as segment is exactly `N` elements long.
5608+
unsafe { &*(segment.as_ptr() as *const [T; N]) }
5609+
}
5610+
fn may_have_side_effect() -> bool {
5611+
false
5612+
}
5613+
}
5614+
54355615
/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
54365616
/// time), starting at the end of the slice.
54375617
///

0 commit comments

Comments
 (0)