about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBastian Kauschke <bastian_kauschke@hotmail.de>2020-05-18 20:40:37 +0200
committerBastian Kauschke <bastian_kauschke@hotmail.de>2020-07-30 10:50:34 +0200
commitd405347f095a20d832261bbf777c8214d7e61dc9 (patch)
treef2721cf70d1d0ffb0930316045e0b16c475a8cba
parent870b7cbb11d799bcabc6eb5a919a27821c981bc1 (diff)
downloadrust-d405347f095a20d832261bbf777c8214d7e61dc9.tar.gz
rust-d405347f095a20d832261bbf777c8214d7e61dc9.zip
adds `slice::array_chunks`
-rw-r--r--library/core/src/slice/mod.rs180
1 files changed, 180 insertions, 0 deletions
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 77fe379feee..a7d24492fac 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -841,6 +841,41 @@ impl<T> [T] {
         ChunksExactMut { v: fst, rem: snd, chunk_size }
     }
 
+    /// Returns an iterator over `N` elements of the slice at a time, starting at the
+    /// beginning of the slice.
+    ///
+    /// The chunks are slices and do not overlap. If `N` does not divide the length of the
+    /// slice, then the last up to `N-1` elements will be omitted and can be retrieved
+    /// from the `remainder` function of the iterator.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `N` is 0.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(array_chunks)]
+    /// let slice = ['l', 'o', 'r', 'e', 'm'];
+    /// let mut iter = slice.array_chunks();
+    /// assert_eq!(iter.next().unwrap(), &['l', 'o']);
+    /// assert_eq!(iter.next().unwrap(), &['r', 'e']);
+    /// assert!(iter.next().is_none());
+    /// assert_eq!(iter.remainder(), &['m']);
+    /// ```
+    ///
+    /// [`chunks`]: #method.chunks
+    /// [`rchunks_exact`]: #method.rchunks_exact
+    #[unstable(feature = "array_chunks", issue = "none")]
+    #[inline]
+    pub fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N> {
+        assert_ne!(N, 0);
+        let rem = self.len() % N;
+        let len = self.len() - rem;
+        let (fst, snd) = self.split_at(len);
+        ArrayChunks { v: fst, rem: snd }
+    }
+
     /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end
     /// of the slice.
     ///
@@ -5432,6 +5467,151 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> {
     }
 }
 
+/// An iterator over a slice in (non-overlapping) chunks (`N` elements at a
+/// time), starting at the beginning of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last
+/// up to `chunk_size-1` elements will be omitted but can be retrieved from
+/// the [`remainder`] function from the iterator.
+///
+/// This struct is created by the [`array_chunks`] method on [slices].
+///
+/// [`array_chunks`]: ../../std/primitive.slice.html#method.array_chunks
+/// [`remainder`]: ../../std/slice/struct.ArrayChunks.html#method.remainder
+/// [slices]: ../../std/primitive.slice.html
+#[derive(Debug)]
+#[unstable(feature = "array_chunks", issue = "none")]
+pub struct ArrayChunks<'a, T: 'a, const N: usize> {
+    v: &'a [T],
+    rem: &'a [T],
+}
+
+impl<'a, T, const N: usize> ArrayChunks<'a, T, N> {
+    /// Returns the remainder of the original slice that is not going to be
+    /// returned by the iterator. The returned slice has at most `chunk_size-1`
+    /// elements.
+    #[unstable(feature = "array_chunks", issue = "none")]
+    pub fn remainder(&self) -> &'a [T] {
+        self.rem
+    }
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[unstable(feature = "array_chunks", issue = "none")]
+impl<T, const N: usize> Clone for ArrayChunks<'_, T, N> {
+    fn clone(&self) -> Self {
+        ArrayChunks { v: self.v, rem: self.rem }
+    }
+}
+
+#[unstable(feature = "array_chunks", issue = "none")]
+impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> {
+    type Item = &'a [T; N];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a [T; N]> {
+        if self.v.len() < N {
+            None
+        } else {
+            let (fst, snd) = self.v.split_at(N);
+            self.v = snd;
+            // SAFETY: This is safe as fst is exactly N elements long.
+            let ptr = fst.as_ptr() as *const [T; N];
+            unsafe { Some(&*ptr) }
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let n = self.v.len() / N;
+        (n, Some(n))
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.len()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<Self::Item> {
+        let (start, overflow) = n.overflowing_mul(N);
+        if start >= self.v.len() || overflow {
+            self.v = &[];
+            None
+        } else {
+            let (_, snd) = self.v.split_at(start);
+            self.v = snd;
+            self.next()
+        }
+    }
+
+    #[inline]
+    fn last(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
+}
+
+#[unstable(feature = "array_chunks", issue = "none")]
+impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunks<'a, T, N> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a [T; N]> {
+        if self.v.len() < N {
+            None
+        } else {
+            let (fst, snd) = self.v.split_at(self.v.len() - N);
+            self.v = fst;
+            // SAFETY: This is safe as snd is exactly N elements long.
+            let ptr = snd.as_ptr() as *const [T; N];
+            unsafe { Some(&*ptr) }
+        }
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        let len = self.len();
+        if n >= len {
+            self.v = &[];
+            None
+        } else {
+            let start = (len - 1 - n) * N;
+            let end = start + N;
+            let nth_back = &self.v[start..end];
+            self.v = &self.v[..start];
+            // SAFETY: This is safe as snd is exactly N elements long.
+            let ptr = nth_back.as_ptr() as *const [T; N];
+            unsafe { Some(&*ptr) }
+        }
+    }
+}
+
+#[unstable(feature = "array_chunks", issue = "none")]
+impl<T, const N: usize> ExactSizeIterator for ArrayChunks<'_, T, N> {
+    fn is_empty(&self) -> bool {
+        self.v.is_empty()
+    }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T, const N: usize> TrustedLen for ArrayChunks<'_, T, N> {}
+
+#[unstable(feature = "array_chunks", issue = "none")]
+impl<T, const N: usize> FusedIterator for ArrayChunks<'_, T, N> {}
+
+#[doc(hidden)]
+#[unstable(feature = "array_chunks", issue = "none")]
+unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> {
+    unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T; N] {
+        let start = i * N;
+        // SAFETY: This is safe as `i` must be less than `self.size_hint`.
+        let segment = unsafe { from_raw_parts(self.v.as_ptr().add(start), N) };
+        // SAFETY: This is safe as segment is exactly `N` elements long.
+        unsafe { &*(segment.as_ptr() as *const [T; N]) }
+    }
+    fn may_have_side_effect() -> bool {
+        false
+    }
+}
+
 /// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
 /// time), starting at the end of the slice.
 ///