Skip to content

Commit bed379a

Browse files
committed
break as many Zip side-effects as we can
1 parent 138fd56 commit bed379a

File tree

7 files changed

+143
-299
lines changed

7 files changed

+143
-299
lines changed

library/core/src/iter/adapters/zip.rs

-47
Original file line numberDiff line numberDiff line change
@@ -231,16 +231,6 @@ where
231231
unsafe {
232232
Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
233233
}
234-
} else if A::MAY_HAVE_SIDE_EFFECT && self.index < self.a_len {
235-
let i = self.index;
236-
self.index += 1;
237-
self.len += 1;
238-
// match the base implementation's potential side effects
239-
// SAFETY: we just checked that `i` < `self.a.len()`
240-
unsafe {
241-
self.a.__iterator_get_unchecked(i);
242-
}
243-
None
244234
} else {
245235
None
246236
}
@@ -257,22 +247,7 @@ where
257247
let delta = cmp::min(n, self.len - self.index);
258248
let end = self.index + delta;
259249
while self.index < end {
260-
let i = self.index;
261250
self.index += 1;
262-
if A::MAY_HAVE_SIDE_EFFECT {
263-
// SAFETY: the usage of `cmp::min` to calculate `delta`
264-
// ensures that `end` is smaller than or equal to `self.len`,
265-
// so `i` is also smaller than `self.len`.
266-
unsafe {
267-
self.a.__iterator_get_unchecked(i);
268-
}
269-
}
270-
if B::MAY_HAVE_SIDE_EFFECT {
271-
// SAFETY: same as above.
272-
unsafe {
273-
self.b.__iterator_get_unchecked(i);
274-
}
275-
}
276251
}
277252

278253
self.super_nth(n - delta)
@@ -284,28 +259,6 @@ where
284259
A: DoubleEndedIterator + ExactSizeIterator,
285260
B: DoubleEndedIterator + ExactSizeIterator,
286261
{
287-
if A::MAY_HAVE_SIDE_EFFECT || B::MAY_HAVE_SIDE_EFFECT {
288-
let sz_a = self.a.size();
289-
let sz_b = self.b.size();
290-
// Adjust a, b to equal length, make sure that only the first call
291-
// of `next_back` does this, otherwise we will break the restriction
292-
// on calls to `self.next_back()` after calling `get_unchecked()`.
293-
if sz_a != sz_b {
294-
let sz_a = self.a.size();
295-
if A::MAY_HAVE_SIDE_EFFECT && sz_a > self.len {
296-
for _ in 0..sz_a - self.len {
297-
self.a.next_back();
298-
}
299-
self.a_len = self.len;
300-
}
301-
let sz_b = self.b.size();
302-
if B::MAY_HAVE_SIDE_EFFECT && sz_b > self.len {
303-
for _ in 0..sz_b - self.len {
304-
self.b.next_back();
305-
}
306-
}
307-
}
308-
}
309262
if self.index < self.len {
310263
self.len -= 1;
311264
self.a_len -= 1;

library/core/src/iter/traits/double_ended.rs

+71-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::super::{TrustedLen, TrustedRandomAccess};
12
use crate::ops::{ControlFlow, Try};
23

34
/// An iterator able to yield elements from both ends.
@@ -278,16 +279,12 @@ pub trait DoubleEndedIterator: Iterator {
278279
/// ```
279280
#[inline]
280281
#[stable(feature = "iter_rfold", since = "1.27.0")]
281-
fn rfold<B, F>(mut self, init: B, mut f: F) -> B
282+
fn rfold<B, F>(self, init: B, f: F) -> B
282283
where
283284
Self: Sized,
284285
F: FnMut(B, Self::Item) -> B,
285286
{
286-
let mut accum = init;
287-
while let Some(x) = self.next_back() {
288-
accum = f(accum, x);
289-
}
290-
accum
287+
self.rfold_spec(init, f)
291288
}
292289

293290
/// Searches for an element of an iterator from the back that satisfies a predicate.
@@ -361,3 +358,71 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
361358
(**self).nth_back(n)
362359
}
363360
}
361+
362+
trait SpecIteratorDefaultImpls: DoubleEndedIterator {
363+
fn rfold_spec<B, F>(self, init: B, f: F) -> B
364+
where
365+
Self: Sized,
366+
F: FnMut(B, Self::Item) -> B;
367+
}
368+
369+
impl<T> SpecIteratorDefaultImpls for T
370+
where
371+
T: DoubleEndedIterator,
372+
{
373+
#[inline]
374+
default fn rfold_spec<B, F>(mut self, init: B, mut f: F) -> B
375+
where
376+
Self: Sized,
377+
F: FnMut(B, Self::Item) -> B,
378+
{
379+
let mut accum = init;
380+
while let Some(x) = self.next_back() {
381+
accum = f(accum, x);
382+
}
383+
accum
384+
}
385+
}
386+
387+
impl<T> SpecIteratorDefaultImpls for T
388+
where
389+
T: DoubleEndedIterator + Sized + TrustedLen,
390+
{
391+
#[inline]
392+
default fn rfold_spec<B, F>(mut self, init: B, mut f: F) -> B
393+
where
394+
Self: Sized,
395+
F: FnMut(B, Self::Item) -> B,
396+
{
397+
let mut accum = init;
398+
while self.size_hint().1.is_none() {
399+
accum = f(accum, self.next_back().unwrap())
400+
}
401+
for _ in 0..self.size_hint().1.unwrap() {
402+
accum = f(accum, self.next_back().unwrap());
403+
}
404+
accum
405+
}
406+
}
407+
408+
impl<T> SpecIteratorDefaultImpls for T
409+
where
410+
T: DoubleEndedIterator + Sized + TrustedLen + TrustedRandomAccess,
411+
{
412+
#[inline]
413+
fn rfold_spec<B, F>(mut self, init: B, mut f: F) -> B
414+
where
415+
Self: Sized,
416+
F: FnMut(B, Self::Item) -> B,
417+
{
418+
let mut accum = init;
419+
// SAFETY: every element is only read once, as required by the
420+
// TrustedRandomAccess contract
421+
unsafe {
422+
for i in (0..self.size()).rev() {
423+
accum = f(accum, self.__iterator_get_unchecked(i))
424+
}
425+
}
426+
accum
427+
}
428+
}

library/core/src/iter/traits/iterator.rs

+71-7
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
use crate::cmp::{self, Ordering};
66
use crate::ops::{ControlFlow, Try};
77

8-
use super::super::TrustedRandomAccess;
98
use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
109
use super::super::{FlatMap, Flatten};
1110
use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip};
1211
use super::super::{
1312
Inspect, Map, MapWhile, Peekable, Rev, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile,
1413
};
14+
use super::super::{TrustedLen, TrustedRandomAccess};
1515

1616
fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
1717

@@ -2125,16 +2125,12 @@ pub trait Iterator {
21252125
#[doc(alias = "inject")]
21262126
#[inline]
21272127
#[stable(feature = "rust1", since = "1.0.0")]
2128-
fn fold<B, F>(mut self, init: B, mut f: F) -> B
2128+
fn fold<B, F>(self, init: B, f: F) -> B
21292129
where
21302130
Self: Sized,
21312131
F: FnMut(B, Self::Item) -> B,
21322132
{
2133-
let mut accum = init;
2134-
while let Some(x) = self.next() {
2135-
accum = f(accum, x);
2136-
}
2137-
accum
2133+
self.fold_spec(init, f)
21382134
}
21392135

21402136
/// Reduces the elements to a single one, by repeatedly applying a reducing
@@ -3420,3 +3416,71 @@ impl<I: Iterator + ?Sized> Iterator for &mut I {
34203416
(**self).nth(n)
34213417
}
34223418
}
3419+
3420+
trait SpecIteratorDefaultImpls: Iterator {
3421+
fn fold_spec<B, F>(self, init: B, f: F) -> B
3422+
where
3423+
Self: Sized,
3424+
F: FnMut(B, Self::Item) -> B;
3425+
}
3426+
3427+
impl<T> SpecIteratorDefaultImpls for T
3428+
where
3429+
T: Iterator,
3430+
{
3431+
#[inline]
3432+
default fn fold_spec<B, F>(mut self, init: B, mut f: F) -> B
3433+
where
3434+
Self: Sized,
3435+
F: FnMut(B, Self::Item) -> B,
3436+
{
3437+
let mut accum = init;
3438+
while let Some(x) = self.next() {
3439+
accum = f(accum, x);
3440+
}
3441+
accum
3442+
}
3443+
}
3444+
3445+
impl<T> SpecIteratorDefaultImpls for T
3446+
where
3447+
T: Iterator + Sized + TrustedLen,
3448+
{
3449+
#[inline]
3450+
default fn fold_spec<B, F>(mut self, init: B, mut f: F) -> B
3451+
where
3452+
Self: Sized,
3453+
F: FnMut(B, Self::Item) -> B,
3454+
{
3455+
let mut accum = init;
3456+
while self.size_hint().1.is_none() {
3457+
accum = f(accum, self.next().unwrap());
3458+
}
3459+
for _ in 0..self.size_hint().1.unwrap() {
3460+
accum = f(accum, self.next().unwrap())
3461+
}
3462+
accum
3463+
}
3464+
}
3465+
3466+
impl<T> SpecIteratorDefaultImpls for T
3467+
where
3468+
T: Iterator + Sized + TrustedLen + TrustedRandomAccess,
3469+
{
3470+
#[inline]
3471+
fn fold_spec<B, F>(mut self, init: B, mut f: F) -> B
3472+
where
3473+
Self: Sized,
3474+
F: FnMut(B, Self::Item) -> B,
3475+
{
3476+
let mut accum = init;
3477+
// SAFETY: every element is only read once, as required by the
3478+
// TrustedRandomAccess contract
3479+
unsafe {
3480+
for i in 0..self.size() {
3481+
accum = f(accum, self.__iterator_get_unchecked(i))
3482+
}
3483+
}
3484+
accum
3485+
}
3486+
}

library/core/tests/iter/adapters/cloned.rs

-17
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,6 @@ fn test_cloned() {
1717
assert_eq!(it.next_back(), None);
1818
}
1919

20-
#[test]
21-
fn test_cloned_side_effects() {
22-
let mut count = 0;
23-
{
24-
let iter = [1, 2, 3]
25-
.iter()
26-
.map(|x| {
27-
count += 1;
28-
x
29-
})
30-
.cloned()
31-
.zip(&[1]);
32-
for _ in iter {}
33-
}
34-
assert_eq!(count, 2);
35-
}
36-
3720
#[test]
3821
fn test_cloned_try_folds() {
3922
let a = [1, 2, 3, 4, 5, 6, 7, 8, 9];

library/core/tests/iter/adapters/mod.rs

-26
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ mod take;
2020
mod take_while;
2121
mod zip;
2222

23-
use core::cell::Cell;
24-
2523
/// An iterator that panics whenever `next` or next_back` is called
2624
/// after `None` has already been returned. This does not violate
2725
/// `Iterator`'s contract. Used to test that iterator adaptors don't
@@ -159,27 +157,3 @@ impl<'a, T> Iterator for CycleIter<'a, T> {
159157
elt
160158
}
161159
}
162-
163-
#[derive(Debug)]
164-
struct CountClone(Cell<i32>);
165-
166-
impl CountClone {
167-
pub fn new() -> Self {
168-
Self(Cell::new(0))
169-
}
170-
}
171-
172-
impl PartialEq<i32> for CountClone {
173-
fn eq(&self, rhs: &i32) -> bool {
174-
self.0.get() == *rhs
175-
}
176-
}
177-
178-
impl Clone for CountClone {
179-
fn clone(&self) -> Self {
180-
let ret = CountClone(self.0.clone());
181-
let n = self.0.get();
182-
self.0.set(n + 1);
183-
ret
184-
}
185-
}

0 commit comments

Comments
 (0)