Skip to content

Commit eb594a2

Browse files
committed
adds slice::array_chunks
1 parent 45209a9 commit eb594a2

File tree

1 file changed

+180
-0
lines changed

1 file changed

+180
-0
lines changed

src/libcore/slice/mod.rs

+180
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,41 @@ impl<T> [T] {
835835
ChunksExactMut { v: fst, rem: snd, chunk_size }
836836
}
837837

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

5190+
/// An iterator over a slice in (non-overlapping) chunks (`N` elements at a
5191+
/// time), starting at the beginning of the slice.
5192+
///
5193+
/// When the slice len is not evenly divided by the chunk size, the last
5194+
/// up to `chunk_size-1` elements will be omitted but can be retrieved from
5195+
/// the [`remainder`] function from the iterator.
5196+
///
5197+
/// This struct is created by the [`array_chunks`] method on [slices].
5198+
///
5199+
/// [`array_chunks`]: ../../std/primitive.slice.html#method.array_chunks
5200+
/// [`remainder`]: ../../std/slice/struct.ArrayChunks.html#method.remainder
5201+
/// [slices]: ../../std/primitive.slice.html
5202+
#[derive(Debug)]
5203+
#[unstable(feature = "array_chunks", issue = "none")]
5204+
pub struct ArrayChunks<'a, T: 'a, const N: usize> {
5205+
v: &'a [T],
5206+
rem: &'a [T],
5207+
}
5208+
5209+
impl<'a, T, const N: usize> ArrayChunks<'a, T, N> {
5210+
/// Returns the remainder of the original slice that is not going to be
5211+
/// returned by the iterator. The returned slice has at most `chunk_size-1`
5212+
/// elements.
5213+
#[unstable(feature = "array_chunks", issue = "none")]
5214+
pub fn remainder(&self) -> &'a [T] {
5215+
self.rem
5216+
}
5217+
}
5218+
5219+
// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
5220+
#[unstable(feature = "array_chunks", issue = "none")]
5221+
impl<T, const N: usize> Clone for ArrayChunks<'_, T, N> {
5222+
fn clone(&self) -> Self {
5223+
ArrayChunks { v: self.v, rem: self.rem }
5224+
}
5225+
}
5226+
5227+
#[unstable(feature = "array_chunks", issue = "none")]
5228+
impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> {
5229+
type Item = &'a [T; N];
5230+
5231+
#[inline]
5232+
fn next(&mut self) -> Option<&'a [T; N]> {
5233+
if self.v.len() < N {
5234+
None
5235+
} else {
5236+
let (fst, snd) = self.v.split_at(N);
5237+
self.v = snd;
5238+
// SAFETY: This is safe as fst is exactly N elements long.
5239+
let ptr = fst.as_ptr() as *const [T; N];
5240+
unsafe { Some(&*ptr) }
5241+
}
5242+
}
5243+
5244+
#[inline]
5245+
fn size_hint(&self) -> (usize, Option<usize>) {
5246+
let n = self.v.len() / N;
5247+
(n, Some(n))
5248+
}
5249+
5250+
#[inline]
5251+
fn count(self) -> usize {
5252+
self.len()
5253+
}
5254+
5255+
#[inline]
5256+
fn nth(&mut self, n: usize) -> Option<Self::Item> {
5257+
let (start, overflow) = n.overflowing_mul(N);
5258+
if start >= self.v.len() || overflow {
5259+
self.v = &[];
5260+
None
5261+
} else {
5262+
let (_, snd) = self.v.split_at(start);
5263+
self.v = snd;
5264+
self.next()
5265+
}
5266+
}
5267+
5268+
#[inline]
5269+
fn last(mut self) -> Option<Self::Item> {
5270+
self.next_back()
5271+
}
5272+
}
5273+
5274+
#[unstable(feature = "array_chunks", issue = "none")]
5275+
impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunks<'a, T, N> {
5276+
#[inline]
5277+
fn next_back(&mut self) -> Option<&'a [T; N]> {
5278+
if self.v.len() < N {
5279+
None
5280+
} else {
5281+
let (fst, snd) = self.v.split_at(self.v.len() - N);
5282+
self.v = fst;
5283+
// SAFETY: This is safe as snd is exactly N elements long.
5284+
let ptr = snd.as_ptr() as *const [T; N];
5285+
unsafe { Some(&*ptr) }
5286+
}
5287+
}
5288+
5289+
#[inline]
5290+
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
5291+
let len = self.len();
5292+
if n >= len {
5293+
self.v = &[];
5294+
None
5295+
} else {
5296+
let start = (len - 1 - n) * N;
5297+
let end = start + N;
5298+
let nth_back = &self.v[start..end];
5299+
self.v = &self.v[..start];
5300+
// SAFETY: This is safe as snd is exactly N elements long.
5301+
let ptr = nth_back.as_ptr() as *const [T; N];
5302+
unsafe { Some(&*ptr) }
5303+
}
5304+
}
5305+
}
5306+
5307+
#[unstable(feature = "array_chunks", issue = "none")]
5308+
impl<T, const N: usize> ExactSizeIterator for ArrayChunks<'_, T, N> {
5309+
fn is_empty(&self) -> bool {
5310+
self.v.is_empty()
5311+
}
5312+
}
5313+
5314+
#[unstable(feature = "trusted_len", issue = "37572")]
5315+
unsafe impl<T, const N: usize> TrustedLen for ArrayChunks<'_, T, N> {}
5316+
5317+
#[unstable(feature = "array_chunks", issue = "none")]
5318+
impl<T, const N: usize> FusedIterator for ArrayChunks<'_, T, N> {}
5319+
5320+
#[doc(hidden)]
5321+
#[unstable(feature = "array_chunks", issue = "none")]
5322+
unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> {
5323+
unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T; N] {
5324+
let start = i * N;
5325+
let segment = from_raw_parts(self.v.as_ptr().add(start), N);
5326+
// SAFETY: This is safe as segment is exactly N elements long.
5327+
let ptr = segment.as_ptr() as *const [T; N];
5328+
&*ptr
5329+
}
5330+
fn may_have_side_effect() -> bool {
5331+
false
5332+
}
5333+
}
5334+
51555335
/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
51565336
/// time), starting at the end of the slice.
51575337
///

0 commit comments

Comments
 (0)