Skip to content

Commit 09ee9b7

Browse files
committedSep 29, 2017
Auto merge of #44856 - cuviper:more-fold, r=dtolnay
Add more custom folding to `core::iter` adaptors Many of the iterator adaptors will perform faster folds if they forward to their inner iterator's folds, especially for inner types like `Chain` which are optimized too. The following types are newly specialized: | Type | `fold` | `rfold` | | ----------- | ------ | ------- | | `Enumerate` | ✓ | ✓ | | `Filter` | ✓ | ✓ | | `FilterMap` | ✓ | ✓ | | `FlatMap` | exists | ✓ | | `Fuse` | ✓ | ✓ | | `Inspect` | ✓ | ✓ | | `Peekable` | ✓ | N/A¹ | | `Skip` | ✓ | N/A² | | `SkipWhile` | ✓ | N/A¹ | ¹ not a `DoubleEndedIterator` ² `Skip::next_back` doesn't pull skipped items at all, but this couldn't be avoided if `Skip::rfold` were to call its inner iterator's `rfold`. Benchmarks ---------- In the following results, plain `_sum` computes the sum of a million integers -- note that `sum()` is implemented with `fold()`. The `_ref_sum` variants do the same on a `by_ref()` iterator, which is limited to calling `next()` one by one, without specialized `fold`. The `chain` variants perform the same tests on two iterators chained together, to show a greater benefit of forwarding `fold` internally. test iter::bench_enumerate_chain_ref_sum ... bench: 2,216,264 ns/iter (+/- 29,228) test iter::bench_enumerate_chain_sum ... bench: 922,380 ns/iter (+/- 2,676) test iter::bench_enumerate_ref_sum ... bench: 476,094 ns/iter (+/- 7,110) test iter::bench_enumerate_sum ... bench: 476,438 ns/iter (+/- 3,334) test iter::bench_filter_chain_ref_sum ... bench: 2,266,095 ns/iter (+/- 6,051) test iter::bench_filter_chain_sum ... bench: 745,594 ns/iter (+/- 2,013) test iter::bench_filter_ref_sum ... bench: 889,696 ns/iter (+/- 1,188) test iter::bench_filter_sum ... bench: 667,325 ns/iter (+/- 1,894) test iter::bench_filter_map_chain_ref_sum ... bench: 2,259,195 ns/iter (+/- 353,440) test iter::bench_filter_map_chain_sum ... bench: 1,223,280 ns/iter (+/- 1,972) test iter::bench_filter_map_ref_sum ... bench: 611,607 ns/iter (+/- 2,507) test iter::bench_filter_map_sum ... bench: 611,610 ns/iter (+/- 472) test iter::bench_fuse_chain_ref_sum ... bench: 2,246,106 ns/iter (+/- 22,395) test iter::bench_fuse_chain_sum ... bench: 634,887 ns/iter (+/- 1,341) test iter::bench_fuse_ref_sum ... bench: 444,816 ns/iter (+/- 1,748) test iter::bench_fuse_sum ... bench: 316,954 ns/iter (+/- 2,616) test iter::bench_inspect_chain_ref_sum ... bench: 2,245,431 ns/iter (+/- 21,371) test iter::bench_inspect_chain_sum ... bench: 631,645 ns/iter (+/- 4,928) test iter::bench_inspect_ref_sum ... bench: 317,437 ns/iter (+/- 702) test iter::bench_inspect_sum ... bench: 315,942 ns/iter (+/- 4,320) test iter::bench_peekable_chain_ref_sum ... bench: 2,243,585 ns/iter (+/- 12,186) test iter::bench_peekable_chain_sum ... bench: 634,848 ns/iter (+/- 1,712) test iter::bench_peekable_ref_sum ... bench: 444,808 ns/iter (+/- 480) test iter::bench_peekable_sum ... bench: 317,133 ns/iter (+/- 3,309) test iter::bench_skip_chain_ref_sum ... bench: 1,778,734 ns/iter (+/- 2,198) test iter::bench_skip_chain_sum ... bench: 761,850 ns/iter (+/- 1,645) test iter::bench_skip_ref_sum ... bench: 478,207 ns/iter (+/- 119,252) test iter::bench_skip_sum ... bench: 315,614 ns/iter (+/- 3,054) test iter::bench_skip_while_chain_ref_sum ... bench: 2,486,370 ns/iter (+/- 4,845) test iter::bench_skip_while_chain_sum ... bench: 633,915 ns/iter (+/- 5,892) test iter::bench_skip_while_ref_sum ... bench: 666,926 ns/iter (+/- 804) test iter::bench_skip_while_sum ... bench: 444,405 ns/iter (+/- 571)
·
1.90.01.22.0
2 parents d514263 + 13724fa commit 09ee9b7

File tree

4 files changed

+471
-33
lines changed

4 files changed

+471
-33
lines changed
 

‎src/libcore/benches/iter.rs‎

Lines changed: 121 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -147,40 +147,131 @@ fn bench_for_each_chain_ref_fold(b: &mut Bencher) {
147147
});
148148
}
149149

150-
#[bench]
151-
fn bench_flat_map_sum(b: &mut Bencher) {
152-
b.iter(|| -> i64 {
153-
(0i64..1000).flat_map(|x| x..x+1000)
154-
.map(black_box)
155-
.sum()
156-
});
150+
151+
/// Helper to benchmark `sum` for iterators taken by value which
152+
/// can optimize `fold`, and by reference which cannot.
153+
macro_rules! bench_sums {
154+
($bench_sum:ident, $bench_ref_sum:ident, $iter:expr) => {
155+
#[bench]
156+
fn $bench_sum(b: &mut Bencher) {
157+
b.iter(|| -> i64 {
158+
$iter.map(black_box).sum()
159+
});
160+
}
161+
162+
#[bench]
163+
fn $bench_ref_sum(b: &mut Bencher) {
164+
b.iter(|| -> i64 {
165+
$iter.map(black_box).by_ref().sum()
166+
});
167+
}
168+
}
157169
}
158170

159-
#[bench]
160-
fn bench_flat_map_ref_sum(b: &mut Bencher) {
161-
b.iter(|| -> i64 {
162-
(0i64..1000).flat_map(|x| x..x+1000)
163-
.map(black_box)
164-
.by_ref()
165-
.sum()
166-
});
171+
bench_sums! {
172+
bench_flat_map_sum,
173+
bench_flat_map_ref_sum,
174+
(0i64..1000).flat_map(|x| x..x+1000)
167175
}
168176

169-
#[bench]
170-
fn bench_flat_map_chain_sum(b: &mut Bencher) {
171-
b.iter(|| -> i64 {
172-
(0i64..1000000).flat_map(|x| once(x).chain(once(x)))
173-
.map(black_box)
174-
.sum()
175-
});
177+
bench_sums! {
178+
bench_flat_map_chain_sum,
179+
bench_flat_map_chain_ref_sum,
180+
(0i64..1000000).flat_map(|x| once(x).chain(once(x)))
176181
}
177182

178-
#[bench]
179-
fn bench_flat_map_chain_ref_sum(b: &mut Bencher) {
180-
b.iter(|| -> i64 {
181-
(0i64..1000000).flat_map(|x| once(x).chain(once(x)))
182-
.map(black_box)
183-
.by_ref()
184-
.sum()
185-
});
183+
bench_sums! {
184+
bench_enumerate_sum,
185+
bench_enumerate_ref_sum,
186+
(0i64..1000000).enumerate().map(|(i, x)| x * i as i64)
187+
}
188+
189+
bench_sums! {
190+
bench_enumerate_chain_sum,
191+
bench_enumerate_chain_ref_sum,
192+
(0i64..1000000).chain(0..1000000).enumerate().map(|(i, x)| x * i as i64)
193+
}
194+
195+
bench_sums! {
196+
bench_filter_sum,
197+
bench_filter_ref_sum,
198+
(0i64..1000000).filter(|x| x % 2 == 0)
199+
}
200+
201+
bench_sums! {
202+
bench_filter_chain_sum,
203+
bench_filter_chain_ref_sum,
204+
(0i64..1000000).chain(0..1000000).filter(|x| x % 2 == 0)
205+
}
206+
207+
bench_sums! {
208+
bench_filter_map_sum,
209+
bench_filter_map_ref_sum,
210+
(0i64..1000000).filter_map(|x| x.checked_mul(x))
211+
}
212+
213+
bench_sums! {
214+
bench_filter_map_chain_sum,
215+
bench_filter_map_chain_ref_sum,
216+
(0i64..1000000).chain(0..1000000).filter_map(|x| x.checked_mul(x))
217+
}
218+
219+
bench_sums! {
220+
bench_fuse_sum,
221+
bench_fuse_ref_sum,
222+
(0i64..1000000).fuse()
223+
}
224+
225+
bench_sums! {
226+
bench_fuse_chain_sum,
227+
bench_fuse_chain_ref_sum,
228+
(0i64..1000000).chain(0..1000000).fuse()
229+
}
230+
231+
bench_sums! {
232+
bench_inspect_sum,
233+
bench_inspect_ref_sum,
234+
(0i64..1000000).inspect(|_| {})
235+
}
236+
237+
bench_sums! {
238+
bench_inspect_chain_sum,
239+
bench_inspect_chain_ref_sum,
240+
(0i64..1000000).chain(0..1000000).inspect(|_| {})
241+
}
242+
243+
bench_sums! {
244+
bench_peekable_sum,
245+
bench_peekable_ref_sum,
246+
(0i64..1000000).peekable()
247+
}
248+
249+
bench_sums! {
250+
bench_peekable_chain_sum,
251+
bench_peekable_chain_ref_sum,
252+
(0i64..1000000).chain(0..1000000).peekable()
253+
}
254+
255+
bench_sums! {
256+
bench_skip_sum,
257+
bench_skip_ref_sum,
258+
(0i64..1000000).skip(1000)
259+
}
260+
261+
bench_sums! {
262+
bench_skip_chain_sum,
263+
bench_skip_chain_ref_sum,
264+
(0i64..1000000).chain(0..1000000).skip(1000)
265+
}
266+
267+
bench_sums! {
268+
bench_skip_while_sum,
269+
bench_skip_while_ref_sum,
270+
(0i64..1000000).skip_while(|&x| x < 1000)
271+
}
272+
273+
bench_sums! {
274+
bench_skip_while_chain_sum,
275+
bench_skip_while_chain_ref_sum,
276+
(0i64..1000000).chain(0..1000000).skip_while(|&x| x < 1000)
186277
}

‎src/libcore/iter/mod.rs‎

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,18 @@ impl<I: Iterator, P> Iterator for Filter<I, P> where P: FnMut(&I::Item) -> bool
12501250
}
12511251
count
12521252
}
1253+
1254+
#[inline]
1255+
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
1256+
where Fold: FnMut(Acc, Self::Item) -> Acc,
1257+
{
1258+
let mut predicate = self.predicate;
1259+
self.iter.fold(init, move |acc, item| if predicate(&item) {
1260+
fold(acc, item)
1261+
} else {
1262+
acc
1263+
})
1264+
}
12531265
}
12541266

12551267
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1265,6 +1277,18 @@ impl<I: DoubleEndedIterator, P> DoubleEndedIterator for Filter<I, P>
12651277
}
12661278
None
12671279
}
1280+
1281+
#[inline]
1282+
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
1283+
where Fold: FnMut(Acc, Self::Item) -> Acc,
1284+
{
1285+
let mut predicate = self.predicate;
1286+
self.iter.rfold(init, move |acc, item| if predicate(&item) {
1287+
fold(acc, item)
1288+
} else {
1289+
acc
1290+
})
1291+
}
12681292
}
12691293

12701294
#[unstable(feature = "fused", issue = "35602")]
@@ -1316,6 +1340,17 @@ impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
13161340
let (_, upper) = self.iter.size_hint();
13171341
(0, upper) // can't know a lower bound, due to the predicate
13181342
}
1343+
1344+
#[inline]
1345+
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
1346+
where Fold: FnMut(Acc, Self::Item) -> Acc,
1347+
{
1348+
let mut f = self.f;
1349+
self.iter.fold(init, move |acc, item| match f(item) {
1350+
Some(x) => fold(acc, x),
1351+
None => acc,
1352+
})
1353+
}
13191354
}
13201355

13211356
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1331,6 +1366,17 @@ impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for FilterMap<I, F>
13311366
}
13321367
None
13331368
}
1369+
1370+
#[inline]
1371+
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
1372+
where Fold: FnMut(Acc, Self::Item) -> Acc,
1373+
{
1374+
let mut f = self.f;
1375+
self.iter.rfold(init, move |acc, item| match f(item) {
1376+
Some(x) => fold(acc, x),
1377+
None => acc,
1378+
})
1379+
}
13341380
}
13351381

13361382
#[unstable(feature = "fused", issue = "35602")]
@@ -1395,6 +1441,19 @@ impl<I> Iterator for Enumerate<I> where I: Iterator {
13951441
fn count(self) -> usize {
13961442
self.iter.count()
13971443
}
1444+
1445+
#[inline]
1446+
#[rustc_inherit_overflow_checks]
1447+
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
1448+
where Fold: FnMut(Acc, Self::Item) -> Acc,
1449+
{
1450+
let mut count = self.count;
1451+
self.iter.fold(init, move |acc, item| {
1452+
let acc = fold(acc, (count, item));
1453+
count += 1;
1454+
acc
1455+
})
1456+
}
13981457
}
13991458

14001459
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1410,6 +1469,19 @@ impl<I> DoubleEndedIterator for Enumerate<I> where
14101469
(self.count + len, a)
14111470
})
14121471
}
1472+
1473+
#[inline]
1474+
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
1475+
where Fold: FnMut(Acc, Self::Item) -> Acc,
1476+
{
1477+
// Can safely add and subtract the count, as `ExactSizeIterator` promises
1478+
// that the number of elements fits into a `usize`.
1479+
let mut count = self.count + self.iter.len();
1480+
self.iter.rfold(init, move |acc, item| {
1481+
count -= 1;
1482+
fold(acc, (count, item))
1483+
})
1484+
}
14131485
}
14141486

14151487
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1521,6 +1593,18 @@ impl<I: Iterator> Iterator for Peekable<I> {
15211593
let hi = hi.and_then(|x| x.checked_add(peek_len));
15221594
(lo, hi)
15231595
}
1596+
1597+
#[inline]
1598+
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
1599+
where Fold: FnMut(Acc, Self::Item) -> Acc,
1600+
{
1601+
let acc = match self.peeked {
1602+
Some(None) => return init,
1603+
Some(Some(v)) => fold(init, v),
1604+
None => init,
1605+
};
1606+
self.iter.fold(acc, fold)
1607+
}
15241608
}
15251609

15261610
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1629,6 +1713,19 @@ impl<I: Iterator, P> Iterator for SkipWhile<I, P>
16291713
let (_, upper) = self.iter.size_hint();
16301714
(0, upper) // can't know a lower bound, due to the predicate
16311715
}
1716+
1717+
#[inline]
1718+
fn fold<Acc, Fold>(mut self, mut init: Acc, mut fold: Fold) -> Acc
1719+
where Fold: FnMut(Acc, Self::Item) -> Acc,
1720+
{
1721+
if !self.flag {
1722+
match self.next() {
1723+
Some(v) => init = fold(init, v),
1724+
None => return init,
1725+
}
1726+
}
1727+
self.iter.fold(init, fold)
1728+
}
16321729
}
16331730

16341731
#[unstable(feature = "fused", issue = "35602")]
@@ -1769,6 +1866,19 @@ impl<I> Iterator for Skip<I> where I: Iterator {
17691866

17701867
(lower, upper)
17711868
}
1869+
1870+
#[inline]
1871+
fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
1872+
where Fold: FnMut(Acc, Self::Item) -> Acc,
1873+
{
1874+
if self.n > 0 {
1875+
// nth(n) skips n+1
1876+
if self.iter.nth(self.n - 1).is_none() {
1877+
return init;
1878+
}
1879+
}
1880+
self.iter.fold(init, fold)
1881+
}
17721882
}
17731883

17741884
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1991,6 +2101,16 @@ impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F> wher
19912101
}
19922102
}
19932103
}
2104+
2105+
#[inline]
2106+
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
2107+
where Fold: FnMut(Acc, Self::Item) -> Acc,
2108+
{
2109+
self.frontiter.into_iter()
2110+
.chain(self.iter.map(self.f).map(U::into_iter))
2111+
.chain(self.backiter)
2112+
.rfold(init, |acc, iter| iter.rfold(acc, &mut fold))
2113+
}
19942114
}
19952115

19962116
#[unstable(feature = "fused", issue = "35602")]
@@ -2068,6 +2188,17 @@ impl<I> Iterator for Fuse<I> where I: Iterator {
20682188
self.iter.size_hint()
20692189
}
20702190
}
2191+
2192+
#[inline]
2193+
default fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
2194+
where Fold: FnMut(Acc, Self::Item) -> Acc,
2195+
{
2196+
if self.done {
2197+
init
2198+
} else {
2199+
self.iter.fold(init, fold)
2200+
}
2201+
}
20712202
}
20722203

20732204
#[stable(feature = "rust1", since = "1.0.0")]
@@ -2082,6 +2213,17 @@ impl<I> DoubleEndedIterator for Fuse<I> where I: DoubleEndedIterator {
20822213
next
20832214
}
20842215
}
2216+
2217+
#[inline]
2218+
default fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
2219+
where Fold: FnMut(Acc, Self::Item) -> Acc,
2220+
{
2221+
if self.done {
2222+
init
2223+
} else {
2224+
self.iter.rfold(init, fold)
2225+
}
2226+
}
20852227
}
20862228

20872229
unsafe impl<I> TrustedRandomAccess for Fuse<I>
@@ -2122,6 +2264,13 @@ impl<I> Iterator for Fuse<I> where I: FusedIterator {
21222264
fn size_hint(&self) -> (usize, Option<usize>) {
21232265
self.iter.size_hint()
21242266
}
2267+
2268+
#[inline]
2269+
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
2270+
where Fold: FnMut(Acc, Self::Item) -> Acc,
2271+
{
2272+
self.iter.fold(init, fold)
2273+
}
21252274
}
21262275

21272276
#[unstable(feature = "fused", reason = "recently added", issue = "35602")]
@@ -2132,6 +2281,13 @@ impl<I> DoubleEndedIterator for Fuse<I>
21322281
fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
21332282
self.iter.next_back()
21342283
}
2284+
2285+
#[inline]
2286+
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
2287+
where Fold: FnMut(Acc, Self::Item) -> Acc,
2288+
{
2289+
self.iter.rfold(init, fold)
2290+
}
21352291
}
21362292

21372293

@@ -2196,6 +2352,14 @@ impl<I: Iterator, F> Iterator for Inspect<I, F> where F: FnMut(&I::Item) {
21962352
fn size_hint(&self) -> (usize, Option<usize>) {
21972353
self.iter.size_hint()
21982354
}
2355+
2356+
#[inline]
2357+
fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
2358+
where Fold: FnMut(Acc, Self::Item) -> Acc,
2359+
{
2360+
let mut f = self.f;
2361+
self.iter.fold(init, move |acc, item| { f(&item); fold(acc, item) })
2362+
}
21992363
}
22002364

22012365
#[stable(feature = "rust1", since = "1.0.0")]
@@ -2207,6 +2371,14 @@ impl<I: DoubleEndedIterator, F> DoubleEndedIterator for Inspect<I, F>
22072371
let next = self.iter.next_back();
22082372
self.do_inspect(next)
22092373
}
2374+
2375+
#[inline]
2376+
fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
2377+
where Fold: FnMut(Acc, Self::Item) -> Acc,
2378+
{
2379+
let mut f = self.f;
2380+
self.iter.rfold(init, move |acc, item| { f(&item); fold(acc, item) })
2381+
}
22102382
}
22112383

22122384
#[stable(feature = "rust1", since = "1.0.0")]

‎src/libcore/tests/iter.rs‎

Lines changed: 177 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,25 @@ fn test_filter_map() {
248248
assert_eq!(it.collect::<Vec<usize>>(), [0*0, 2*2, 4*4, 6*6, 8*8]);
249249
}
250250

251+
#[test]
252+
fn test_filter_map_fold() {
253+
let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
254+
let ys = [0*0, 2*2, 4*4, 6*6, 8*8];
255+
let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x*x) } else { None });
256+
let i = it.fold(0, |i, x| {
257+
assert_eq!(x, ys[i]);
258+
i + 1
259+
});
260+
assert_eq!(i, ys.len());
261+
262+
let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x*x) } else { None });
263+
let i = it.rfold(ys.len(), |i, x| {
264+
assert_eq!(x, ys[i - 1]);
265+
i - 1
266+
});
267+
assert_eq!(i, 0);
268+
}
269+
251270
#[test]
252271
fn test_iterator_enumerate() {
253272
let xs = [0, 1, 2, 3, 4, 5];
@@ -282,7 +301,31 @@ fn test_iterator_enumerate_nth() {
282301
#[test]
283302
fn test_iterator_enumerate_count() {
284303
let xs = [0, 1, 2, 3, 4, 5];
285-
assert_eq!(xs.iter().count(), 6);
304+
assert_eq!(xs.iter().enumerate().count(), 6);
305+
}
306+
307+
#[test]
308+
fn test_iterator_enumerate_fold() {
309+
let xs = [0, 1, 2, 3, 4, 5];
310+
let mut it = xs.iter().enumerate();
311+
// steal a couple to get an interesting offset
312+
assert_eq!(it.next(), Some((0, &0)));
313+
assert_eq!(it.next(), Some((1, &1)));
314+
let i = it.fold(2, |i, (j, &x)| {
315+
assert_eq!(i, j);
316+
assert_eq!(x, xs[j]);
317+
i + 1
318+
});
319+
assert_eq!(i, xs.len());
320+
321+
let mut it = xs.iter().enumerate();
322+
assert_eq!(it.next(), Some((0, &0)));
323+
let i = it.rfold(xs.len() - 1, |i, (j, &x)| {
324+
assert_eq!(i, j);
325+
assert_eq!(x, xs[j]);
326+
i - 1
327+
});
328+
assert_eq!(i, 0);
286329
}
287330

288331
#[test]
@@ -291,6 +334,25 @@ fn test_iterator_filter_count() {
291334
assert_eq!(xs.iter().filter(|&&x| x % 2 == 0).count(), 5);
292335
}
293336

337+
#[test]
338+
fn test_iterator_filter_fold() {
339+
let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
340+
let ys = [0, 2, 4, 6, 8];
341+
let it = xs.iter().filter(|&&x| x % 2 == 0);
342+
let i = it.fold(0, |i, &x| {
343+
assert_eq!(x, ys[i]);
344+
i + 1
345+
});
346+
assert_eq!(i, ys.len());
347+
348+
let it = xs.iter().filter(|&&x| x % 2 == 0);
349+
let i = it.rfold(ys.len(), |i, &x| {
350+
assert_eq!(x, ys[i - 1]);
351+
i - 1
352+
});
353+
assert_eq!(i, 0);
354+
}
355+
294356
#[test]
295357
fn test_iterator_peekable() {
296358
let xs = vec![0, 1, 2, 3, 4, 5];
@@ -381,6 +443,18 @@ fn test_iterator_peekable_last() {
381443
assert_eq!(it.last(), None);
382444
}
383445

446+
#[test]
447+
fn test_iterator_peekable_fold() {
448+
let xs = [0, 1, 2, 3, 4, 5];
449+
let mut it = xs.iter().peekable();
450+
assert_eq!(it.peek(), Some(&&0));
451+
let i = it.fold(0, |i, &x| {
452+
assert_eq!(x, xs[i]);
453+
i + 1
454+
});
455+
assert_eq!(i, xs.len());
456+
}
457+
384458
/// This is an iterator that follows the Iterator contract,
385459
/// but it is not fused. After having returned None once, it will start
386460
/// producing elements if .next() is called again.
@@ -470,6 +544,26 @@ fn test_iterator_skip_while() {
470544
assert_eq!(i, ys.len());
471545
}
472546

547+
#[test]
548+
fn test_iterator_skip_while_fold() {
549+
let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
550+
let ys = [15, 16, 17, 19];
551+
let it = xs.iter().skip_while(|&x| *x < 15);
552+
let i = it.fold(0, |i, &x| {
553+
assert_eq!(x, ys[i]);
554+
i + 1
555+
});
556+
assert_eq!(i, ys.len());
557+
558+
let mut it = xs.iter().skip_while(|&x| *x < 15);
559+
assert_eq!(it.next(), Some(&ys[0])); // process skips before folding
560+
let i = it.fold(1, |i, &x| {
561+
assert_eq!(x, ys[i]);
562+
i + 1
563+
});
564+
assert_eq!(i, ys.len());
565+
}
566+
473567
#[test]
474568
fn test_iterator_skip() {
475569
let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
@@ -566,6 +660,26 @@ fn test_iterator_skip_last() {
566660
assert_eq!(it.last(), Some(&30));
567661
}
568662

663+
#[test]
664+
fn test_iterator_skip_fold() {
665+
let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
666+
let ys = [13, 15, 16, 17, 19, 20, 30];
667+
let it = xs.iter().skip(5);
668+
let i = it.fold(0, |i, &x| {
669+
assert_eq!(x, ys[i]);
670+
i + 1
671+
});
672+
assert_eq!(i, ys.len());
673+
674+
let mut it = xs.iter().skip(5);
675+
assert_eq!(it.next(), Some(&ys[0])); // process skips before folding
676+
let i = it.fold(1, |i, &x| {
677+
assert_eq!(x, ys[i]);
678+
i + 1
679+
});
680+
assert_eq!(i, ys.len());
681+
}
682+
569683
#[test]
570684
fn test_iterator_take() {
571685
let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
@@ -661,13 +775,22 @@ fn test_iterator_flat_map_fold() {
661775
let xs = [0, 3, 6];
662776
let ys = [1, 2, 3, 4, 5, 6, 7];
663777
let mut it = xs.iter().flat_map(|&x| x..x+3);
664-
it.next();
665-
it.next_back();
778+
assert_eq!(it.next(), Some(0));
779+
assert_eq!(it.next_back(), Some(8));
666780
let i = it.fold(0, |i, x| {
667781
assert_eq!(x, ys[i]);
668782
i + 1
669783
});
670784
assert_eq!(i, ys.len());
785+
786+
let mut it = xs.iter().flat_map(|&x| x..x+3);
787+
assert_eq!(it.next(), Some(0));
788+
assert_eq!(it.next_back(), Some(8));
789+
let i = it.rfold(ys.len(), |i, x| {
790+
assert_eq!(x, ys[i - 1]);
791+
i - 1
792+
});
793+
assert_eq!(i, 0);
671794
}
672795

673796
#[test]
@@ -684,6 +807,32 @@ fn test_inspect() {
684807
assert_eq!(&xs[..], &ys[..]);
685808
}
686809

810+
#[test]
811+
fn test_inspect_fold() {
812+
let xs = [1, 2, 3, 4];
813+
let mut n = 0;
814+
{
815+
let it = xs.iter().inspect(|_| n += 1);
816+
let i = it.fold(0, |i, &x| {
817+
assert_eq!(x, xs[i]);
818+
i + 1
819+
});
820+
assert_eq!(i, xs.len());
821+
}
822+
assert_eq!(n, xs.len());
823+
824+
let mut n = 0;
825+
{
826+
let it = xs.iter().inspect(|_| n += 1);
827+
let i = it.rfold(xs.len(), |i, &x| {
828+
assert_eq!(x, xs[i - 1]);
829+
i - 1
830+
});
831+
assert_eq!(i, 0);
832+
}
833+
assert_eq!(n, xs.len());
834+
}
835+
687836
#[test]
688837
fn test_cycle() {
689838
let cycle_len = 3;
@@ -1241,6 +1390,31 @@ fn test_fuse_count() {
12411390
// Can't check len now because count consumes.
12421391
}
12431392

1393+
#[test]
1394+
fn test_fuse_fold() {
1395+
let xs = [0, 1, 2];
1396+
let it = xs.iter(); // `FusedIterator`
1397+
let i = it.fuse().fold(0, |i, &x| {
1398+
assert_eq!(x, xs[i]);
1399+
i + 1
1400+
});
1401+
assert_eq!(i, xs.len());
1402+
1403+
let it = xs.iter(); // `FusedIterator`
1404+
let i = it.fuse().rfold(xs.len(), |i, &x| {
1405+
assert_eq!(x, xs[i - 1]);
1406+
i - 1
1407+
});
1408+
assert_eq!(i, 0);
1409+
1410+
let it = xs.iter().scan((), |_, &x| Some(x)); // `!FusedIterator`
1411+
let i = it.fuse().fold(0, |i, x| {
1412+
assert_eq!(x, xs[i]);
1413+
i + 1
1414+
});
1415+
assert_eq!(i, xs.len());
1416+
}
1417+
12441418
#[test]
12451419
fn test_once() {
12461420
let mut it = once(42);

‎src/libcore/tests/lib.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#![feature(inclusive_range)]
2626
#![feature(inclusive_range_syntax)]
2727
#![feature(iter_rfind)]
28+
#![feature(iter_rfold)]
2829
#![feature(nonzero)]
2930
#![feature(rand)]
3031
#![feature(raw)]

0 commit comments

Comments
 (0)
Please sign in to comment.