]> git.proxmox.com Git - rustc.git/blobdiff - library/core/src/iter/adapters/zip.rs
Merge tag 'debian/1.52.1+dfsg1-1_exp2' into proxmox/buster
[rustc.git] / library / core / src / iter / adapters / zip.rs
index 98b8dca961407e9c3f0ab8d980e74155c91aa5bd..ea7a809c6badb61f34f55ee3bd82ab25a2bf2fb9 100644 (file)
@@ -13,9 +13,10 @@ use crate::iter::{InPlaceIterable, SourceIter, TrustedLen};
 pub struct Zip<A, B> {
     a: A,
     b: B,
-    // index and len are only used by the specialized version of zip
+    // index, len and a_len are only used by the specialized version of zip
     index: usize,
     len: usize,
+    a_len: usize,
 }
 impl<A: Iterator, B: Iterator> Zip<A, B> {
     pub(in crate::iter) fn new(a: A, b: B) -> Zip<A, B> {
@@ -110,6 +111,7 @@ where
             b,
             index: 0, // unused
             len: 0,   // unused
+            a_len: 0, // unused
         }
     }
 
@@ -184,8 +186,9 @@ where
     B: TrustedRandomAccess + Iterator,
 {
     fn new(a: A, b: B) -> Self {
-        let len = cmp::min(a.size(), b.size());
-        Zip { a, b, index: 0, len }
+        let a_len = a.size();
+        let len = cmp::min(a_len, b.size());
+        Zip { a, b, index: 0, len, a_len }
     }
 
     #[inline]
@@ -197,13 +200,15 @@ where
             unsafe {
                 Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
             }
-        } else if A::may_have_side_effect() && self.index < self.a.size() {
+        } else if A::MAY_HAVE_SIDE_EFFECT && self.index < self.a_len {
+            let i = self.index;
+            self.index += 1;
+            self.len += 1;
             // match the base implementation's potential side effects
-            // SAFETY: we just checked that `self.index` < `self.a.len()`
+            // SAFETY: we just checked that `i` < `self.a.len()`
             unsafe {
-                self.a.__iterator_get_unchecked(self.index);
+                self.a.__iterator_get_unchecked(i);
             }
-            self.index += 1;
             None
         } else {
             None
@@ -223,7 +228,7 @@ where
         while self.index < end {
             let i = self.index;
             self.index += 1;
-            if A::may_have_side_effect() {
+            if A::MAY_HAVE_SIDE_EFFECT {
                 // SAFETY: the usage of `cmp::min` to calculate `delta`
                 // ensures that `end` is smaller than or equal to `self.len`,
                 // so `i` is also smaller than `self.len`.
@@ -231,7 +236,7 @@ where
                     self.a.__iterator_get_unchecked(i);
                 }
             }
-            if B::may_have_side_effect() {
+            if B::MAY_HAVE_SIDE_EFFECT {
                 // SAFETY: same as above.
                 unsafe {
                     self.b.__iterator_get_unchecked(i);
@@ -248,9 +253,7 @@ where
         A: DoubleEndedIterator + ExactSizeIterator,
         B: DoubleEndedIterator + ExactSizeIterator,
     {
-        let a_side_effect = A::may_have_side_effect();
-        let b_side_effect = B::may_have_side_effect();
-        if a_side_effect || b_side_effect {
+        if A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT {
             let sz_a = self.a.size();
             let sz_b = self.b.size();
             // Adjust a, b to equal length, make sure that only the first call
@@ -258,13 +261,14 @@ where
             // on calls to `self.next_back()` after calling `get_unchecked()`.
             if sz_a != sz_b {
                 let sz_a = self.a.size();
-                if a_side_effect && sz_a > self.len {
-                    for _ in 0..sz_a - cmp::max(self.len, self.index) {
+                if A::MAY_HAVE_SIDE_EFFECT && sz_a > self.len {
+                    for _ in 0..sz_a - self.len {
                         self.a.next_back();
                     }
+                    self.a_len = self.len;
                 }
                 let sz_b = self.b.size();
-                if b_side_effect && sz_b > self.len {
+                if B::MAY_HAVE_SIDE_EFFECT && sz_b > self.len {
                     for _ in 0..sz_b - self.len {
                         self.b.next_back();
                     }
@@ -273,6 +277,7 @@ where
         }
         if self.index < self.len {
             self.len -= 1;
+            self.a_len -= 1;
             let i = self.len;
             // SAFETY: `i` is smaller than the previous value of `self.len`,
             // which is also smaller than or equal to `self.a.len()` and `self.b.len()`
@@ -308,9 +313,7 @@ where
     A: TrustedRandomAccess,
     B: TrustedRandomAccess,
 {
-    fn may_have_side_effect() -> bool {
-        A::may_have_side_effect() || B::may_have_side_effect()
-    }
+    const MAY_HAVE_SIDE_EFFECT: bool = A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT;
 }
 
 #[stable(feature = "fused", since = "1.26.0")]
@@ -421,9 +424,9 @@ pub unsafe trait TrustedRandomAccess: Sized {
     {
         self.size_hint().0
     }
-    /// Returns `true` if getting an iterator element may have
-    /// side effects. Remember to take inner iterators into account.
-    fn may_have_side_effect() -> bool;
+    /// `true` if getting an iterator element may have side effects.
+    /// Remember to take inner iterators into account.
+    const MAY_HAVE_SIDE_EFFECT: bool;
 }
 
 /// Like `Iterator::__iterator_get_unchecked`, but doesn't require the compiler to