From 80a8e5c1f767384d0736807f33f5e435a748cf4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 26 Sep 2018 01:35:54 +0300 Subject: [PATCH] Add slice::rchunks(), rchunks_mut(), rchunks_exact() and rchunks_exact_mut() These work exactly like the normal chunks iterators but start creating chunks from the end of the slice. See #55177 for the tracking issue --- src/liballoc/lib.rs | 1 + src/liballoc/slice.rs | 2 + src/liballoc/tests/lib.rs | 1 + src/liballoc/tests/slice.rs | 116 +++++- src/libcore/slice/mod.rs | 750 ++++++++++++++++++++++++++++++++++-- src/libcore/tests/lib.rs | 1 + src/libcore/tests/slice.rs | 222 +++++++++++ 7 files changed, 1058 insertions(+), 35 deletions(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 987572e6b74a9..0cad471d9a1d5 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -120,6 +120,7 @@ #![feature(const_vec_new)] #![feature(slice_partition_dedup)] #![feature(maybe_uninit)] +#![feature(rchunks)] // Allow testing this library diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 33d28bef2d707..2628757b503c1 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -125,6 +125,8 @@ pub use core::slice::{from_ref, from_mut}; pub use core::slice::SliceIndex; #[unstable(feature = "chunks_exact", issue = "47115")] pub use core::slice::{ChunksExact, ChunksExactMut}; +#[unstable(feature = "rchunks", issue = "55177")] +pub use core::slice::{RChunks, RChunksMut, RChunksExact, RChunksExactMut}; //////////////////////////////////////////////////////////////////////////////// // Basic slice extension methods diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index c771c41dc3ed3..62c84c9e0864e 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(chunks_exact)] +#![feature(rchunks)] #![feature(repeat_generic_slice)] extern crate alloc_system; diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs index c214c59618d3e..a50f99b00220a 100644 --- a/src/liballoc/tests/slice.rs +++ b/src/liballoc/tests/slice.rs @@ -998,6 +998,54 @@ fn test_chunks_exactator_0() { let _it = v.chunks_exact(0); } +#[test] +fn test_rchunksator() { + let v = &[1, 2, 3, 4, 5]; + + assert_eq!(v.rchunks(2).len(), 3); + + let chunks: &[&[_]] = &[&[4, 5], &[2, 3], &[1]]; + assert_eq!(v.rchunks(2).collect::>(), chunks); + let chunks: &[&[_]] = &[&[3, 4, 5], &[1, 2]]; + assert_eq!(v.rchunks(3).collect::>(), chunks); + let chunks: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(v.rchunks(6).collect::>(), chunks); + + let chunks: &[&[_]] = &[&[1], &[2, 3], &[4, 5]]; + assert_eq!(v.rchunks(2).rev().collect::>(), chunks); +} + +#[test] +#[should_panic] +fn test_rchunksator_0() { + let v = &[1, 2, 3, 4]; + let _it = v.rchunks(0); +} + +#[test] +fn test_rchunks_exactator() { + let v = &[1, 2, 3, 4, 5]; + + assert_eq!(v.rchunks_exact(2).len(), 2); + + let chunks: &[&[_]] = &[&[4, 5], &[2, 3]]; + assert_eq!(v.rchunks_exact(2).collect::>(), chunks); + let chunks: &[&[_]] = &[&[3, 4, 5]]; + assert_eq!(v.rchunks_exact(3).collect::>(), chunks); + let chunks: &[&[_]] = &[]; + assert_eq!(v.rchunks_exact(6).collect::>(), chunks); + + let chunks: &[&[_]] = &[&[2, 3], &[4, 5]]; + assert_eq!(v.rchunks_exact(2).rev().collect::>(), chunks); +} + +#[test] +#[should_panic] +fn test_rchunks_exactator_0() { + let v = &[1, 2, 3, 4]; + let _it = v.rchunks_exact(0); +} + #[test] fn test_reverse_part() { let mut values = [1, 2, 3, 4, 5]; @@ -1205,7 +1253,7 @@ fn test_get_mut() { #[test] fn test_mut_chunks() { let mut v = [0, 1, 2, 3, 4, 5, 6]; - assert_eq!(v.chunks_mut(2).len(), 4); + assert_eq!(v.chunks_mut(3).len(), 3); for (i, chunk) in v.chunks_mut(3).enumerate() { for x in chunk { *x = i as u8; @@ -1237,7 +1285,7 @@ fn test_mut_chunks_0() { #[test] fn test_mut_chunks_exact() { let mut v = [0, 1, 2, 3, 4, 5, 6]; - assert_eq!(v.chunks_exact_mut(2).len(), 3); + assert_eq!(v.chunks_exact_mut(3).len(), 2); for (i, chunk) in v.chunks_exact_mut(3).enumerate() { for x in chunk { *x = i as u8; @@ -1266,6 +1314,70 @@ fn test_mut_chunks_exact_0() { let _it = v.chunks_exact_mut(0); } +#[test] +fn test_mut_rchunks() { + let mut v = [0, 1, 2, 3, 4, 5, 6]; + assert_eq!(v.rchunks_mut(3).len(), 3); + for (i, chunk) in v.rchunks_mut(3).enumerate() { + for x in chunk { + *x = i as u8; + } + } + let result = [2, 1, 1, 1, 0, 0, 0]; + assert_eq!(v, result); +} + +#[test] +fn test_mut_rchunks_rev() { + let mut v = [0, 1, 2, 3, 4, 5, 6]; + for (i, chunk) in v.rchunks_mut(3).rev().enumerate() { + for x in chunk { + *x = i as u8; + } + } + let result = [0, 1, 1, 1, 2, 2, 2]; + assert_eq!(v, result); +} + +#[test] +#[should_panic] +fn test_mut_rchunks_0() { + let mut v = [1, 2, 3, 4]; + let _it = v.rchunks_mut(0); +} + +#[test] +fn test_mut_rchunks_exact() { + let mut v = [0, 1, 2, 3, 4, 5, 6]; + assert_eq!(v.rchunks_exact_mut(3).len(), 2); + for (i, chunk) in v.rchunks_exact_mut(3).enumerate() { + for x in chunk { + *x = i as u8; + } + } + let result = [0, 1, 1, 1, 0, 0, 0]; + assert_eq!(v, result); +} + +#[test] +fn test_mut_rchunks_exact_rev() { + let mut v = [0, 1, 2, 3, 4, 5, 6]; + for (i, chunk) in v.rchunks_exact_mut(3).rev().enumerate() { + for x in chunk { + *x = i as u8; + } + } + let result = [0, 0, 0, 0, 1, 1, 1]; + assert_eq!(v, result); +} + +#[test] +#[should_panic] +fn test_mut_rchunks_exact_0() { + let mut v = [1, 2, 3, 4]; + let _it = v.rchunks_exact_mut(0); +} + #[test] fn test_mut_last() { let mut x = [1, 2, 3, 4, 5]; diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 76dcca0257817..6801eb9ea09d5 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -620,13 +620,15 @@ impl [T] { Windows { v: self, size } } - /// Returns an iterator over `chunk_size` elements of the slice at a - /// time. The chunks are slices and do not overlap. If `chunk_size` does - /// not divide the length of the slice, then the last chunk will - /// not have length `chunk_size`. + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. /// - /// See [`chunks_exact`] for a variant of this iterator that returns chunks - /// of always exactly `chunk_size` elements. + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`chunks_exact`] for a variant of this iterator that returns chunks of always exactly + /// `chunk_size` elements, and [`rchunks`] for the same iterator but starting at the end of the + /// slice of the slice. /// /// # Panics /// @@ -644,6 +646,7 @@ impl [T] { /// ``` /// /// [`chunks_exact`]: #method.chunks_exact + /// [`rchunks`]: #method.rchunks #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn chunks(&self, chunk_size: usize) -> Chunks { @@ -651,13 +654,15 @@ impl [T] { Chunks { v: self, chunk_size } } - /// Returns an iterator over `chunk_size` elements of the slice at a time. - /// The chunks are mutable slices, and do not overlap. If `chunk_size` does - /// not divide the length of the slice, then the last chunk will not - /// have length `chunk_size`. + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last chunk will not have length `chunk_size`. /// - /// See [`chunks_exact_mut`] for a variant of this iterator that returns chunks - /// of always exactly `chunk_size` elements. + /// See [`chunks_exact_mut`] for a variant of this iterator that returns chunks of always + /// exactly `chunk_size` elements, and [`rchunks_mut`] for the same iterator but starting at + /// the end of the slice of the slice. /// /// # Panics /// @@ -679,6 +684,7 @@ impl [T] { /// ``` /// /// [`chunks_exact_mut`]: #method.chunks_exact_mut + /// [`rchunks_mut`]: #method.rchunks_mut #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut { @@ -686,15 +692,19 @@ impl [T] { ChunksMut { v: self, chunk_size } } - /// Returns an iterator over `chunk_size` elements of the slice at a - /// time. The chunks are slices and do not overlap. If `chunk_size` does - /// not divide the length of the slice, then the last up to `chunk_size-1` - /// elements will be omitted and can be retrieved from the `remainder` - /// function of the iterator. + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved + /// from the `remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`chunks`]. /// - /// Due to each chunk having exactly `chunk_size` elements, the compiler - /// can often optimize the resulting code better than in the case of - /// [`chunks`]. + /// See [`chunks`] for a variant of this iterator that also returns the remainder as a smaller + /// chunk, and [`rchunks_exact`] for the same iterator but starting at the end of the slice of + /// the slice. /// /// # Panics /// @@ -710,9 +720,11 @@ impl [T] { /// 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 = "chunks_exact", issue = "47115")] #[inline] pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact { @@ -723,15 +735,19 @@ impl [T] { ChunksExact { v: fst, rem: snd, chunk_size } } - /// Returns an iterator over `chunk_size` elements of the slice at a time. - /// The chunks are mutable slices, and do not overlap. If `chunk_size` does - /// not divide the length of the slice, then the last up to `chunk_size-1` - /// elements will be omitted and can be retrieved from the `into_remainder` - /// function of the iterator. + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. /// - /// Due to each chunk having exactly `chunk_size` elements, the compiler - /// can often optimize the resulting code better than in the case of - /// [`chunks_mut`]. + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last up to `chunk_size-1` elements will be omitted and can be + /// retrieved from the `into_remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`chunks_mut`]. + /// + /// See [`chunks_mut`] for a variant of this iterator that also returns the remainder as a + /// smaller chunk, and [`rchunks_exact_mut`] for the same iterator but starting at the end of + /// the slice of the slice. /// /// # Panics /// @@ -755,6 +771,7 @@ impl [T] { /// ``` /// /// [`chunks_mut`]: #method.chunks_mut + /// [`rchunks_exact_mut`]: #method.rchunks_exact_mut #[unstable(feature = "chunks_exact", issue = "47115")] #[inline] pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut { @@ -765,6 +782,170 @@ impl [T] { ChunksExactMut { v: fst, rem: snd, chunk_size } } + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end + /// of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`rchunks_exact`] for a variant of this iterator that returns chunks of always exactly + /// `chunk_size` elements, and [`chunks`] for the same iterator but starting at the beginning + /// of the slice. + /// + /// # Panics + /// + /// Panics if `chunk_size` is 0. + /// + /// # Examples + /// + /// ``` + /// #![feature(rchunks)] + /// + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.rchunks(2); + /// assert_eq!(iter.next().unwrap(), &['e', 'm']); + /// assert_eq!(iter.next().unwrap(), &['o', 'r']); + /// assert_eq!(iter.next().unwrap(), &['l']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`rchunks_exact`]: #method.rchunks_exact + /// [`chunks`]: #method.chunks + #[unstable(feature = "rchunks", issue = "55177")] + #[inline] + pub fn rchunks(&self, chunk_size: usize) -> RChunks { + assert!(chunk_size != 0); + RChunks { v: self, chunk_size } + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end + /// of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last chunk will not have length `chunk_size`. + /// + /// See [`rchunks_exact_mut`] for a variant of this iterator that returns chunks of always + /// exactly `chunk_size` elements, and [`chunks_mut`] for the same iterator but starting at the + /// beginning of the slice. + /// + /// # Panics + /// + /// Panics if `chunk_size` is 0. + /// + /// # Examples + /// + /// ``` + /// #![feature(rchunks)] + /// + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.rchunks_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[3, 2, 2, 1, 1]); + /// ``` + /// + /// [`rchunks_exact_mut`]: #method.rchunks_exact_mut + /// [`chunks_mut`]: #method.chunks_mut + #[unstable(feature = "rchunks", issue = "55177")] + #[inline] + pub fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut { + assert!(chunk_size != 0); + RChunksMut { v: self, chunk_size } + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are slices and do not overlap. If `chunk_size` does not divide the length of the + /// slice, then the last up to `chunk_size-1` elements will be omitted and can be retrieved + /// from the `remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`chunks`]. + /// + /// See [`rchunks`] for a variant of this iterator that also returns the remainder as a smaller + /// chunk, and [`chunks_exact`] for the same iterator but starting at the beginning of the + /// slice of the slice. + /// + /// # Panics + /// + /// Panics if `chunk_size` is 0. + /// + /// # Examples + /// + /// ``` + /// #![feature(rchunks)] + /// + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.rchunks_exact(2); + /// assert_eq!(iter.next().unwrap(), &['e', 'm']); + /// assert_eq!(iter.next().unwrap(), &['o', 'r']); + /// assert!(iter.next().is_none()); + /// assert_eq!(iter.remainder(), &['l']); + /// ``` + /// + /// [`rchunks`]: #method.rchunks + /// [`chunks_exact`]: #method.chunks_exact + #[unstable(feature = "rchunks", issue = "55177")] + #[inline] + pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact { + assert!(chunk_size != 0); + let rem = self.len() % chunk_size; + let (fst, snd) = self.split_at(rem); + RChunksExact { v: snd, rem: fst, chunk_size } + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end + /// of the slice. + /// + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does not divide the + /// length of the slice, then the last up to `chunk_size-1` elements will be omitted and can be + /// retrieved from the `into_remainder` function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler can often optimize the + /// resulting code better than in the case of [`chunks_mut`]. + /// + /// See [`rchunks_mut`] for a variant of this iterator that also returns the remainder as a + /// smaller chunk, and [`chunks_exact_mut`] for the same iterator but starting at the beginning + /// of the slice of the slice. + /// + /// # Panics + /// + /// Panics if `chunk_size` is 0. + /// + /// # Examples + /// + /// ``` + /// #![feature(rchunks)] + /// + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.rchunks_exact_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[0, 2, 2, 1, 1]); + /// ``` + /// + /// [`rchunks_mut`]: #method.rchunks_mut + /// [`chunks_exact_mut`]: #method.chunks_exact_mut + #[unstable(feature = "rchunks", issue = "55177")] + #[inline] + pub fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut { + assert!(chunk_size != 0); + let rem = self.len() % chunk_size; + let (fst, snd) = self.split_at_mut(rem); + RChunksExactMut { v: snd, rem: fst, chunk_size } + } + /// Divides one slice into two at an index. /// /// The first will contain all indices from `[0, mid)` (excluding @@ -3581,7 +3762,7 @@ unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> { } /// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a -/// time). +/// time), starting at the beginning of the slice. /// /// When the slice len is not evenly divided by the chunk size, the last slice /// of the iteration will be the remainder. @@ -3708,8 +3889,10 @@ unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> { } /// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` -/// elements at a time). When the slice len is not evenly divided by the chunk -/// size, the last slice of the iteration will be the remainder. +/// 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 slice +/// of the iteration will be the remainder. /// /// This struct is created by the [`chunks_mut`] method on [slices]. /// @@ -3827,7 +4010,7 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { } /// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a -/// time). +/// 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 @@ -3941,6 +4124,7 @@ unsafe impl TrustedLen for ChunksExact<'_, T> {} impl FusedIterator for ChunksExact<'_, T> {} #[doc(hidden)] +#[unstable(feature = "chunks_exact", issue = "47115")] unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] { let start = i * self.chunk_size; @@ -3950,7 +4134,7 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { } /// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` -/// elements at a time). +/// 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 @@ -4056,6 +4240,7 @@ unsafe impl TrustedLen for ChunksExactMut<'_, T> {} impl FusedIterator for ChunksExactMut<'_, T> {} #[doc(hidden)] +#[unstable(feature = "chunks_exact", issue = "47115")] unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] { let start = i * self.chunk_size; @@ -4064,6 +4249,505 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { 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. +/// +/// When the slice len is not evenly divided by the chunk size, the last slice +/// of the iteration will be the remainder. +/// +/// This struct is created by the [`rchunks`] method on [slices]. +/// +/// [`rchunks`]: ../../std/primitive.slice.html#method.rchunks +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[unstable(feature = "rchunks", issue = "55177")] +pub struct RChunks<'a, T:'a> { + v: &'a [T], + chunk_size: usize +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> Clone for RChunks<'a, T> { + fn clone(&self) -> RChunks<'a, T> { + RChunks { + v: self.v, + chunk_size: self.chunk_size, + } + } +} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> Iterator for RChunks<'a, T> { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.v.is_empty() { + None + } else { + let chunksz = cmp::min(self.v.len(), self.chunk_size); + let (fst, snd) = self.v.split_at(self.v.len() - chunksz); + self.v = fst; + Some(snd) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.v.is_empty() { + (0, Some(0)) + } else { + let n = self.v.len() / self.chunk_size; + let rem = self.v.len() % self.chunk_size; + let n = if rem > 0 { n+1 } else { n }; + (n, Some(n)) + } + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let (end, overflow) = n.overflowing_mul(self.chunk_size); + if end >= self.v.len() || overflow { + self.v = &[]; + None + } else { + // Can't underflow because of the check above + let end = self.v.len() - end; + let start = match end.checked_sub(self.chunk_size) { + Some(sum) => sum, + None => 0, + }; + let nth = &self.v[start..end]; + self.v = &self.v[0..start]; + Some(nth) + } + } + + #[inline] + fn last(self) -> Option { + if self.v.is_empty() { + None + } else { + let rem = self.v.len() % self.chunk_size; + let end = if rem == 0 { self.chunk_size } else { rem }; + Some(&self.v[0..end]) + } + } +} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> DoubleEndedIterator for RChunks<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.v.is_empty() { + None + } else { + let remainder = self.v.len() % self.chunk_size; + let chunksz = if remainder != 0 { remainder } else { self.chunk_size }; + let (fst, snd) = self.v.split_at(chunksz); + self.v = snd; + Some(fst) + } + } +} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> ExactSizeIterator for RChunks<'a, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for RChunks<'a, T> {} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> FusedIterator for RChunks<'a, T> {} + +#[doc(hidden)] +#[unstable(feature = "rchunks", issue = "55177")] +unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { + unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] { + let end = self.v.len() - i * self.chunk_size; + let start = match end.checked_sub(self.chunk_size) { + None => 0, + Some(start) => start, + }; + from_raw_parts(self.v.as_ptr().add(start), end - start) + } + fn may_have_side_effect() -> bool { false } +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` +/// elements at a time), starting at the end of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last slice +/// of the iteration will be the remainder. +/// +/// This struct is created by the [`rchunks_mut`] method on [slices]. +/// +/// [`rchunks_mut`]: ../../std/primitive.slice.html#method.rchunks_mut +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[unstable(feature = "rchunks", issue = "55177")] +pub struct RChunksMut<'a, T:'a> { + v: &'a mut [T], + chunk_size: usize +} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> Iterator for RChunksMut<'a, T> { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.v.is_empty() { + None + } else { + let sz = cmp::min(self.v.len(), self.chunk_size); + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (head, tail) = tmp.split_at_mut(tmp_len - sz); + self.v = head; + Some(tail) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.v.is_empty() { + (0, Some(0)) + } else { + let n = self.v.len() / self.chunk_size; + let rem = self.v.len() % self.chunk_size; + let n = if rem > 0 { n + 1 } else { n }; + (n, Some(n)) + } + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { + let (end, overflow) = n.overflowing_mul(self.chunk_size); + if end >= self.v.len() || overflow { + self.v = &mut []; + None + } else { + // Can't underflow because of the check above + let end = self.v.len() - end; + let start = match end.checked_sub(self.chunk_size) { + Some(sum) => sum, + None => 0, + }; + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(start); + let (nth, _) = tail.split_at_mut(end - start); + self.v = head; + Some(nth) + } + } + + #[inline] + fn last(self) -> Option { + if self.v.is_empty() { + None + } else { + let rem = self.v.len() % self.chunk_size; + let end = if rem == 0 { self.chunk_size } else { rem }; + Some(&mut self.v[0..end]) + } + } +} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.v.is_empty() { + None + } else { + let remainder = self.v.len() % self.chunk_size; + let sz = if remainder != 0 { remainder } else { self.chunk_size }; + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(sz); + self.v = tail; + Some(head) + } + } +} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> ExactSizeIterator for RChunksMut<'a, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for RChunksMut<'a, T> {} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> FusedIterator for RChunksMut<'a, T> {} + +#[doc(hidden)] +#[unstable(feature = "rchunks", issue = "55177")] +unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { + unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] { + let end = self.v.len() - i * self.chunk_size; + let start = match end.checked_sub(self.chunk_size) { + None => 0, + Some(start) => start, + }; + from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) + } + 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. +/// +/// 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 [`rchunks_exact`] method on [slices]. +/// +/// [`rchunks_exact`]: ../../std/primitive.slice.html#method.rchunks_exact +/// [`remainder`]: ../../std/slice/struct.ChunksExact.html#method.remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[unstable(feature = "rchunks", issue = "55177")] +pub struct RChunksExact<'a, T:'a> { + v: &'a [T], + rem: &'a [T], + chunk_size: usize +} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> RChunksExact<'a, T> { + /// Return 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. + pub fn remainder(&self) -> &'a [T] { + self.rem + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> Clone for RChunksExact<'a, T> { + fn clone(&self) -> RChunksExact<'a, T> { + RChunksExact { + v: self.v, + rem: self.rem, + chunk_size: self.chunk_size, + } + } +} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> Iterator for RChunksExact<'a, T> { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size); + self.v = fst; + Some(snd) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.v.len() / self.chunk_size; + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let (end, overflow) = n.overflowing_mul(self.chunk_size); + if end >= self.v.len() || overflow { + self.v = &[]; + None + } else { + let (fst, _) = self.v.split_at(self.v.len() - end); + self.v = fst; + self.next() + } + } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } +} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let (fst, snd) = self.v.split_at(self.chunk_size); + self.v = snd; + Some(fst) + } + } +} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> ExactSizeIterator for RChunksExact<'a, T> { + fn is_empty(&self) -> bool { + self.v.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for RChunksExact<'a, T> {} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> FusedIterator for RChunksExact<'a, T> {} + +#[doc(hidden)] +#[unstable(feature = "rchunks", issue = "55177")] +unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { + unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] { + let end = self.v.len() - i * self.chunk_size; + let start = end - self.chunk_size; + from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) + } + fn may_have_side_effect() -> bool { false } +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` +/// elements at a time), starting at the end 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 +/// [`into_remainder`] function from the iterator. +/// +/// This struct is created by the [`rchunks_exact_mut`] method on [slices]. +/// +/// [`rchunks_exact_mut`]: ../../std/primitive.slice.html#method.rchunks_exact_mut +/// [`into_remainder`]: ../../std/slice/struct.ChunksExactMut.html#method.into_remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[unstable(feature = "rchunks", issue = "55177")] +pub struct RChunksExactMut<'a, T:'a> { + v: &'a mut [T], + rem: &'a mut [T], + chunk_size: usize +} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> RChunksExactMut<'a, T> { + /// Return 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. + pub fn into_remainder(self) -> &'a mut [T] { + self.rem + } +} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> Iterator for RChunksExactMut<'a, T> { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size); + self.v = head; + Some(tail) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.v.len() / self.chunk_size; + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { + let (end, overflow) = n.overflowing_mul(self.chunk_size); + if end >= self.v.len() || overflow { + self.v = &mut []; + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (fst, _) = tmp.split_at_mut(tmp_len - end); + self.v = fst; + self.next() + } + } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } +} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(self.chunk_size); + self.v = tail; + Some(head) + } + } +} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> ExactSizeIterator for RChunksExactMut<'a, T> { + fn is_empty(&self) -> bool { + self.v.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for RChunksExactMut<'a, T> {} + +#[unstable(feature = "rchunks", issue = "55177")] +impl<'a, T> FusedIterator for RChunksExactMut<'a, T> {} + +#[doc(hidden)] +#[unstable(feature = "rchunks", issue = "55177")] +unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { + unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] { + let end = self.v.len() - i * self.chunk_size; + let start = end - self.chunk_size; + from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) + } + fn may_have_side_effect() -> bool { false } +} + // // Free functions // diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 0beb60a127097..e889d484353a5 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -35,6 +35,7 @@ #![feature(try_from)] #![feature(try_trait)] #![feature(chunks_exact)] +#![feature(rchunks)] #![feature(align_offset)] #![feature(reverse_bits)] #![feature(inner_deref)] diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index de49a7bed395c..dba5a43eb21da 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -338,6 +338,228 @@ fn test_chunks_exact_mut_zip() { assert_eq!(v1, [13, 14, 19, 20, 4]); } +#[test] +fn test_rchunks_count() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.rchunks(3); + assert_eq!(c.count(), 2); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.rchunks(2); + assert_eq!(c2.count(), 3); + + let v3: &[i32] = &[]; + let c3 = v3.rchunks(2); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_rchunks_nth() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks(2); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let mut c2 = v2.rchunks(3); + assert_eq!(c2.nth(1).unwrap(), &[0, 1]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_rchunks_last() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.rchunks(2); + assert_eq!(c.last().unwrap()[1], 1); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.rchunks(2); + assert_eq!(c2.last().unwrap()[0], 0); +} + +#[test] +fn test_rchunks_zip() { + let v1: &[i32] = &[0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + let res = v1.rchunks(2) + .zip(v2.rchunks(2)) + .map(|(a, b)| a.iter().sum::() + b.iter().sum::()) + .collect::>(); + assert_eq!(res, vec![26, 18, 6]); +} + +#[test] +fn test_rchunks_mut_count() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.rchunks_mut(3); + assert_eq!(c.count(), 2); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.rchunks_mut(2); + assert_eq!(c2.count(), 3); + + let v3: &mut [i32] = &mut []; + let c3 = v3.rchunks_mut(2); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_rchunks_mut_nth() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks_mut(2); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c2 = v2.rchunks_mut(3); + assert_eq!(c2.nth(1).unwrap(), &[0, 1]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_rchunks_mut_last() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.rchunks_mut(2); + assert_eq!(c.last().unwrap(), &[0, 1]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.rchunks_mut(2); + assert_eq!(c2.last().unwrap(), &[0]); +} + +#[test] +fn test_rchunks_mut_zip() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + for (a, b) in v1.rchunks_mut(2).zip(v2.rchunks(2)) { + let sum = b.iter().sum::(); + for v in a { + *v += sum; + } + } + assert_eq!(v1, [6, 16, 17, 22, 23]); +} + +#[test] +fn test_rchunks_exact_count() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.rchunks_exact(3); + assert_eq!(c.count(), 2); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.rchunks_exact(2); + assert_eq!(c2.count(), 2); + + let v3: &[i32] = &[]; + let c3 = v3.rchunks_exact(2); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_rchunks_exact_nth() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks_exact(2); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + + let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; + let mut c2 = v2.rchunks_exact(3); + assert_eq!(c2.nth(1).unwrap(), &[1, 2, 3]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_rchunks_exact_last() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.rchunks_exact(2); + assert_eq!(c.last().unwrap(), &[0, 1]); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.rchunks_exact(2); + assert_eq!(c2.last().unwrap(), &[1, 2]); +} + +#[test] +fn test_rchunks_exact_remainder() { + let v: &[i32] = &[0, 1, 2, 3, 4]; + let c = v.rchunks_exact(2); + assert_eq!(c.remainder(), &[0]); +} + +#[test] +fn test_rchunks_exact_zip() { + let v1: &[i32] = &[0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + let res = v1.rchunks_exact(2) + .zip(v2.rchunks_exact(2)) + .map(|(a, b)| a.iter().sum::() + b.iter().sum::()) + .collect::>(); + assert_eq!(res, vec![26, 18]); +} + +#[test] +fn test_rchunks_exact_mut_count() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.rchunks_exact_mut(3); + assert_eq!(c.count(), 2); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.rchunks_exact_mut(2); + assert_eq!(c2.count(), 2); + + let v3: &mut [i32] = &mut []; + let c3 = v3.rchunks_exact_mut(2); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_rchunks_exact_mut_nth() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.rchunks_exact_mut(2); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + let mut c2 = v2.rchunks_exact_mut(3); + assert_eq!(c2.nth(1).unwrap(), &[1, 2, 3]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_rchunks_exact_mut_last() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.rchunks_exact_mut(2); + assert_eq!(c.last().unwrap(), &[0, 1]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.rchunks_exact_mut(2); + assert_eq!(c2.last().unwrap(), &[1, 2]); +} + +#[test] +fn test_rchunks_exact_mut_remainder() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c = v.rchunks_exact_mut(2); + assert_eq!(c.into_remainder(), &[0]); +} + +#[test] +fn test_rchunks_exact_mut_zip() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + for (a, b) in v1.rchunks_exact_mut(2).zip(v2.rchunks_exact(2)) { + let sum = b.iter().sum::(); + for v in a { + *v += sum; + } + } + assert_eq!(v1, [0, 16, 17, 22, 23]); +} + #[test] fn test_windows_count() { let v: &[i32] = &[0, 1, 2, 3, 4, 5];