Skip to content

Commit 64f7de9

Browse files
committed
Auto merge of #51339 - sdroege:exact-chunks-remainder, r=alexcrichton
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 is related to #47115 (comment) and the following comments. While there the discussion was first about a way to get the "tail" of the iterator (everything from the slice that is still not iterated yet), this gives kind of unintuitive behaviour and is inconsistent with how the other slice iterators work. Unintuitive because the `next_back` would have no effect on the tail (or otherwise the tail could not include the remainder items), inconsistent because a) generally the idea of the slice iterators seems to be to only ever return items that were not iterated yet (and don't provide a way to access the same item twice) and b) we would return a "flat" `&[T]` slice but the iterator's shape is `&[[T]]` instead, c) the mutable variant would have to borrow from the iterator instead of the underlying slice (all other iterator functions borrow from the underlying slice!) As such, I've only implemented functions to get the remainder. This also allows the implementation to be completely safe still (and around slices instead of raw pointers), while getting the tail would either be inefficient or would have to be implemented around raw pointers. CC @Kerollmops
2 parents 6cc42a4 + 903624f commit 64f7de9

File tree

2 files changed

+54
-8
lines changed

2 files changed

+54
-8
lines changed

src/libcore/slice/mod.rs

+40-8
Original file line numberDiff line numberDiff line change
@@ -729,7 +729,8 @@ impl<T> [T] {
729729
/// Returns an iterator over `chunk_size` elements of the slice at a
730730
/// time. The chunks are slices and do not overlap. If `chunk_size` does
731731
/// not divide the length of the slice, then the last up to `chunk_size-1`
732-
/// elements will be omitted.
732+
/// elements will be omitted and can be retrieved from the `remainder`
733+
/// function of the iterator.
733734
///
734735
/// Due to each chunk having exactly `chunk_size` elements, the compiler
735736
/// can often optimize the resulting code better than in the case of
@@ -758,14 +759,15 @@ impl<T> [T] {
758759
assert!(chunk_size != 0);
759760
let rem = self.len() % chunk_size;
760761
let len = self.len() - rem;
761-
ExactChunks { v: &self[..len], chunk_size: chunk_size}
762+
let (fst, snd) = self.split_at(len);
763+
ExactChunks { v: fst, rem: snd, chunk_size: chunk_size}
762764
}
763765

764766
/// Returns an iterator over `chunk_size` elements of the slice at a time.
765767
/// The chunks are mutable slices, and do not overlap. If `chunk_size` does
766768
/// not divide the length of the slice, then the last up to `chunk_size-1`
767-
/// elements will be omitted.
768-
///
769+
/// elements will be omitted and can be retrieved from the `into_remainder`
770+
/// function of the iterator.
769771
///
770772
/// Due to each chunk having exactly `chunk_size` elements, the compiler
771773
/// can often optimize the resulting code better than in the case of
@@ -799,7 +801,8 @@ impl<T> [T] {
799801
assert!(chunk_size != 0);
800802
let rem = self.len() % chunk_size;
801803
let len = self.len() - rem;
802-
ExactChunksMut { v: &mut self[..len], chunk_size: chunk_size}
804+
let (fst, snd) = self.split_at_mut(len);
805+
ExactChunksMut { v: fst, rem: snd, chunk_size: chunk_size}
803806
}
804807

805808
/// Divides one slice into two at an index.
@@ -3657,25 +3660,39 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> {
36573660
/// time).
36583661
///
36593662
/// When the slice len is not evenly divided by the chunk size, the last
3660-
/// up to `chunk_size-1` elements will be omitted.
3663+
/// up to `chunk_size-1` elements will be omitted but can be retrieved from
3664+
/// the [`remainder`] function from the iterator.
36613665
///
36623666
/// This struct is created by the [`exact_chunks`] method on [slices].
36633667
///
36643668
/// [`exact_chunks`]: ../../std/primitive.slice.html#method.exact_chunks
3669+
/// [`remainder`]: ../../std/slice/struct.ExactChunks.html#method.remainder
36653670
/// [slices]: ../../std/primitive.slice.html
36663671
#[derive(Debug)]
36673672
#[unstable(feature = "exact_chunks", issue = "47115")]
36683673
pub struct ExactChunks<'a, T:'a> {
36693674
v: &'a [T],
3675+
rem: &'a [T],
36703676
chunk_size: usize
36713677
}
36723678

3679+
#[unstable(feature = "exact_chunks", issue = "47115")]
3680+
impl<'a, T> ExactChunks<'a, T> {
3681+
/// Return the remainder of the original slice that is not going to be
3682+
/// returned by the iterator. The returned slice has at most `chunk_size-1`
3683+
/// elements.
3684+
pub fn remainder(&self) -> &'a [T] {
3685+
self.rem
3686+
}
3687+
}
3688+
36733689
// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
36743690
#[unstable(feature = "exact_chunks", issue = "47115")]
36753691
impl<'a, T> Clone for ExactChunks<'a, T> {
36763692
fn clone(&self) -> ExactChunks<'a, T> {
36773693
ExactChunks {
36783694
v: self.v,
3695+
rem: self.rem,
36793696
chunk_size: self.chunk_size,
36803697
}
36813698
}
@@ -3763,20 +3780,35 @@ unsafe impl<'a, T> TrustedRandomAccess for ExactChunks<'a, T> {
37633780
}
37643781

37653782
/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
3766-
/// elements at a time). When the slice len is not evenly divided by the chunk
3767-
/// size, the last up to `chunk_size-1` elements will be omitted.
3783+
/// elements at a time).
3784+
///
3785+
/// When the slice len is not evenly divided by the chunk size, the last up to
3786+
/// `chunk_size-1` elements will be omitted but can be retrieved from the
3787+
/// [`into_remainder`] function from the iterator.
37683788
///
37693789
/// This struct is created by the [`exact_chunks_mut`] method on [slices].
37703790
///
37713791
/// [`exact_chunks_mut`]: ../../std/primitive.slice.html#method.exact_chunks_mut
3792+
/// [`into_remainder`]: ../../std/slice/struct.ExactChunksMut.html#method.into_remainder
37723793
/// [slices]: ../../std/primitive.slice.html
37733794
#[derive(Debug)]
37743795
#[unstable(feature = "exact_chunks", issue = "47115")]
37753796
pub struct ExactChunksMut<'a, T:'a> {
37763797
v: &'a mut [T],
3798+
rem: &'a mut [T],
37773799
chunk_size: usize
37783800
}
37793801

3802+
#[unstable(feature = "exact_chunks", issue = "47115")]
3803+
impl<'a, T> ExactChunksMut<'a, T> {
3804+
/// Return the remainder of the original slice that is not going to be
3805+
/// returned by the iterator. The returned slice has at most `chunk_size-1`
3806+
/// elements.
3807+
pub fn into_remainder(self) -> &'a mut [T] {
3808+
self.rem
3809+
}
3810+
}
3811+
37803812
#[unstable(feature = "exact_chunks", issue = "47115")]
37813813
impl<'a, T> Iterator for ExactChunksMut<'a, T> {
37823814
type Item = &'a mut [T];

src/libcore/tests/slice.rs

+14
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,13 @@ fn test_exact_chunks_last() {
259259
assert_eq!(c2.last().unwrap(), &[2, 3]);
260260
}
261261

262+
#[test]
263+
fn test_exact_chunks_remainder() {
264+
let v: &[i32] = &[0, 1, 2, 3, 4];
265+
let c = v.exact_chunks(2);
266+
assert_eq!(c.remainder(), &[4]);
267+
}
268+
262269
#[test]
263270
fn test_exact_chunks_zip() {
264271
let v1: &[i32] = &[0, 1, 2, 3, 4];
@@ -310,6 +317,13 @@ fn test_exact_chunks_mut_last() {
310317
assert_eq!(c2.last().unwrap(), &[2, 3]);
311318
}
312319

320+
#[test]
321+
fn test_exact_chunks_mut_remainder() {
322+
let v: &mut [i32] = &mut [0, 1, 2, 3, 4];
323+
let c = v.exact_chunks_mut(2);
324+
assert_eq!(c.into_remainder(), &[4]);
325+
}
326+
313327
#[test]
314328
fn test_exact_chunks_mut_zip() {
315329
let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];

0 commit comments

Comments
 (0)