22
22
#include " benchmark/benchmark.h"
23
23
#include " test_iterators.h"
24
24
#include " ../../GenerateInput.h"
25
+ #include " ../../../std/containers/from_range_helpers.h"
25
26
26
27
namespace support {
27
28
@@ -172,8 +173,8 @@ void sequence_container_benchmarks(std::string container) {
172
173
bool toggle = false ;
173
174
for ([[maybe_unused]] auto _ : st) {
174
175
std::vector<ValueType>& in = toggle ? in1 : in2;
175
- auto first = in.data ();
176
- auto last = in.data () + in. size ();
176
+ auto first = in.begin ();
177
+ auto last = in.end ();
177
178
c.assign (cpp17_input_iterator (first), cpp17_input_iterator (last));
178
179
toggle = !toggle;
179
180
DoNotOptimizeData (c);
@@ -237,8 +238,8 @@ void sequence_container_benchmarks(std::string container) {
237
238
std::vector<ValueType> in;
238
239
std::generate_n (std::back_inserter (in), size, gen);
239
240
DoNotOptimizeData (in);
240
- auto first = in.data ();
241
- auto last = in.data () + in. size ();
241
+ auto first = in.begin ();
242
+ auto last = in.end ();
242
243
243
244
const int small = 100 ; // arbitrary
244
245
Container c;
@@ -264,8 +265,8 @@ void sequence_container_benchmarks(std::string container) {
264
265
std::vector<ValueType> in;
265
266
std::generate_n (std::back_inserter (in), size, gen);
266
267
DoNotOptimizeData (in);
267
- auto first = in.data ();
268
- auto last = in.data () + in. size ();
268
+ auto first = in.begin ();
269
+ auto last = in.end ();
269
270
270
271
const int overflow = size / 10 ; // 10% of elements won't fit in the vector when we insert
271
272
Container c;
@@ -290,8 +291,8 @@ void sequence_container_benchmarks(std::string container) {
290
291
std::vector<ValueType> in;
291
292
std::generate_n (std::back_inserter (in), size, gen);
292
293
DoNotOptimizeData (in);
293
- auto first = in.data ();
294
- auto last = in.data () + in. size ();
294
+ auto first = in.begin ();
295
+ auto last = in.end ();
295
296
296
297
auto const overflow = 9 * (size / 10 ); // 90% of elements won't fit in the vector when we insert
297
298
Container c;
@@ -448,6 +449,180 @@ void sequence_container_benchmarks(std::string container) {
448
449
}
449
450
});
450
451
}
452
+
453
+ // //////////////////////////////////////////////////////////////////////////////////////////////
454
+ // Additional benchmarks for vector<bool> iterator-pair and range-based operations
455
+ // //////////////////////////////////////////////////////////////////////////////////////////////
456
+
457
+ static constexpr bool is_vector_bool = requires {
458
+ typename Container::allocator_type;
459
+ } && std::same_as<std::remove_cvref_t <Container>, std::vector<bool , typename Container::allocator_type>>;
460
+
461
+ if constexpr (is_vector_bool) {
462
+ auto bench_vb = [&](std::string operation, auto f) {
463
+ benchmark::RegisterBenchmark (container + " ::" + operation, f)->Arg (1024 )->Arg (1 << 16 )->Arg (1 << 20 );
464
+ };
465
+
466
+ { // iterator-pair ctor
467
+ auto bm = [&generators, &bench_vb, &tostr]<template <class > class Iter >(std::string iter) {
468
+ for (auto gen : generators)
469
+ bench_vb (" ctor(" + iter + " , " + iter + " )" + tostr (gen), [gen](auto & st) {
470
+ auto const size = st.range (0 );
471
+ std::vector<int > in;
472
+ std::generate_n (std::back_inserter (in), size, gen);
473
+ benchmark::DoNotOptimize (in);
474
+ const auto begin = Iter (in.begin ());
475
+ const auto end = Iter (in.end ());
476
+ benchmark::DoNotOptimize (in);
477
+
478
+ for ([[maybe_unused]] auto _ : st) {
479
+ Container c (begin, end); // we assume the destructor doesn't dominate the benchmark
480
+ DoNotOptimizeData (c);
481
+ }
482
+ });
483
+ };
484
+ bm.template operator ()<forward_iterator>(" fwd_iter" );
485
+ bm.template operator ()<random_access_iterator>(" ra_iter" );
486
+ }
487
+ { // iterator-pair assignment
488
+ auto bm = [&generators, &bench_vb, &tostr]<template <class > class Iter >(std::string iter) {
489
+ for (auto gen : generators)
490
+ bench_vb (" assign(" + iter + " , " + iter + " )" + tostr (gen), [gen](auto & st) {
491
+ auto const size = st.range (0 );
492
+ std::vector<int > in1, in2;
493
+ std::generate_n (std::back_inserter (in1), size, gen);
494
+ std::generate_n (std::back_inserter (in2), size, gen);
495
+ DoNotOptimizeData (in1);
496
+ DoNotOptimizeData (in2);
497
+
498
+ Container c (in1.begin (), in1.end ());
499
+ bool toggle = true ;
500
+ for ([[maybe_unused]] auto _ : st) {
501
+ auto & in = toggle ? in2 : in1;
502
+ c.assign (Iter (in.begin ()), Iter (in.end ()));
503
+ toggle = !toggle;
504
+ DoNotOptimizeData (c);
505
+ }
506
+ });
507
+ };
508
+ bm.template operator ()<forward_iterator>(" fwd_iter" );
509
+ bm.template operator ()<random_access_iterator>(" ra_iter" );
510
+ }
511
+ { // Iterator-pair insertion
512
+ auto bm = [&generators, &bench_vb, &tostr]<template <class > class Iter >(std::string iter) {
513
+ for (auto gen : generators)
514
+ bench_vb (" insert(begin, " + iter + " , " + iter + " )" + tostr (gen), [gen](auto & st) {
515
+ auto const size = st.range (0 );
516
+ std::vector<int > in;
517
+ Container c;
518
+ std::generate_n (std::back_inserter (in), size, gen);
519
+ std::generate_n (std::back_inserter (c), size, gen);
520
+ DoNotOptimizeData (in);
521
+ DoNotOptimizeData (c);
522
+
523
+ for ([[maybe_unused]] auto _ : st) {
524
+ c.insert (c.begin (), Iter (in.begin ()), Iter (in.end ()));
525
+ c.erase (c.begin () + size, c.end ()); // avoid growing indefinitely
526
+ DoNotOptimizeData (c);
527
+ }
528
+ });
529
+ };
530
+ bm.template operator ()<forward_iterator>(" fwd_iter" );
531
+ bm.template operator ()<random_access_iterator>(" ra_iter" );
532
+ }
533
+
534
+ #if defined(__cpp_lib_containers_ranges) && __cpp_lib_containers_ranges >= 202202L
535
+ { // Range-ctor
536
+ auto bm = [&generators, &bench_vb, &tostr]<template <class , class > class Range >(std::string range) {
537
+ for (auto gen : generators)
538
+ bench_vb (" ctor(" + range + " )" + tostr (gen), [gen](auto & st) {
539
+ auto const size = st.range (0 );
540
+ std::vector<int > in;
541
+ std::generate_n (std::back_inserter (in), size, gen);
542
+ Range rg (std::ranges::begin (in), std::ranges::end (in));
543
+ benchmark::DoNotOptimize (in);
544
+
545
+ for ([[maybe_unused]] auto _ : st) {
546
+ Container c (std::from_range, rg); // we assume the destructor doesn't dominate the benchmark
547
+ DoNotOptimizeData (c);
548
+ }
549
+ });
550
+ };
551
+ bm.template operator ()<forward_range_wrapper>(" fwd_range" );
552
+ bm.template operator ()<random_access_range_wrapper>(" ra_range" );
553
+ }
554
+ { // Range-assignment
555
+ auto bm = [&generators, &bench_vb, &tostr]<template <class , class > class Range >(std::string range) {
556
+ for (auto gen : generators)
557
+ bench_vb (" assign_range(" + range + " )" + tostr (gen), [gen](auto & st) {
558
+ auto const size = st.range (0 );
559
+ std::vector<int > in1, in2;
560
+ std::generate_n (std::back_inserter (in1), size, gen);
561
+ std::generate_n (std::back_inserter (in2), size, gen);
562
+ Range rg1 (std::ranges::begin (in1), std::ranges::end (in1));
563
+ Range rg2 (std::ranges::begin (in2), std::ranges::end (in2));
564
+ DoNotOptimizeData (in1);
565
+ DoNotOptimizeData (in2);
566
+
567
+ Container c (std::from_range, rg1);
568
+ bool toggle = true ;
569
+ for ([[maybe_unused]] auto _ : st) {
570
+ auto & in = toggle ? rg2 : rg1;
571
+ c.assign_range (in);
572
+ toggle = !toggle;
573
+ DoNotOptimizeData (c);
574
+ }
575
+ });
576
+ };
577
+ bm.template operator ()<forward_range_wrapper>(" fwd_range" );
578
+ bm.template operator ()<random_access_range_wrapper>(" ra_range" );
579
+ }
580
+ { // Range-insertion
581
+ auto bm = [&generators, &bench_vb, &tostr]<template <class , class > class Range >(std::string range) {
582
+ for (auto gen : generators)
583
+ bench_vb (" insert_range(" + range + " )" + tostr (gen), [gen](auto & st) {
584
+ auto const size = st.range (0 );
585
+ std::vector<int > in;
586
+ Container c;
587
+ std::generate_n (std::back_inserter (in), size, gen);
588
+ std::generate_n (std::back_inserter (c), size, gen);
589
+ Range rg (std::ranges::begin (in), std::ranges::end (in));
590
+ DoNotOptimizeData (in);
591
+ DoNotOptimizeData (c);
592
+
593
+ for ([[maybe_unused]] auto _ : st) {
594
+ c.insert_range (c.begin (), in);
595
+ c.erase (c.begin () + size, c.end ()); // avoid growing indefinitely
596
+ DoNotOptimizeData (c);
597
+ }
598
+ });
599
+ };
600
+ bm.template operator ()<forward_range_wrapper>(" fwd_range" );
601
+ bm.template operator ()<random_access_range_wrapper>(" ra_range" );
602
+ }
603
+ { // Range-append
604
+ auto bm = [&generators, &bench_vb, &tostr]<template <class , class > class Range >(std::string range) {
605
+ for (auto gen : generators)
606
+ bench_vb (" append_range(" + range + " )" + tostr (gen), [gen](auto & st) {
607
+ auto const size = st.range (0 );
608
+ std::vector<int > in;
609
+ std::generate_n (std::back_inserter (in), size, gen);
610
+ Range rg (std::ranges::begin (in), std::ranges::end (in));
611
+ DoNotOptimizeData (in);
612
+
613
+ Container c;
614
+ for ([[maybe_unused]] auto _ : st) {
615
+ c.append_range (in);
616
+ c.erase (c.begin (), c.end ()); // avoid growing indefinitely
617
+ DoNotOptimizeData (c);
618
+ }
619
+ });
620
+ };
621
+ bm.template operator ()<forward_range_wrapper>(" fwd_range" );
622
+ bm.template operator ()<random_access_range_wrapper>(" ra_range" );
623
+ }
624
+ #endif
625
+ }
451
626
}
452
627
453
628
} // namespace support
0 commit comments