diff --git a/benches/bench1.rs b/benches/bench1.rs index f718ce2c9..53e77b0da 100644 --- a/benches/bench1.rs +++ b/benches/bench1.rs @@ -7,10 +7,6 @@ use std::cmp; use std::iter::repeat; use std::ops::{Add, Range}; -mod extra; - -use crate::extra::ZipSlices; - fn slice_iter(c: &mut Criterion) { let xs: Vec<_> = repeat(1i32).take(20).collect(); @@ -120,72 +116,6 @@ fn zip_slices_ziptuple(c: &mut Criterion) { }); } -fn zipslices(c: &mut Criterion) { - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - c.bench_function("zipslices", move |b| { - b.iter(|| { - for (&x, &y) in ZipSlices::new(&xs, &ys) { - black_box(x); - black_box(y); - } - }) - }); -} - -fn zipslices_mut(c: &mut Criterion) { - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - let xs = black_box(xs); - let mut ys = black_box(ys); - - c.bench_function("zipslices mut", move |b| { - b.iter(|| { - for (&x, &mut y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) { - black_box(x); - black_box(y); - } - }) - }); -} - -fn zipdot_i32_zipslices(c: &mut Criterion) { - let xs = vec![2; 1024]; - let ys = vec![2; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - c.bench_function("zipdot i32 zipslices", move |b| { - b.iter(|| { - let mut s = 0i32; - for (&x, &y) in ZipSlices::new(&xs, &ys) { - s += x * y; - } - s - }) - }); -} - -fn zipdot_f32_zipslices(c: &mut Criterion) { - let xs = vec![2f32; 1024]; - let ys = vec![2f32; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - c.bench_function("zipdot f32 zipslices", move |b| { - b.iter(|| { - let mut s = 0.; - for (&x, &y) in ZipSlices::new(&xs, &ys) { - s += x * y; - } - s - }) - }); -} - fn zip_checked_counted_loop(c: &mut Criterion) { let xs = vec![0; 1024]; let ys = vec![0; 768]; @@ -801,10 +731,6 @@ criterion_group!( zipdot_f32_default_zip, zip_default_zip3, zip_slices_ziptuple, - zipslices, - zipslices_mut, - zipdot_i32_zipslices, - zipdot_f32_zipslices, zip_checked_counted_loop, zipdot_i32_checked_counted_loop, zipdot_f32_checked_counted_loop, diff --git a/benches/extra/mod.rs b/benches/extra/mod.rs deleted file mode 100644 index 52fe5cc3f..000000000 --- a/benches/extra/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub use self::zipslices::ZipSlices; -mod zipslices; diff --git a/benches/extra/zipslices.rs b/benches/extra/zipslices.rs deleted file mode 100644 index 2ec7bc0c0..000000000 --- a/benches/extra/zipslices.rs +++ /dev/null @@ -1,194 +0,0 @@ -use std::cmp; - -// Note: There are different ways to implement ZipSlices. -// This version performed the best in benchmarks. -// -// I also implemented a version with three pointers (tptr, tend, uptr), -// that mimiced slice::Iter and only checked bounds by using tptr == tend, -// but that was inferior to this solution. - -/// An iterator which iterates two slices simultaneously. -/// -/// `ZipSlices` acts like a double-ended `.zip()` iterator. -/// -/// It was intended to be more efficient than `.zip()`, and it was, then -/// rustc changed how it optimizes so it can not promise improved performance -/// at this time. -/// -/// Note that elements past the end of the shortest of the two slices are ignored. -/// -/// Iterator element type for `ZipSlices` is `(T::Item, U::Item)`. For example, -/// for a `ZipSlices<&'a [A], &'b mut [B]>`, the element type is `(&'a A, &'b mut B)`. -#[derive(Clone)] -pub struct ZipSlices { - t: T, - u: U, - len: usize, - index: usize, -} - -impl<'a, 'b, A, B> ZipSlices<&'a [A], &'b [B]> { - /// Create a new `ZipSlices` from slices `a` and `b`. - /// - /// Act like a double-ended `.zip()` iterator, but more efficiently. - /// - /// Note that elements past the end of the shortest of the two slices are ignored. - #[inline(always)] - pub fn new(a: &'a [A], b: &'b [B]) -> Self { - let minl = cmp::min(a.len(), b.len()); - ZipSlices { - t: a, - u: b, - len: minl, - index: 0, - } - } -} - -impl ZipSlices -where - T: Slice, - U: Slice, -{ - /// Create a new `ZipSlices` from slices `a` and `b`. - /// - /// Act like a double-ended `.zip()` iterator, but more efficiently. - /// - /// Note that elements past the end of the shortest of the two slices are ignored. - #[inline(always)] - pub fn from_slices(a: T, b: U) -> Self { - let minl = cmp::min(a.len(), b.len()); - Self { - t: a, - u: b, - len: minl, - index: 0, - } - } -} - -impl Iterator for ZipSlices -where - T: Slice, - U: Slice, -{ - type Item = (T::Item, U::Item); - - #[inline(always)] - fn next(&mut self) -> Option { - unsafe { - if self.index >= self.len { - None - } else { - let i = self.index; - self.index += 1; - Some((self.t.get_unchecked(i), self.u.get_unchecked(i))) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.len - self.index; - (len, Some(len)) - } -} - -impl DoubleEndedIterator for ZipSlices -where - T: Slice, - U: Slice, -{ - #[inline(always)] - fn next_back(&mut self) -> Option { - unsafe { - if self.index >= self.len { - None - } else { - self.len -= 1; - let i = self.len; - Some((self.t.get_unchecked(i), self.u.get_unchecked(i))) - } - } - } -} - -impl ExactSizeIterator for ZipSlices -where - T: Slice, - U: Slice, -{ -} - -unsafe impl Slice for ZipSlices -where - T: Slice, - U: Slice, -{ - type Item = (T::Item, U::Item); - - fn len(&self) -> usize { - self.len - self.index - } - - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { - (self.t.get_unchecked(i), self.u.get_unchecked(i)) - } -} - -/// A helper trait to let `ZipSlices` accept both `&[T]` and `&mut [T]`. -/// -/// # Safety -/// -/// Unsafe trait because: -/// -/// - Implementors must guarantee that `get_unchecked` is valid for all indices `0..len()`. -pub unsafe trait Slice { - /// The type of a reference to the slice's elements - type Item; - #[doc(hidden)] - fn len(&self) -> usize; - #[doc(hidden)] - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item; -} - -unsafe impl<'a, T> Slice for &'a [T] { - type Item = &'a T; - #[inline(always)] - fn len(&self) -> usize { - (**self).len() - } - #[inline(always)] - unsafe fn get_unchecked(&mut self, i: usize) -> &'a T { - debug_assert!(i < self.len()); - (**self).get_unchecked(i) - } -} - -unsafe impl<'a, T> Slice for &'a mut [T] { - type Item = &'a mut T; - #[inline(always)] - fn len(&self) -> usize { - (**self).len() - } - #[inline(always)] - unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut T { - debug_assert!(i < self.len()); - // override the lifetime constraints of &mut &'a mut [T] - (*(*self as *mut [T])).get_unchecked_mut(i) - } -} - -#[test] -fn zipslices() { - let xs = [1, 2, 3, 4, 5, 6]; - let ys = [1, 2, 3, 7]; - ::itertools::assert_equal(ZipSlices::new(&xs, &ys), xs.iter().zip(&ys)); - - let xs = [1, 2, 3, 4, 5, 6]; - let mut ys = [0; 6]; - for (x, y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) { - *y = *x; - } - ::itertools::assert_equal(&xs, &ys); -}