Skip to content

Commit 09ee9b7

Browse files
committed
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)
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

+121-30
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
}

0 commit comments

Comments
 (0)