From 51d546f4aa8a94b81d2a580518d95d1ab12a3655 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Tue, 2 Jan 2018 02:13:20 +0200 Subject: Add slice::ExactChunks and ::ExactChunksMut iterators These guarantee that always the requested slice size will be returned and any leftoever elements at the end will be ignored. It allows llvm to get rid of bounds checks in the code using the iterator. This is inspired by the same iterators provided by ndarray. See https://github.com/rust-lang/rust/issues/47115 --- src/liballoc/lib.rs | 1 + src/liballoc/slice.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) (limited to 'src/liballoc') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 3cc3ea46796..d8ce28695ab 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -124,6 +124,7 @@ #![feature(unsize)] #![feature(allocator_internals)] #![feature(on_unimplemented)] +#![feature(exact_chunks)] #![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol, swap_with_slice, i128))] #![cfg_attr(test, feature(test, box_heap))] diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index fa73197885b..bae36673637 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -123,6 +123,8 @@ pub use core::slice::{from_raw_parts, from_raw_parts_mut}; pub use core::slice::{from_ref, from_ref_mut}; #[unstable(feature = "slice_get_slice", issue = "35729")] pub use core::slice::SliceIndex; +#[unstable(feature = "exact_chunks", issue = "47115")] +pub use core::slice::{ExactChunks, ExactChunksMut}; //////////////////////////////////////////////////////////////////////////////// // Basic slice extension methods @@ -631,6 +633,31 @@ impl [T] { core_slice::SliceExt::chunks(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. + /// + /// # Panics + /// + /// Panics if `chunk_size` is 0. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.chunks(2); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert_eq!(iter.next().unwrap(), &['m']); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "exact_chunks", issue = "47115")] + #[inline] + pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks { + core_slice::SliceExt::exact_chunks(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 @@ -660,6 +687,35 @@ impl [T] { core_slice::SliceExt::chunks_mut(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 up to `chunk_size-1` + /// elements will be omitted. + /// + /// # Panics + /// + /// Panics if `chunk_size` is 0. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.exact_chunks_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 3]); + /// ``` + #[unstable(feature = "exact_chunks", issue = "47115")] + #[inline] + pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut { + core_slice::SliceExt::exact_chunks_mut(self, chunk_size) + } + /// Divides one slice into two at an index. /// /// The first will contain all indices from `[0, mid)` (excluding -- cgit 1.4.1-3-g733a5 From 83396fc712aefd24531f7925d377b148da8ed04f Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Tue, 2 Jan 2018 14:54:18 +0200 Subject: Add #![feature(exact_chunks)] to the documentation examples to fix the doc tests --- src/liballoc/slice.rs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/liballoc') diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index bae36673637..6a3970f3728 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -645,6 +645,8 @@ impl [T] { /// # Examples /// /// ``` + /// #![feature(exact_chunks)] + /// /// let slice = ['l', 'o', 'r', 'e', 'm']; /// let mut iter = slice.chunks(2); /// assert_eq!(iter.next().unwrap(), &['l', 'o']); @@ -699,6 +701,8 @@ impl [T] { /// # Examples /// /// ``` + /// #![feature(exact_chunks)] + /// /// let v = &mut [0, 0, 0, 0, 0]; /// let mut count = 1; /// -- cgit 1.4.1-3-g733a5 From 802ba9ea5b432d36444d8da8646bd2a1624b9dfa Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Tue, 2 Jan 2018 14:55:25 +0200 Subject: Fix assertions in examples of the exact_chunk() documentation --- src/liballoc/slice.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/liballoc') diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 6a3970f3728..9ff39363fd7 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -651,7 +651,6 @@ impl [T] { /// let mut iter = slice.chunks(2); /// assert_eq!(iter.next().unwrap(), &['l', 'o']); /// assert_eq!(iter.next().unwrap(), &['r', 'e']); - /// assert_eq!(iter.next().unwrap(), &['m']); /// assert!(iter.next().is_none()); /// ``` #[unstable(feature = "exact_chunks", issue = "47115")] @@ -712,7 +711,7 @@ impl [T] { /// } /// count += 1; /// } - /// assert_eq!(v, &[1, 1, 2, 2, 3]); + /// assert_eq!(v, &[1, 1, 2, 2]); /// ``` #[unstable(feature = "exact_chunks", issue = "47115")] #[inline] -- cgit 1.4.1-3-g733a5 From e51a89a0ad35f42af9c39d4ada25a5ad9746cd62 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Tue, 2 Jan 2018 19:21:39 +0200 Subject: Fix doctests for slice::exact_chunks() for real --- src/liballoc/slice.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/liballoc') diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 9ff39363fd7..182e9b0a00e 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -648,7 +648,7 @@ impl [T] { /// #![feature(exact_chunks)] /// /// let slice = ['l', 'o', 'r', 'e', 'm']; - /// let mut iter = slice.chunks(2); + /// let mut iter = slice.exact_chunks(2); /// assert_eq!(iter.next().unwrap(), &['l', 'o']); /// assert_eq!(iter.next().unwrap(), &['r', 'e']); /// assert!(iter.next().is_none()); @@ -711,7 +711,7 @@ impl [T] { /// } /// count += 1; /// } - /// assert_eq!(v, &[1, 1, 2, 2]); + /// assert_eq!(v, &[1, 1, 2, 2, 0]); /// ``` #[unstable(feature = "exact_chunks", issue = "47115")] #[inline] -- cgit 1.4.1-3-g733a5 From 8a82e8e89f6eec3744f12d45c12ce05d48233d8d Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Tue, 9 Jan 2018 22:58:41 +0200 Subject: Mention in the exact_chunks docs that this can often be optimized better by the compiler And also link from the normal chunks iterator to the exact_chunks one. --- src/liballoc/slice.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/liballoc') diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 182e9b0a00e..f8980b8777e 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -613,6 +613,9 @@ impl [T] { /// not divide the length of the slice, then the last chunk will /// not have length `chunk_size`. /// + /// See [`exact_chunks`] for a variant of this iterator that returns chunks + /// of always exactly `chunk_size` elements. + /// /// # Panics /// /// Panics if `chunk_size` is 0. @@ -638,6 +641,10 @@ impl [T] { /// not divide the length of the slice, then the last up to `chunk_size-1` /// elements will be omitted. /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler + /// can often optimize the resulting code better than in the case of + /// [`chunks`]. + /// /// # Panics /// /// Panics if `chunk_size` is 0. @@ -664,6 +671,9 @@ impl [T] { /// not divide the length of the slice, then the last chunk will not /// have length `chunk_size`. /// + /// See [`exact_chunks_mut`] for a variant of this iterator that returns chunks + /// of always exactly `chunk_size` elements. + /// /// # Panics /// /// Panics if `chunk_size` is 0. @@ -693,6 +703,11 @@ impl [T] { /// not divide the length of the slice, then the last up to `chunk_size-1` /// elements will be omitted. /// + /// + /// 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`]. + /// /// # Panics /// /// Panics if `chunk_size` is 0. -- cgit 1.4.1-3-g733a5 From baa81dc77f0a46b35c6b103cba79334d87622f2b Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Thu, 11 Jan 2018 12:11:32 +0200 Subject: Use assert_eq!() instead of assert!(a == b) in slice chunks_mut() unit test This way more useful information is printed if the test ever fails. --- src/liballoc/tests/slice.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/liballoc') diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs index 85d5ce304b8..c2f7522c5f0 100644 --- a/src/liballoc/tests/slice.rs +++ b/src/liballoc/tests/slice.rs @@ -1124,7 +1124,7 @@ fn test_mut_chunks() { } } let result = [0, 0, 0, 1, 1, 1, 2]; - assert!(v == result); + assert_eq!(v, result); } #[test] @@ -1136,7 +1136,7 @@ fn test_mut_chunks_rev() { } } let result = [2, 2, 2, 1, 1, 1, 0]; - assert!(v == result); + assert_eq!(v, result); } #[test] -- cgit 1.4.1-3-g733a5 From 5f4fc8214279f2ffadbf2cc3a4c22b748c17bd15 Mon Sep 17 00:00:00 2001 From: Sebastian Dröge Date: Thu, 11 Jan 2018 12:13:45 +0200 Subject: Add unit tests for exact_chunks/exact_chunks_mut These are basically modified copies of the chunks/chunks_mut tests. --- src/liballoc/tests/lib.rs | 1 + src/liballoc/tests/slice.rs | 56 ++++++++++++++++++++++++ src/libcore/tests/lib.rs | 1 + src/libcore/tests/slice.rs | 104 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 162 insertions(+) (limited to 'src/liballoc') diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index f1e95883b38..eee229bc6fd 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -30,6 +30,7 @@ #![feature(string_retain)] #![feature(unboxed_closures)] #![feature(unicode)] +#![feature(exact_chunks)] extern crate alloc_system; extern crate std_unicode; diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs index c2f7522c5f0..5a3e5e6cb78 100644 --- a/src/liballoc/tests/slice.rs +++ b/src/liballoc/tests/slice.rs @@ -910,6 +910,30 @@ fn test_chunksator_0() { let _it = v.chunks(0); } +#[test] +fn test_exact_chunksator() { + let v = &[1, 2, 3, 4, 5]; + + assert_eq!(v.exact_chunks(2).len(), 2); + + let chunks: &[&[_]] = &[&[1, 2], &[3, 4]]; + assert_eq!(v.exact_chunks(2).collect::>(), chunks); + let chunks: &[&[_]] = &[&[1, 2, 3]]; + assert_eq!(v.exact_chunks(3).collect::>(), chunks); + let chunks: &[&[_]] = &[]; + assert_eq!(v.exact_chunks(6).collect::>(), chunks); + + let chunks: &[&[_]] = &[&[3, 4], &[1, 2]]; + assert_eq!(v.exact_chunks(2).rev().collect::>(), chunks); +} + +#[test] +#[should_panic] +fn test_exact_chunksator_0() { + let v = &[1, 2, 3, 4]; + let _it = v.exact_chunks(0); +} + #[test] fn test_reverse_part() { let mut values = [1, 2, 3, 4, 5]; @@ -1146,6 +1170,38 @@ fn test_mut_chunks_0() { let _it = v.chunks_mut(0); } +#[test] +fn test_mut_exact_chunks() { + let mut v = [0, 1, 2, 3, 4, 5, 6]; + assert_eq!(v.exact_chunks_mut(2).len(), 3); + for (i, chunk) in v.exact_chunks_mut(3).enumerate() { + for x in chunk { + *x = i as u8; + } + } + let result = [0, 0, 0, 1, 1, 1, 6]; + assert_eq!(v, result); +} + +#[test] +fn test_mut_exact_chunks_rev() { + let mut v = [0, 1, 2, 3, 4, 5, 6]; + for (i, chunk) in v.exact_chunks_mut(3).rev().enumerate() { + for x in chunk { + *x = i as u8; + } + } + let result = [1, 1, 1, 0, 0, 0, 6]; + assert_eq!(v, result); +} + +#[test] +#[should_panic] +fn test_mut_exact_chunks_0() { + let mut v = [1, 2, 3, 4]; + let _it = v.exact_chunks_mut(0); +} + #[test] fn test_mut_last() { let mut x = [1, 2, 3, 4, 5]; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index c4b85b82981..2c0009569d7 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -42,6 +42,7 @@ #![feature(try_from)] #![feature(try_trait)] #![feature(unique)] +#![feature(exact_chunks)] extern crate core; extern crate test; diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 4f9fc30785c..a89a88ac0af 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -202,6 +202,110 @@ fn test_chunks_mut_zip() { assert_eq!(v1, [13, 14, 19, 20, 14]); } +#[test] +fn test_exact_chunks_count() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.exact_chunks(3); + assert_eq!(c.count(), 2); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.exact_chunks(2); + assert_eq!(c2.count(), 2); + + let v3: &[i32] = &[]; + let c3 = v3.exact_chunks(2); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_exact_chunks_nth() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.exact_chunks(2); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[4, 5]); + + let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; + let mut c2 = v2.exact_chunks(3); + assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_exact_chunks_last() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.exact_chunks(2); + assert_eq!(c.last().unwrap(), &[4, 5]); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.exact_chunks(2); + assert_eq!(c2.last().unwrap(), &[2, 3]); +} + +#[test] +fn test_exact_chunks_zip() { + let v1: &[i32] = &[0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + let res = v1.exact_chunks(2) + .zip(v2.exact_chunks(2)) + .map(|(a, b)| a.iter().sum::() + b.iter().sum::()) + .collect::>(); + assert_eq!(res, vec![14, 22]); +} + +#[test] +fn test_exact_chunks_mut_count() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.exact_chunks_mut(3); + assert_eq!(c.count(), 2); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.exact_chunks_mut(2); + assert_eq!(c2.count(), 2); + + let v3: &mut [i32] = &mut []; + let c3 = v3.exact_chunks_mut(2); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_exact_chunks_mut_nth() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.exact_chunks_mut(2); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + let mut c2 = v2.exact_chunks_mut(3); + assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_exact_chunks_mut_last() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.exact_chunks_mut(2); + assert_eq!(c.last().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.exact_chunks_mut(2); + assert_eq!(c2.last().unwrap(), &[2, 3]); +} + +#[test] +fn test_exact_chunks_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.exact_chunks_mut(2).zip(v2.exact_chunks(2)) { + let sum = b.iter().sum::(); + for v in a { + *v += sum; + } + } + assert_eq!(v1, [13, 14, 19, 20, 4]); +} + #[test] fn test_windows_count() { let v: &[i32] = &[0, 1, 2, 3, 4, 5]; -- cgit 1.4.1-3-g733a5