Add ExactChunks::remainder and ExactChunks::into_remainder

These allow to get the leftover items of the slice that are not being
iterated as part of the iterator due to not filling a complete chunk.

The mutable version consumes the slice because otherwise we would either
a) have to borrow the iterator instead of taking the lifetime of
the underlying slice, which is not what *any* of the other iterator
functions is doing, or
b) would allow returning multiple mutable references to the same data

The current behaviour of consuming the iterator is consistent with
IterMut::into_slice for the normal iterator.
This commit is contained in:
Sebastian Dröge 2018-06-04 09:02:58 +03:00
parent 6eafab06cf
commit 903624fb8d
2 changed files with 54 additions and 8 deletions

View File

@ -729,7 +729,8 @@ impl<T> [T] {
/// Returns an iterator over `chunk_size` elements of the slice at a /// 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 /// 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` /// not divide the length of the slice, then the last up to `chunk_size-1`
/// elements will be omitted. /// 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 /// Due to each chunk having exactly `chunk_size` elements, the compiler
/// can often optimize the resulting code better than in the case of /// can often optimize the resulting code better than in the case of
@ -758,14 +759,15 @@ impl<T> [T] {
assert!(chunk_size != 0); assert!(chunk_size != 0);
let rem = self.len() % chunk_size; let rem = self.len() % chunk_size;
let len = self.len() - rem; let len = self.len() - rem;
ExactChunks { v: &self[..len], chunk_size: chunk_size} let (fst, snd) = self.split_at(len);
ExactChunks { v: fst, rem: snd, chunk_size: chunk_size}
} }
/// Returns an iterator over `chunk_size` elements of the slice at a time. /// 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 /// 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` /// not divide the length of the slice, then the last up to `chunk_size-1`
/// elements will be omitted. /// 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 /// Due to each chunk having exactly `chunk_size` elements, the compiler
/// can often optimize the resulting code better than in the case of /// can often optimize the resulting code better than in the case of
@ -799,7 +801,8 @@ impl<T> [T] {
assert!(chunk_size != 0); assert!(chunk_size != 0);
let rem = self.len() % chunk_size; let rem = self.len() % chunk_size;
let len = self.len() - rem; let len = self.len() - rem;
ExactChunksMut { v: &mut self[..len], chunk_size: chunk_size} let (fst, snd) = self.split_at_mut(len);
ExactChunksMut { v: fst, rem: snd, chunk_size: chunk_size}
} }
/// Divides one slice into two at an index. /// Divides one slice into two at an index.
@ -3654,25 +3657,39 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> {
/// time). /// time).
/// ///
/// When the slice len is not evenly divided by the chunk size, the last /// When the slice len is not evenly divided by the chunk size, the last
/// up to `chunk_size-1` elements will be omitted. /// 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 [`exact_chunks`] method on [slices]. /// This struct is created by the [`exact_chunks`] method on [slices].
/// ///
/// [`exact_chunks`]: ../../std/primitive.slice.html#method.exact_chunks /// [`exact_chunks`]: ../../std/primitive.slice.html#method.exact_chunks
/// [`remainder`]: ../../std/slice/struct.ExactChunks.html#method.remainder
/// [slices]: ../../std/primitive.slice.html /// [slices]: ../../std/primitive.slice.html
#[derive(Debug)] #[derive(Debug)]
#[unstable(feature = "exact_chunks", issue = "47115")] #[unstable(feature = "exact_chunks", issue = "47115")]
pub struct ExactChunks<'a, T:'a> { pub struct ExactChunks<'a, T:'a> {
v: &'a [T], v: &'a [T],
rem: &'a [T],
chunk_size: usize chunk_size: usize
} }
#[unstable(feature = "exact_chunks", issue = "47115")]
impl<'a, T> ExactChunks<'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)]` // FIXME(#26925) Remove in favor of `#[derive(Clone)]`
#[unstable(feature = "exact_chunks", issue = "47115")] #[unstable(feature = "exact_chunks", issue = "47115")]
impl<'a, T> Clone for ExactChunks<'a, T> { impl<'a, T> Clone for ExactChunks<'a, T> {
fn clone(&self) -> ExactChunks<'a, T> { fn clone(&self) -> ExactChunks<'a, T> {
ExactChunks { ExactChunks {
v: self.v, v: self.v,
rem: self.rem,
chunk_size: self.chunk_size, chunk_size: self.chunk_size,
} }
} }
@ -3760,20 +3777,35 @@ unsafe impl<'a, T> TrustedRandomAccess for ExactChunks<'a, T> {
} }
/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` /// 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 /// elements at a time).
/// size, the last up to `chunk_size-1` elements will be omitted. ///
/// 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 [`exact_chunks_mut`] method on [slices]. /// This struct is created by the [`exact_chunks_mut`] method on [slices].
/// ///
/// [`exact_chunks_mut`]: ../../std/primitive.slice.html#method.exact_chunks_mut /// [`exact_chunks_mut`]: ../../std/primitive.slice.html#method.exact_chunks_mut
/// [`into_remainder`]: ../../std/slice/struct.ExactChunksMut.html#method.into_remainder
/// [slices]: ../../std/primitive.slice.html /// [slices]: ../../std/primitive.slice.html
#[derive(Debug)] #[derive(Debug)]
#[unstable(feature = "exact_chunks", issue = "47115")] #[unstable(feature = "exact_chunks", issue = "47115")]
pub struct ExactChunksMut<'a, T:'a> { pub struct ExactChunksMut<'a, T:'a> {
v: &'a mut [T], v: &'a mut [T],
rem: &'a mut [T],
chunk_size: usize chunk_size: usize
} }
#[unstable(feature = "exact_chunks", issue = "47115")]
impl<'a, T> ExactChunksMut<'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 = "exact_chunks", issue = "47115")] #[unstable(feature = "exact_chunks", issue = "47115")]
impl<'a, T> Iterator for ExactChunksMut<'a, T> { impl<'a, T> Iterator for ExactChunksMut<'a, T> {
type Item = &'a mut [T]; type Item = &'a mut [T];

View File

@ -259,6 +259,13 @@ fn test_exact_chunks_last() {
assert_eq!(c2.last().unwrap(), &[2, 3]); assert_eq!(c2.last().unwrap(), &[2, 3]);
} }
#[test]
fn test_exact_chunks_remainder() {
let v: &[i32] = &[0, 1, 2, 3, 4];
let c = v.exact_chunks(2);
assert_eq!(c.remainder(), &[4]);
}
#[test] #[test]
fn test_exact_chunks_zip() { fn test_exact_chunks_zip() {
let v1: &[i32] = &[0, 1, 2, 3, 4]; let v1: &[i32] = &[0, 1, 2, 3, 4];
@ -310,6 +317,13 @@ fn test_exact_chunks_mut_last() {
assert_eq!(c2.last().unwrap(), &[2, 3]); assert_eq!(c2.last().unwrap(), &[2, 3]);
} }
#[test]
fn test_exact_chunks_mut_remainder() {
let v: &mut [i32] = &mut [0, 1, 2, 3, 4];
let c = v.exact_chunks_mut(2);
assert_eq!(c.into_remainder(), &[4]);
}
#[test] #[test]
fn test_exact_chunks_mut_zip() { fn test_exact_chunks_mut_zip() {
let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];