1 #![allow(unstable_name_collisions, clippy::incompatible_msrv)]
2 
3 use criterion::black_box;
4 use criterion::BenchmarkId;
5 use itertools::Itertools;
6 
7 const NTH_INPUTS: &[usize] = &[0, 1, 2, 4, 8];
8 
9 /// Create multiple functions each defining a benchmark group about iterator methods.
10 ///
11 /// Each created group has functions with the following ids:
12 ///
13 /// - `next`, `size_hint`, `count`, `last`, `nth`, `collect`, `fold`
14 /// - and when marked as `DoubleEndedIterator`: `next_back`, `nth_back`, `rfold`
15 /// - and when marked as `ExactSizeIterator`: `len`
16 ///
17 /// Note that this macro can be called only once.
18 macro_rules! bench_specializations {
19     (
20         $(
21             $name:ident {
22                 $($extra:ident)*
23                 {$(
24                     $init:stmt;
25                 )*}
26                 $iterator:expr
27             }
28         )*
29     ) => {
30         $(
31             #[allow(unused_must_use)]
32             fn $name(c: &mut ::criterion::Criterion) {
33                 let mut bench_group = c.benchmark_group(stringify!($name));
34                 $(
35                     $init
36                 )*
37                 let bench_first_its = {
38                     let mut bench_idx = 0;
39                     [0; 1000].map(|_| {
40                         let mut it = $iterator;
41                         if bench_idx != 0 {
42                             it.nth(bench_idx - 1);
43                         }
44                         bench_idx += 1;
45                         it
46                     })
47                 };
48                 bench_specializations!(@Iterator bench_group bench_first_its: $iterator);
49                 $(
50                     bench_specializations!(@$extra bench_group bench_first_its: $iterator);
51                 )*
52                 bench_group.finish();
53             }
54         )*
55 
56         ::criterion::criterion_group!(benches, $($name, )*);
57         ::criterion::criterion_main!(benches);
58     };
59 
60     (@Iterator $group:ident $first_its:ident: $iterator:expr) => {
61         $group.bench_function("next", |bencher| bencher.iter(|| {
62             let mut it = $iterator;
63             while let Some(x) = it.next() {
64                 black_box(x);
65             }
66         }));
67         $group.bench_function("size_hint", |bencher| bencher.iter(|| {
68             $first_its.iter().for_each(|it| {
69                 black_box(it.size_hint());
70             })
71         }));
72         $group.bench_function("count", |bencher| bencher.iter(|| {
73             $iterator.count()
74         }));
75         $group.bench_function("last", |bencher| bencher.iter(|| {
76             $iterator.last()
77         }));
78         for n in NTH_INPUTS {
79             $group.bench_with_input(BenchmarkId::new("nth", n), n, |bencher, n| bencher.iter(|| {
80                 for start in 0_usize..10 {
81                     let mut it = $iterator;
82                     if let Some(s) = start.checked_sub(1) {
83                         black_box(it.nth(s));
84                     }
85                     while let Some(x) = it.nth(*n) {
86                         black_box(x);
87                     }
88                 }
89             }));
90         }
91         $group.bench_function("collect", |bencher| bencher.iter(|| {
92             $iterator.collect::<Vec<_>>()
93         }));
94         $group.bench_function("fold", |bencher| bencher.iter(|| {
95             $iterator.fold((), |(), x| {
96                 black_box(x);
97             })
98         }));
99     };
100 
101     (@DoubleEndedIterator $group:ident $_first_its:ident: $iterator:expr) => {
102         $group.bench_function("next_back", |bencher| bencher.iter(|| {
103             let mut it = $iterator;
104             while let Some(x) = it.next_back() {
105                 black_box(x);
106             }
107         }));
108         for n in NTH_INPUTS {
109             $group.bench_with_input(BenchmarkId::new("nth_back", n), n, |bencher, n| bencher.iter(|| {
110                 for start in 0_usize..10 {
111                     let mut it = $iterator;
112                     if let Some(s) = start.checked_sub(1) {
113                         black_box(it.nth_back(s));
114                     }
115                     while let Some(x) = it.nth_back(*n) {
116                         black_box(x);
117                     }
118                 }
119             }));
120         }
121         $group.bench_function("rfold", |bencher| bencher.iter(|| {
122             $iterator.rfold((), |(), x| {
123                 black_box(x);
124             })
125         }));
126     };
127 
128     (@ExactSizeIterator $group:ident $first_its:ident: $_iterator:expr) => {
129         $group.bench_function("len", |bencher| bencher.iter(|| {
130             $first_its.iter().for_each(|it| {
131                 black_box(it.len());
132             })
133         }));
134     };
135 }
136 
137 // Usage examples:
138 // - For `ZipLongest::fold` only:
139 //     cargo bench --bench specializations zip_longest/fold
140 // - For `.combinations(k).nth(8)`:
141 //     cargo bench --bench specializations combinations./nth/8
142 bench_specializations! {
143     interleave {
144         {
145             let v1 = black_box(vec![0; 1024]);
146             let v2 = black_box(vec![0; 768]);
147         }
148         v1.iter().interleave(&v2)
149     }
150     interleave_shortest {
151         {
152             let v1 = black_box(vec![0; 1024]);
153             let v2 = black_box(vec![0; 768]);
154         }
155         v1.iter().interleave_shortest(&v2)
156     }
157     batching {
158         {
159             let v = black_box(vec![0; 1024]);
160         }
161         v.iter().batching(Iterator::next)
162     }
163     tuple_windows1 {
164         ExactSizeIterator
165         {
166             let v = black_box(vec![0; 1024]);
167         }
168         v.iter().tuple_windows::<(_,)>()
169     }
170     tuple_windows2 {
171         ExactSizeIterator
172         {
173             let v = black_box(vec![0; 1024]);
174         }
175         v.iter().tuple_windows::<(_, _)>()
176     }
177     tuple_windows3 {
178         ExactSizeIterator
179         {
180             let v = black_box(vec![0; 1024]);
181         }
182         v.iter().tuple_windows::<(_, _, _)>()
183     }
184     tuple_windows4 {
185         ExactSizeIterator
186         {
187             let v = black_box(vec![0; 1024]);
188         }
189         v.iter().tuple_windows::<(_, _, _, _)>()
190     }
191     circular_tuple_windows1 {
192         ExactSizeIterator
193         {
194             let v = black_box(vec![0; 1024]);
195         }
196         v.iter().circular_tuple_windows::<(_,)>()
197     }
198     circular_tuple_windows2 {
199         ExactSizeIterator
200         {
201             let v = black_box(vec![0; 1024]);
202         }
203         v.iter().circular_tuple_windows::<(_, _)>()
204     }
205     circular_tuple_windows3 {
206         ExactSizeIterator
207         {
208             let v = black_box(vec![0; 1024]);
209         }
210         v.iter().circular_tuple_windows::<(_, _, _)>()
211     }
212     circular_tuple_windows4 {
213         ExactSizeIterator
214         {
215             let v = black_box(vec![0; 1024]);
216         }
217         v.iter().circular_tuple_windows::<(_, _, _, _)>()
218     }
219     tuples1 {
220         ExactSizeIterator
221         {
222             let v = black_box(vec![0; 1024]);
223         }
224         v.iter().tuples::<(_,)>()
225     }
226     tuples2 {
227         ExactSizeIterator
228         {
229             let v = black_box(vec![0; 1024]);
230         }
231         v.iter().tuples::<(_, _)>()
232     }
233     tuples3 {
234         ExactSizeIterator
235         {
236             let v = black_box(vec![0; 1024]);
237         }
238         v.iter().tuples::<(_, _, _)>()
239     }
240     tuples4 {
241         ExactSizeIterator
242         {
243             let v = black_box(vec![0; 1024]);
244         }
245         v.iter().tuples::<(_, _, _, _)>()
246     }
247     tuple_buffer {
248         ExactSizeIterator
249         {
250             let v = black_box(vec![0; 11]);
251             // Short but the buffer can't have 12 or more elements.
252         }
253         {
254             let mut it = v.iter().tuples::<(_, _, _, _, _, _, _, _, _, _, _, _)>();
255             it.next(); // No element but it fills the buffer.
256             it.into_buffer()
257         }
258     }
259     cartesian_product {
260         {
261             let v = black_box(vec![0; 16]);
262         }
263         itertools::iproduct!(&v, &v, &v)
264     }
265     multi_cartesian_product {
266         {
267             let vs = black_box([0; 3].map(|_| vec![0; 16]));
268         }
269         vs.iter().multi_cartesian_product()
270     }
271     coalesce {
272         {
273             let v = black_box(vec![0; 1024]);
274         }
275         v.iter().coalesce(|x, y| if x == y { Ok(x) } else { Err((x, y)) })
276     }
277     dedup {
278         {
279             let v = black_box((0..32).flat_map(|x| [x; 32]).collect_vec());
280         }
281         v.iter().dedup()
282     }
283     dedup_by {
284         {
285             let v = black_box((0..32).flat_map(|x| [x; 32]).collect_vec());
286         }
287         v.iter().dedup_by(PartialOrd::ge)
288     }
289     dedup_with_count {
290         {
291             let v = black_box((0..32).flat_map(|x| [x; 32]).collect_vec());
292         }
293         v.iter().dedup_with_count()
294     }
295     dedup_by_with_count {
296         {
297             let v = black_box((0..32).flat_map(|x| [x; 32]).collect_vec());
298         }
299         v.iter().dedup_by_with_count(PartialOrd::ge)
300     }
301     duplicates {
302         DoubleEndedIterator
303         {
304             let v = black_box((0..32).cycle().take(1024).collect_vec());
305         }
306         v.iter().duplicates()
307     }
308     duplicates_by {
309         DoubleEndedIterator
310         {
311             let v = black_box((0..1024).collect_vec());
312         }
313         v.iter().duplicates_by(|x| *x % 10)
314     }
315     unique {
316         DoubleEndedIterator
317         {
318             let v = black_box((0..32).cycle().take(1024).collect_vec());
319         }
320         v.iter().unique()
321     }
322     unique_by {
323         DoubleEndedIterator
324         {
325             let v = black_box((0..1024).collect_vec());
326         }
327         v.iter().unique_by(|x| *x % 50)
328     }
329     take_while_inclusive {
330         {
331             let v = black_box((0..1024).collect_vec());
332         }
333         v.iter().take_while_inclusive(|x| **x < 1000)
334     }
335     pad_using {
336         DoubleEndedIterator
337         ExactSizeIterator
338         {
339             let v = black_box((0..1024).collect_vec());
340         }
341         v.iter().copied().pad_using(2048, |i| 5 * i)
342     }
343     positions {
344         DoubleEndedIterator
345         {
346             let v = black_box((0..1024).collect_vec());
347         }
348         v.iter().positions(|x| x % 5 == 0)
349     }
350     update {
351         DoubleEndedIterator
352         ExactSizeIterator
353         {
354             let v = black_box((0_i32..1024).collect_vec());
355         }
356         v.iter().copied().update(|x| *x *= 7)
357     }
358     tuple_combinations1 {
359         {
360             let v = black_box(vec![0; 1024]);
361         }
362         v.iter().tuple_combinations::<(_,)>()
363     }
364     tuple_combinations2 {
365         {
366             let v = black_box(vec![0; 64]);
367         }
368         v.iter().tuple_combinations::<(_, _)>()
369     }
370     tuple_combinations3 {
371         {
372             let v = black_box(vec![0; 64]);
373         }
374         v.iter().tuple_combinations::<(_, _, _)>()
375     }
376     tuple_combinations4 {
377         {
378             let v = black_box(vec![0; 64]);
379         }
380         v.iter().tuple_combinations::<(_, _, _, _)>()
381     }
382     intersperse {
383         {
384             let v = black_box(vec![0; 1024]);
385             let n = black_box(0);
386         }
387         v.iter().intersperse(&n)
388     }
389     intersperse_with {
390         {
391             let v = black_box(vec![0; 1024]);
392             let n = black_box(0);
393         }
394         v.iter().intersperse_with(|| &n)
395     }
396     combinations1 {
397         {
398             let v = black_box(vec![0; 1792]);
399         }
400         v.iter().combinations(1)
401     }
402     combinations2 {
403         {
404             let v = black_box(vec![0; 60]);
405         }
406         v.iter().combinations(2)
407     }
408     combinations3 {
409         {
410             let v = black_box(vec![0; 23]);
411         }
412         v.iter().combinations(3)
413     }
414     combinations4 {
415         {
416             let v = black_box(vec![0; 16]);
417         }
418         v.iter().combinations(4)
419     }
420     combinations_with_replacement1 {
421         {
422             let v = black_box(vec![0; 4096]);
423         }
424         v.iter().combinations_with_replacement(1)
425     }
426     combinations_with_replacement2 {
427         {
428             let v = black_box(vec![0; 90]);
429         }
430         v.iter().combinations_with_replacement(2)
431     }
432     combinations_with_replacement3 {
433         {
434             let v = black_box(vec![0; 28]);
435         }
436         v.iter().combinations_with_replacement(3)
437     }
438     combinations_with_replacement4 {
439         {
440             let v = black_box(vec![0; 16]);
441         }
442         v.iter().combinations_with_replacement(4)
443     }
444     permutations1 {
445         {
446             let v = black_box(vec![0; 1024]);
447         }
448         v.iter().permutations(1)
449     }
450     permutations2 {
451         {
452             let v = black_box(vec![0; 36]);
453         }
454         v.iter().permutations(2)
455     }
456     permutations3 {
457         {
458             let v = black_box(vec![0; 12]);
459         }
460         v.iter().permutations(3)
461     }
462     permutations4 {
463         {
464             let v = black_box(vec![0; 8]);
465         }
466         v.iter().permutations(4)
467     }
468     powerset {
469         {
470             let v = black_box(vec![0; 10]);
471         }
472         v.iter().powerset()
473     }
474     while_some {
475         {}
476         (0..)
477             .map(black_box)
478             .map(|i| char::from_digit(i, 16))
479             .while_some()
480     }
481     with_position {
482         ExactSizeIterator
483         {
484             let v = black_box((0..10240).collect_vec());
485         }
486         v.iter().with_position()
487     }
488     zip_longest {
489         DoubleEndedIterator
490         ExactSizeIterator
491         {
492             let xs = black_box(vec![0; 1024]);
493             let ys = black_box(vec![0; 768]);
494         }
495         xs.iter().zip_longest(ys.iter())
496     }
497     zip_eq {
498         ExactSizeIterator
499         {
500             let v = black_box(vec![0; 1024]);
501         }
502         v.iter().zip_eq(v.iter().rev())
503     }
504     multizip {
505         DoubleEndedIterator
506         ExactSizeIterator
507         {
508             let v1 = black_box(vec![0; 1024]);
509             let v2 = black_box(vec![0; 768]);
510             let v3 = black_box(vec![0; 2048]);
511         }
512         itertools::multizip((&v1, &v2, &v3))
513     }
514     izip {
515         DoubleEndedIterator
516         ExactSizeIterator
517         {
518             let v1 = black_box(vec![0; 1024]);
519             let v2 = black_box(vec![0; 768]);
520             let v3 = black_box(vec![0; 2048]);
521         }
522         itertools::izip!(&v1, &v2, &v3)
523     }
524     put_back {
525         {
526             let v = black_box(vec![0; 1024]);
527         }
528         itertools::put_back(&v).with_value(black_box(&0))
529     }
530     put_back_n {
531         {
532             let v1 = black_box(vec![0; 1024]);
533             let v2 = black_box(vec![0; 16]);
534         }
535         {
536             let mut it = itertools::put_back_n(&v1);
537             for n in &v2 {
538                 it.put_back(n);
539             }
540             it
541         }
542     }
543     exactly_one_error {
544         ExactSizeIterator
545         {
546             let v = black_box(vec![0; 1024]);
547         }
548         // Use `at_most_one` would be similar.
549         v.iter().exactly_one().unwrap_err()
550     }
551     multipeek {
552         ExactSizeIterator
553         {
554             let v = black_box(vec![0; 1024]);
555             let n = black_box(16);
556         }
557         {
558             let mut it = v.iter().multipeek();
559             for _ in 0..n {
560                 it.peek();
561             }
562             it
563         }
564     }
565     peek_nth {
566         ExactSizeIterator
567         {
568             let v = black_box(vec![0; 1024]);
569             let n = black_box(16);
570         }
571         {
572             let mut it = itertools::peek_nth(&v);
573             it.peek_nth(n);
574             it
575         }
576     }
577     repeat_n {
578         DoubleEndedIterator
579         ExactSizeIterator
580         {}
581         itertools::repeat_n(black_box(0), black_box(1024))
582     }
583     merge {
584         {
585             let v1 = black_box((0..1024).collect_vec());
586             let v2 = black_box((0..768).collect_vec());
587         }
588         v1.iter().merge(&v2)
589     }
590     merge_by {
591         {
592             let v1 = black_box((0..1024).collect_vec());
593             let v2 = black_box((0..768).collect_vec());
594         }
595         v1.iter().merge_by(&v2, PartialOrd::ge)
596     }
597     merge_join_by_ordering {
598         {
599             let v1 = black_box((0..1024).collect_vec());
600             let v2 = black_box((0..768).collect_vec());
601         }
602         v1.iter().merge_join_by(&v2, Ord::cmp)
603     }
604     merge_join_by_bool {
605         {
606             let v1 = black_box((0..1024).collect_vec());
607             let v2 = black_box((0..768).collect_vec());
608         }
609         v1.iter().merge_join_by(&v2, PartialOrd::ge)
610     }
611     kmerge {
612         {
613             let vs = black_box(vec![vec![0; 1024], vec![0; 256], vec![0; 768]]);
614         }
615         vs.iter().kmerge()
616     }
617     kmerge_by {
618         {
619             let vs = black_box(vec![vec![0; 1024], vec![0; 256], vec![0; 768]]);
620         }
621         vs.iter().kmerge_by(PartialOrd::ge)
622     }
623     map_into {
624         DoubleEndedIterator
625         ExactSizeIterator
626         {
627             let v = black_box(vec![0_u8; 1024]);
628         }
629         v.iter().copied().map_into::<u32>()
630     }
631     map_ok {
632         DoubleEndedIterator
633         ExactSizeIterator
634         {
635             let v = black_box((0_u32..1024)
636                 .map(|x| if x % 2 == 1 { Err(x) } else { Ok(x) })
637                 .collect_vec());
638         }
639         v.iter().copied().map_ok(|x| x + 1)
640     }
641     filter_ok {
642         {
643             let v = black_box((0_u32..1024)
644                 .map(|x| if x % 2 == 1 { Err(x) } else { Ok(x) })
645                 .collect_vec());
646         }
647         v.iter().copied().filter_ok(|x| x % 3 == 0)
648     }
649     filter_map_ok {
650         {
651             let v = black_box((0_u32..1024)
652                 .map(|x| if x % 2 == 1 { Err(x) } else { Ok(x) })
653                 .collect_vec());
654         }
655         v.iter().copied().filter_map_ok(|x| if x % 3 == 0 { Some(x + 1) } else { None })
656     }
657     flatten_ok {
658         DoubleEndedIterator
659         {
660             let d = black_box(vec![0; 8]);
661             let v = black_box((0..512)
662                 .map(|x| if x % 2 == 0 { Ok(&d) } else { Err(x) })
663                 .collect_vec());
664         }
665         v.iter().copied().flatten_ok()
666     }
667 }
668