123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- 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 pointes (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<T, U>` 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, U> {
- 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<T, U> ZipSlices<T, U>
- 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());
- ZipSlices {
- t: a,
- u: b,
- len: minl,
- index: 0,
- }
- }
- }
- impl<T, U> Iterator for ZipSlices<T, U>
- where T: Slice,
- U: Slice
- {
- type Item = (T::Item, U::Item);
- #[inline(always)]
- fn next(&mut self) -> Option<Self::Item> {
- 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<usize>) {
- let len = self.len - self.index;
- (len, Some(len))
- }
- }
- impl<T, U> DoubleEndedIterator for ZipSlices<T, U>
- where T: Slice,
- U: Slice
- {
- #[inline(always)]
- fn next_back(&mut self) -> Option<Self::Item> {
- 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<T, U> ExactSizeIterator for ZipSlices<T, U>
- where T: Slice,
- U: Slice
- {}
- unsafe impl<T, U> Slice for ZipSlices<T, U>
- 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]`.
- ///
- /// 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);
- }
|