Skip to content

Commit fb62f4d

Browse files
authored
Auto merge of #36490 - bluss:zip-slightly-despecialized-edition, r=alexcrichton
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. Previous PR: #33090 This means that the Zip iterator will always carry two usize fields, which are sometimes 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 where it was called: ```rust 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. Fixes #35727
2 parents cde61ba + af1a3ff commit fb62f4d

File tree

2 files changed

+31
-38
lines changed

2 files changed

+31
-38
lines changed

Diff for: src/libcore/iter/mod.rs

+14-38
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,9 @@ impl<A, B> FusedIterator for Chain<A, B>
643643
pub struct Zip<A, B> {
644644
a: A,
645645
b: B,
646-
spec: <(A, B) as ZipImplData>::Data,
646+
// index and len are only used by the specialized version of zip
647+
index: usize,
648+
len: usize,
647649
}
648650

649651
#[stable(feature = "rust1", since = "1.0.0")]
@@ -685,17 +687,6 @@ trait ZipImpl<A, B> {
685687
B: DoubleEndedIterator + ExactSizeIterator;
686688
}
687689

688-
// Zip specialization data members
689-
#[doc(hidden)]
690-
trait ZipImplData {
691-
type Data: 'static + Clone + Default + fmt::Debug;
692-
}
693-
694-
#[doc(hidden)]
695-
impl<T> ZipImplData for T {
696-
default type Data = ();
697-
}
698-
699690
// General Zip impl
700691
#[doc(hidden)]
701692
impl<A, B> ZipImpl<A, B> for Zip<A, B>
@@ -706,7 +697,8 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
706697
Zip {
707698
a: a,
708699
b: b,
709-
spec: Default::default(), // unused
700+
index: 0, // unused
701+
len: 0, // unused
710702
}
711703
}
712704

@@ -759,20 +751,6 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
759751
}
760752
}
761753

762-
#[doc(hidden)]
763-
#[derive(Default, Debug, Clone)]
764-
struct ZipImplFields {
765-
index: usize,
766-
len: usize,
767-
}
768-
769-
#[doc(hidden)]
770-
impl<A, B> ZipImplData for (A, B)
771-
where A: TrustedRandomAccess, B: TrustedRandomAccess
772-
{
773-
type Data = ZipImplFields;
774-
}
775-
776754
#[doc(hidden)]
777755
impl<A, B> ZipImpl<A, B> for Zip<A, B>
778756
where A: TrustedRandomAccess, B: TrustedRandomAccess
@@ -782,18 +760,16 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
782760
Zip {
783761
a: a,
784762
b: b,
785-
spec: ZipImplFields {
786-
index: 0,
787-
len: len,
788-
}
763+
index: 0,
764+
len: len,
789765
}
790766
}
791767

792768
#[inline]
793769
fn next(&mut self) -> Option<(A::Item, B::Item)> {
794-
if self.spec.index < self.spec.len {
795-
let i = self.spec.index;
796-
self.spec.index += 1;
770+
if self.index < self.len {
771+
let i = self.index;
772+
self.index += 1;
797773
unsafe {
798774
Some((self.a.get_unchecked(i), self.b.get_unchecked(i)))
799775
}
@@ -804,7 +780,7 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
804780

805781
#[inline]
806782
fn size_hint(&self) -> (usize, Option<usize>) {
807-
let len = self.spec.len - self.spec.index;
783+
let len = self.len - self.index;
808784
(len, Some(len))
809785
}
810786

@@ -813,9 +789,9 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
813789
where A: DoubleEndedIterator + ExactSizeIterator,
814790
B: DoubleEndedIterator + ExactSizeIterator
815791
{
816-
if self.spec.index < self.spec.len {
817-
self.spec.len -= 1;
818-
let i = self.spec.len;
792+
if self.index < self.len {
793+
self.len -= 1;
794+
let i = self.len;
819795
unsafe {
820796
Some((self.a.get_unchecked(i), self.b.get_unchecked(i)))
821797
}

Diff for: src/test/run-pass/variance-iterators-in-libcore.rs

+17
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)