Skip to content

Commit eae3bfa

Browse files
blussbrson
authored andcommitted
Remove data structure specialization for .zip() iterator
Go back on half the specialization, the part that changed the Zip struct's fields themselves depending on the types of the iterators. This means that the Zip iterator will always carry two usize fields, which are unused. If a whole for loop using a .zip() iterator is inlined, these are simply removed and have no effect. The same improvement for Zip of for example slice iterators remain, and they still optimize well. However, like when the specialization of zip was merged, the compiler is still very sensistive to the exact context. For example this code only autovectorizes if the function is used, not if the code in zip_sum_i32 is inserted inline it was called: ``` fn zip_sum_i32(xs: &[i32], ys: &[i32]) -> i32 { let mut s = 0; for (&x, &y) in xs.iter().zip(ys) { s += x * y; } s } fn zipdot_i32_default_zip(b: &mut test::Bencher) { let xs = vec![1; 1024]; let ys = vec![1; 1024]; b.iter(|| { zip_sum_i32(&xs, &ys) }) } ``` Include a test that checks that Zip<T, U> is covariant w.r.t. T and U.
1 parent e962b88 commit eae3bfa

File tree

2 files changed

+31
-38
lines changed

2 files changed

+31
-38
lines changed

src/libcore/iter/mod.rs

+14-38
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,9 @@ impl<A, B> DoubleEndedIterator for Chain<A, B> where
626626
pub struct Zip<A, B> {
627627
a: A,
628628
b: B,
629-
spec: <(A, B) as ZipImplData>::Data,
629+
// index and len are only used by the specialized version of zip
630+
index: usize,
631+
len: usize,
630632
}
631633

632634
#[stable(feature = "rust1", since = "1.0.0")]
@@ -668,17 +670,6 @@ trait ZipImpl<A, B> {
668670
B: DoubleEndedIterator + ExactSizeIterator;
669671
}
670672

671-
// Zip specialization data members
672-
#[doc(hidden)]
673-
trait ZipImplData {
674-
type Data: 'static + Clone + Default + fmt::Debug;
675-
}
676-
677-
#[doc(hidden)]
678-
impl<T> ZipImplData for T {
679-
default type Data = ();
680-
}
681-
682673
// General Zip impl
683674
#[doc(hidden)]
684675
impl<A, B> ZipImpl<A, B> for Zip<A, B>
@@ -689,7 +680,8 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
689680
Zip {
690681
a: a,
691682
b: b,
692-
spec: Default::default(), // unused
683+
index: 0, // unused
684+
len: 0, // unused
693685
}
694686
}
695687

@@ -742,20 +734,6 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
742734
}
743735
}
744736

745-
#[doc(hidden)]
746-
#[derive(Default, Debug, Clone)]
747-
struct ZipImplFields {
748-
index: usize,
749-
len: usize,
750-
}
751-
752-
#[doc(hidden)]
753-
impl<A, B> ZipImplData for (A, B)
754-
where A: TrustedRandomAccess, B: TrustedRandomAccess
755-
{
756-
type Data = ZipImplFields;
757-
}
758-
759737
#[doc(hidden)]
760738
impl<A, B> ZipImpl<A, B> for Zip<A, B>
761739
where A: TrustedRandomAccess, B: TrustedRandomAccess
@@ -765,18 +743,16 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
765743
Zip {
766744
a: a,
767745
b: b,
768-
spec: ZipImplFields {
769-
index: 0,
770-
len: len,
771-
}
746+
index: 0,
747+
len: len,
772748
}
773749
}
774750

775751
#[inline]
776752
fn next(&mut self) -> Option<(A::Item, B::Item)> {
777-
if self.spec.index < self.spec.len {
778-
let i = self.spec.index;
779-
self.spec.index += 1;
753+
if self.index < self.len {
754+
let i = self.index;
755+
self.index += 1;
780756
unsafe {
781757
Some((self.a.get_unchecked(i), self.b.get_unchecked(i)))
782758
}
@@ -787,7 +763,7 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
787763

788764
#[inline]
789765
fn size_hint(&self) -> (usize, Option<usize>) {
790-
let len = self.spec.len - self.spec.index;
766+
let len = self.len - self.index;
791767
(len, Some(len))
792768
}
793769

@@ -796,9 +772,9 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
796772
where A: DoubleEndedIterator + ExactSizeIterator,
797773
B: DoubleEndedIterator + ExactSizeIterator
798774
{
799-
if self.spec.index < self.spec.len {
800-
self.spec.len -= 1;
801-
let i = self.spec.len;
775+
if self.index < self.len {
776+
self.len -= 1;
777+
let i = self.len;
802778
unsafe {
803779
Some((self.a.get_unchecked(i), self.b.get_unchecked(i)))
804780
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(warnings)]
12+
13+
use std::iter::Zip;
14+
15+
fn zip_covariant<'a, A, B>(iter: Zip<&'static A, &'static B>) -> Zip<&'a A, &'a B> { iter }
16+
17+
fn main() { }

0 commit comments

Comments
 (0)