Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit bed379a

Browse files
committedApr 2, 2021
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

Lines changed: 0 additions & 47 deletions
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

Lines changed: 71 additions & 6 deletions
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

Lines changed: 71 additions & 7 deletions
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

Lines changed: 0 additions & 17 deletions
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

Lines changed: 0 additions & 26 deletions
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-
}

‎library/core/tests/iter/adapters/zip.rs

Lines changed: 0 additions & 195 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use super::*;
21
use core::iter::*;
32

43
#[test]
@@ -18,200 +17,6 @@ fn test_zip_nth() {
1817
assert_eq!(it.nth(3), None);
1918
}
2019

21-
#[test]
22-
fn test_zip_nth_side_effects() {
23-
let mut a = Vec::new();
24-
let mut b = Vec::new();
25-
let value = [1, 2, 3, 4, 5, 6]
26-
.iter()
27-
.cloned()
28-
.map(|n| {
29-
a.push(n);
30-
n * 10
31-
})
32-
.zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| {
33-
b.push(n * 100);
34-
n * 1000
35-
}))
36-
.skip(1)
37-
.nth(3);
38-
assert_eq!(value, Some((50, 6000)));
39-
assert_eq!(a, vec![1, 2, 3, 4, 5]);
40-
assert_eq!(b, vec![200, 300, 400, 500, 600]);
41-
}
42-
43-
#[test]
44-
fn test_zip_next_back_side_effects() {
45-
let mut a = Vec::new();
46-
let mut b = Vec::new();
47-
let mut iter = [1, 2, 3, 4, 5, 6]
48-
.iter()
49-
.cloned()
50-
.map(|n| {
51-
a.push(n);
52-
n * 10
53-
})
54-
.zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| {
55-
b.push(n * 100);
56-
n * 1000
57-
}));
58-
59-
// The second iterator is one item longer, so `next_back` is called on it
60-
// one more time.
61-
assert_eq!(iter.next_back(), Some((60, 7000)));
62-
assert_eq!(iter.next_back(), Some((50, 6000)));
63-
assert_eq!(iter.next_back(), Some((40, 5000)));
64-
assert_eq!(iter.next_back(), Some((30, 4000)));
65-
assert_eq!(a, vec![6, 5, 4, 3]);
66-
assert_eq!(b, vec![800, 700, 600, 500, 400]);
67-
}
68-
69-
#[test]
70-
fn test_zip_nth_back_side_effects() {
71-
let mut a = Vec::new();
72-
let mut b = Vec::new();
73-
let value = [1, 2, 3, 4, 5, 6]
74-
.iter()
75-
.cloned()
76-
.map(|n| {
77-
a.push(n);
78-
n * 10
79-
})
80-
.zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| {
81-
b.push(n * 100);
82-
n * 1000
83-
}))
84-
.nth_back(3);
85-
assert_eq!(value, Some((30, 4000)));
86-
assert_eq!(a, vec![6, 5, 4, 3]);
87-
assert_eq!(b, vec![800, 700, 600, 500, 400]);
88-
}
89-
90-
#[test]
91-
fn test_zip_next_back_side_effects_exhausted() {
92-
let mut a = Vec::new();
93-
let mut b = Vec::new();
94-
let mut iter = [1, 2, 3, 4, 5, 6]
95-
.iter()
96-
.cloned()
97-
.map(|n| {
98-
a.push(n);
99-
n * 10
100-
})
101-
.zip([2, 3, 4].iter().cloned().map(|n| {
102-
b.push(n * 100);
103-
n * 1000
104-
}));
105-
106-
iter.next();
107-
iter.next();
108-
iter.next();
109-
iter.next();
110-
assert_eq!(iter.next_back(), None);
111-
assert_eq!(a, vec![1, 2, 3, 4, 6, 5]);
112-
assert_eq!(b, vec![200, 300, 400]);
113-
}
114-
115-
#[test]
116-
fn test_zip_cloned_sideffectful() {
117-
let xs = [CountClone::new(), CountClone::new(), CountClone::new(), CountClone::new()];
118-
let ys = [CountClone::new(), CountClone::new()];
119-
120-
for _ in xs.iter().cloned().zip(ys.iter().cloned()) {}
121-
122-
assert_eq!(&xs, &[1, 1, 1, 0][..]);
123-
assert_eq!(&ys, &[1, 1][..]);
124-
125-
let xs = [CountClone::new(), CountClone::new()];
126-
let ys = [CountClone::new(), CountClone::new(), CountClone::new(), CountClone::new()];
127-
128-
for _ in xs.iter().cloned().zip(ys.iter().cloned()) {}
129-
130-
assert_eq!(&xs, &[1, 1][..]);
131-
assert_eq!(&ys, &[1, 1, 0, 0][..]);
132-
}
133-
134-
#[test]
135-
fn test_zip_map_sideffectful() {
136-
let mut xs = [0; 6];
137-
let mut ys = [0; 4];
138-
139-
for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {}
140-
141-
assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]);
142-
assert_eq!(&ys, &[1, 1, 1, 1]);
143-
144-
let mut xs = [0; 4];
145-
let mut ys = [0; 6];
146-
147-
for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {}
148-
149-
assert_eq!(&xs, &[1, 1, 1, 1]);
150-
assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]);
151-
}
152-
153-
#[test]
154-
fn test_zip_map_rev_sideffectful() {
155-
let mut xs = [0; 6];
156-
let mut ys = [0; 4];
157-
158-
{
159-
let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1));
160-
it.next_back();
161-
}
162-
assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]);
163-
assert_eq!(&ys, &[0, 0, 0, 1]);
164-
165-
let mut xs = [0; 6];
166-
let mut ys = [0; 4];
167-
168-
{
169-
let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1));
170-
(&mut it).take(5).count();
171-
it.next_back();
172-
}
173-
assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]);
174-
assert_eq!(&ys, &[1, 1, 1, 1]);
175-
}
176-
177-
#[test]
178-
fn test_zip_nested_sideffectful() {
179-
let mut xs = [0; 6];
180-
let ys = [0; 4];
181-
182-
{
183-
// test that it has the side effect nested inside enumerate
184-
let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys);
185-
it.count();
186-
}
187-
assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]);
188-
}
189-
190-
#[test]
191-
fn test_zip_nth_back_side_effects_exhausted() {
192-
let mut a = Vec::new();
193-
let mut b = Vec::new();
194-
let mut iter = [1, 2, 3, 4, 5, 6]
195-
.iter()
196-
.cloned()
197-
.map(|n| {
198-
a.push(n);
199-
n * 10
200-
})
201-
.zip([2, 3, 4].iter().cloned().map(|n| {
202-
b.push(n * 100);
203-
n * 1000
204-
}));
205-
206-
iter.next();
207-
iter.next();
208-
iter.next();
209-
iter.next();
210-
assert_eq!(iter.nth_back(0), None);
211-
assert_eq!(a, vec![1, 2, 3, 4, 6, 5]);
212-
assert_eq!(b, vec![200, 300, 400]);
213-
}
214-
21520
#[test]
21621
fn test_zip_trusted_random_access_composition() {
21722
let a = [0, 1, 2, 3, 4];

‎src/test/ui/issues/issue-3044.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ LL | | });
1111
note: associated function defined here
1212
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
1313
|
14-
LL | fn fold<B, F>(mut self, init: B, mut f: F) -> B
14+
LL | fn fold<B, F>(self, init: B, f: F) -> B
1515
| ^^^^
1616

1717
error: aborting due to previous error

0 commit comments

Comments
 (0)
Please sign in to comment.