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