Home | History | Annotate | Line # | Download | only in benchmarks
      1 //===----------------------------------------------------------------------===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 
      9 #include <algorithm>
     10 #include <cstdint>
     11 #include <map>
     12 #include <random>
     13 #include <vector>
     14 
     15 #include "CartesianBenchmarks.h"
     16 #include "benchmark/benchmark.h"
     17 #include "test_macros.h"
     18 
     19 // When VALIDATE is defined the benchmark will run to validate the benchmarks.
     20 // The time taken by several operations depend on whether or not an element
     21 // exists. To avoid errors in the benchmark these operations have a validation
     22 // mode to test the benchmark. Since they are not meant to be benchmarked the
     23 // number of sizes tested is limited to 1.
     24 //#define VALIDATE
     25 
     26 namespace {
     27 
     28 enum class Mode { Hit, Miss };
     29 
     30 struct AllModes : EnumValuesAsTuple<AllModes, Mode, 2> {
     31   static constexpr const char* Names[] = {"ExistingElement", "NewElement"};
     32 };
     33 
     34 // The positions of the hints to pick:
     35 // - Begin picks the first item. The item cannot be put before this element.
     36 // - Thrid picks the third item. This is just an element with a valid entry
     37 //   before and after it.
     38 // - Correct contains the correct hint.
     39 // - End contains a hint to the end of the map.
     40 enum class Hint { Begin, Third, Correct, End };
     41 struct AllHints : EnumValuesAsTuple<AllHints, Hint, 4> {
     42   static constexpr const char* Names[] = {"Begin", "Third", "Correct", "End"};
     43 };
     44 
     45 enum class Order { Sorted, Random };
     46 struct AllOrders : EnumValuesAsTuple<AllOrders, Order, 2> {
     47   static constexpr const char* Names[] = {"Sorted", "Random"};
     48 };
     49 
     50 struct TestSets {
     51   std::vector<uint64_t> Keys;
     52   std::vector<std::map<uint64_t, int64_t> > Maps;
     53   std::vector<
     54       std::vector<typename std::map<uint64_t, int64_t>::const_iterator> >
     55       Hints;
     56 };
     57 
     58 enum class Shuffle { None, Keys, Hints };
     59 
     60 TestSets makeTestingSets(size_t MapSize, Mode mode, Shuffle shuffle,
     61                          size_t max_maps) {
     62   /*
     63    * The shuffle does not retain the random number generator to use the same
     64    * set of random numbers for every iteration.
     65    */
     66   TestSets R;
     67 
     68   int MapCount = std::min(max_maps, 1000000 / MapSize);
     69 
     70   for (uint64_t I = 0; I < MapSize; ++I) {
     71     R.Keys.push_back(mode == Mode::Hit ? 2 * I + 2 : 2 * I + 1);
     72   }
     73   if (shuffle == Shuffle::Keys)
     74     std::shuffle(R.Keys.begin(), R.Keys.end(), std::mt19937());
     75 
     76   for (int M = 0; M < MapCount; ++M) {
     77     auto& map = R.Maps.emplace_back();
     78     auto& hints = R.Hints.emplace_back();
     79     for (uint64_t I = 0; I < MapSize; ++I) {
     80       hints.push_back(map.insert(std::make_pair(2 * I + 2, 0)).first);
     81     }
     82     if (shuffle == Shuffle::Hints)
     83       std::shuffle(hints.begin(), hints.end(), std::mt19937());
     84   }
     85 
     86   return R;
     87 }
     88 
     89 struct Base {
     90   size_t MapSize;
     91   Base(size_t T) : MapSize(T) {}
     92 
     93   std::string baseName() const { return "_MapSize=" + std::to_string(MapSize); }
     94 };
     95 
     96 //*******************************************************************|
     97 //                       Member functions                            |
     98 //*******************************************************************|
     99 
    100 struct ConstructorDefault {
    101   void run(benchmark::State& State) const {
    102     for (auto _ : State) {
    103       benchmark::DoNotOptimize(std::map<uint64_t, int64_t>());
    104     }
    105   }
    106 
    107   std::string name() const { return "BM_ConstructorDefault"; }
    108 };
    109 
    110 struct ConstructorIterator : Base {
    111   using Base::Base;
    112 
    113   void run(benchmark::State& State) const {
    114     auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1);
    115     auto& Map = Data.Maps.front();
    116     while (State.KeepRunningBatch(MapSize)) {
    117 #ifndef VALIDATE
    118       benchmark::DoNotOptimize(
    119           std::map<uint64_t, int64_t>(Map.begin(), Map.end()));
    120 #else
    121       std::map<uint64_t, int64_t> M{Map.begin(), Map.end()};
    122       if (M != Map)
    123         State.SkipWithError("Map copy not identical");
    124 #endif
    125     }
    126   }
    127 
    128   std::string name() const { return "BM_ConstructorIterator" + baseName(); }
    129 };
    130 
    131 struct ConstructorCopy : Base {
    132   using Base::Base;
    133 
    134   void run(benchmark::State& State) const {
    135     auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1);
    136     auto& Map = Data.Maps.front();
    137     while (State.KeepRunningBatch(MapSize)) {
    138 #ifndef VALIDATE
    139       std::map<uint64_t, int64_t> M(Map);
    140       benchmark::DoNotOptimize(M);
    141 #else
    142       std::map<uint64_t, int64_t> M(Map);
    143       if (M != Map)
    144         State.SkipWithError("Map copy not identical");
    145 #endif
    146     }
    147   }
    148 
    149   std::string name() const { return "BM_ConstructorCopy" + baseName(); }
    150 };
    151 
    152 struct ConstructorMove : Base {
    153   using Base::Base;
    154 
    155   void run(benchmark::State& State) const {
    156     auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
    157     while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
    158       for (auto& Map : Data.Maps) {
    159         std::map<uint64_t, int64_t> M(std::move(Map));
    160         benchmark::DoNotOptimize(M);
    161       }
    162       State.PauseTiming();
    163       Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
    164       State.ResumeTiming();
    165     }
    166   }
    167 
    168   std::string name() const { return "BM_ConstructorMove" + baseName(); }
    169 };
    170 
    171 //*******************************************************************|
    172 //                           Capacity                                |
    173 //*******************************************************************|
    174 
    175 struct Empty : Base {
    176   using Base::Base;
    177 
    178   void run(benchmark::State& State) const {
    179     auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1);
    180     auto& Map = Data.Maps.front();
    181     for (auto _ : State) {
    182 #ifndef VALIDATE
    183       benchmark::DoNotOptimize(Map.empty());
    184 #else
    185       if (Map.empty())
    186         State.SkipWithError("Map contains an invalid number of elements.");
    187 #endif
    188     }
    189   }
    190 
    191   std::string name() const { return "BM_Empty" + baseName(); }
    192 };
    193 
    194 struct Size : Base {
    195   using Base::Base;
    196 
    197   void run(benchmark::State& State) const {
    198     auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1);
    199     auto& Map = Data.Maps.front();
    200     for (auto _ : State) {
    201 #ifndef VALIDATE
    202       benchmark::DoNotOptimize(Map.size());
    203 #else
    204       if (Map.size() != MapSize)
    205         State.SkipWithError("Map contains an invalid number of elements.");
    206 #endif
    207     }
    208   }
    209 
    210   std::string name() const { return "BM_Size" + baseName(); }
    211 };
    212 
    213 //*******************************************************************|
    214 //                           Modifiers                               |
    215 //*******************************************************************|
    216 
    217 struct Clear : Base {
    218   using Base::Base;
    219 
    220   void run(benchmark::State& State) const {
    221     auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
    222     while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
    223       for (auto& Map : Data.Maps) {
    224         Map.clear();
    225         benchmark::DoNotOptimize(Map);
    226       }
    227       State.PauseTiming();
    228       Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
    229       State.ResumeTiming();
    230     }
    231   }
    232 
    233   std::string name() const { return "BM_Clear" + baseName(); }
    234 };
    235 
    236 template <class Mode, class Order>
    237 struct Insert : Base {
    238   using Base::Base;
    239 
    240   void run(benchmark::State& State) const {
    241     auto Data = makeTestingSets(
    242         MapSize, Mode(),
    243         Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
    244     while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
    245       for (auto& Map : Data.Maps) {
    246         for (auto K : Data.Keys) {
    247 #ifndef VALIDATE
    248           benchmark::DoNotOptimize(Map.insert(std::make_pair(K, 1)));
    249 #else
    250           bool Inserted = Map.insert(std::make_pair(K, 1)).second;
    251           if (Mode() == ::Mode::Hit) {
    252             if (Inserted)
    253               State.SkipWithError("Inserted a duplicate element");
    254           } else {
    255             if (!Inserted)
    256               State.SkipWithError("Failed to insert e new element");
    257           }
    258 #endif
    259         }
    260       }
    261 
    262       State.PauseTiming();
    263       Data = makeTestingSets(MapSize, Mode(),
    264                              Order::value == ::Order::Random ? Shuffle::Keys
    265                                                              : Shuffle::None,
    266                              1000);
    267       State.ResumeTiming();
    268     }
    269   }
    270 
    271   std::string name() const {
    272     return "BM_Insert" + baseName() + Mode::name() + Order::name();
    273   }
    274 };
    275 
    276 template <class Mode, class Hint>
    277 struct InsertHint : Base {
    278   using Base::Base;
    279 
    280   template < ::Hint hint>
    281   typename std::enable_if<hint == ::Hint::Correct>::type
    282   run(benchmark::State& State) const {
    283     auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
    284     while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
    285       for (size_t I = 0; I < Data.Maps.size(); ++I) {
    286         auto& Map = Data.Maps[I];
    287         auto H = Data.Hints[I].begin();
    288         for (auto K : Data.Keys) {
    289 #ifndef VALIDATE
    290           benchmark::DoNotOptimize(Map.insert(*H, std::make_pair(K, 1)));
    291 #else
    292           auto Inserted = Map.insert(*H, std::make_pair(K, 1));
    293           if (Mode() == ::Mode::Hit) {
    294             if (Inserted != *H)
    295               State.SkipWithError("Inserted a duplicate element");
    296           } else {
    297             if (++Inserted != *H)
    298               State.SkipWithError("Failed to insert a new element");
    299           }
    300 #endif
    301           ++H;
    302         }
    303       }
    304 
    305       State.PauseTiming();
    306       Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
    307       State.ResumeTiming();
    308     }
    309   }
    310 
    311   template < ::Hint hint>
    312   typename std::enable_if<hint != ::Hint::Correct>::type
    313   run(benchmark::State& State) const {
    314     auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
    315     while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
    316       for (size_t I = 0; I < Data.Maps.size(); ++I) {
    317         auto& Map = Data.Maps[I];
    318         auto Third = *(Data.Hints[I].begin() + 2);
    319         for (auto K : Data.Keys) {
    320           auto Itor = hint == ::Hint::Begin
    321                           ? Map.begin()
    322                           : hint == ::Hint::Third ? Third : Map.end();
    323 #ifndef VALIDATE
    324           benchmark::DoNotOptimize(Map.insert(Itor, std::make_pair(K, 1)));
    325 #else
    326           size_t Size = Map.size();
    327           Map.insert(Itor, std::make_pair(K, 1));
    328           if (Mode() == ::Mode::Hit) {
    329             if (Size != Map.size())
    330               State.SkipWithError("Inserted a duplicate element");
    331           } else {
    332             if (Size + 1 != Map.size())
    333               State.SkipWithError("Failed to insert a new element");
    334           }
    335 #endif
    336         }
    337       }
    338 
    339       State.PauseTiming();
    340       Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
    341       State.ResumeTiming();
    342     }
    343   }
    344 
    345   void run(benchmark::State& State) const {
    346     static constexpr auto h = Hint();
    347     run<h>(State);
    348   }
    349 
    350   std::string name() const {
    351     return "BM_InsertHint" + baseName() + Mode::name() + Hint::name();
    352   }
    353 };
    354 
    355 template <class Mode, class Order>
    356 struct InsertAssign : Base {
    357   using Base::Base;
    358 
    359   void run(benchmark::State& State) const {
    360     auto Data = makeTestingSets(
    361         MapSize, Mode(),
    362         Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
    363     while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
    364       for (auto& Map : Data.Maps) {
    365         for (auto K : Data.Keys) {
    366 #ifndef VALIDATE
    367           benchmark::DoNotOptimize(Map.insert_or_assign(K, 1));
    368 #else
    369           bool Inserted = Map.insert_or_assign(K, 1).second;
    370           if (Mode() == ::Mode::Hit) {
    371             if (Inserted)
    372               State.SkipWithError("Inserted a duplicate element");
    373           } else {
    374             if (!Inserted)
    375               State.SkipWithError("Failed to insert e new element");
    376           }
    377 #endif
    378         }
    379       }
    380 
    381       State.PauseTiming();
    382       Data = makeTestingSets(MapSize, Mode(),
    383                              Order::value == ::Order::Random ? Shuffle::Keys
    384                                                              : Shuffle::None,
    385                              1000);
    386       State.ResumeTiming();
    387     }
    388   }
    389 
    390   std::string name() const {
    391     return "BM_InsertAssign" + baseName() + Mode::name() + Order::name();
    392   }
    393 };
    394 
    395 template <class Mode, class Hint>
    396 struct InsertAssignHint : Base {
    397   using Base::Base;
    398 
    399   template < ::Hint hint>
    400   typename std::enable_if<hint == ::Hint::Correct>::type
    401   run(benchmark::State& State) const {
    402     auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
    403     while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
    404       for (size_t I = 0; I < Data.Maps.size(); ++I) {
    405         auto& Map = Data.Maps[I];
    406         auto H = Data.Hints[I].begin();
    407         for (auto K : Data.Keys) {
    408 #ifndef VALIDATE
    409           benchmark::DoNotOptimize(Map.insert_or_assign(*H, K, 1));
    410 #else
    411           auto Inserted = Map.insert_or_assign(*H, K, 1);
    412           if (Mode() == ::Mode::Hit) {
    413             if (Inserted != *H)
    414               State.SkipWithError("Inserted a duplicate element");
    415           } else {
    416             if (++Inserted != *H)
    417               State.SkipWithError("Failed to insert a new element");
    418           }
    419 #endif
    420           ++H;
    421         }
    422       }
    423 
    424       State.PauseTiming();
    425       Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
    426       State.ResumeTiming();
    427     }
    428   }
    429 
    430   template < ::Hint hint>
    431   typename std::enable_if<hint != ::Hint::Correct>::type
    432   run(benchmark::State& State) const {
    433     auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
    434     while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
    435       for (size_t I = 0; I < Data.Maps.size(); ++I) {
    436         auto& Map = Data.Maps[I];
    437         auto Third = *(Data.Hints[I].begin() + 2);
    438         for (auto K : Data.Keys) {
    439           auto Itor = hint == ::Hint::Begin
    440                           ? Map.begin()
    441                           : hint == ::Hint::Third ? Third : Map.end();
    442 #ifndef VALIDATE
    443           benchmark::DoNotOptimize(Map.insert_or_assign(Itor, K, 1));
    444 #else
    445           size_t Size = Map.size();
    446           Map.insert_or_assign(Itor, K, 1);
    447           if (Mode() == ::Mode::Hit) {
    448             if (Size != Map.size())
    449               State.SkipWithError("Inserted a duplicate element");
    450           } else {
    451             if (Size + 1 != Map.size())
    452               State.SkipWithError("Failed to insert a new element");
    453           }
    454 #endif
    455         }
    456       }
    457 
    458       State.PauseTiming();
    459       Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
    460       State.ResumeTiming();
    461     }
    462   }
    463 
    464   void run(benchmark::State& State) const {
    465     static constexpr auto h = Hint();
    466     run<h>(State);
    467   }
    468 
    469   std::string name() const {
    470     return "BM_InsertAssignHint" + baseName() + Mode::name() + Hint::name();
    471   }
    472 };
    473 
    474 template <class Mode, class Order>
    475 struct Emplace : Base {
    476   using Base::Base;
    477 
    478   void run(benchmark::State& State) const {
    479 
    480     auto Data = makeTestingSets(
    481         MapSize, Mode(),
    482         Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
    483     while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
    484       for (auto& Map : Data.Maps) {
    485         for (auto K : Data.Keys) {
    486 #ifndef VALIDATE
    487           benchmark::DoNotOptimize(Map.emplace(K, 1));
    488 #else
    489           bool Inserted = Map.emplace(K, 1).second;
    490           if (Mode() == ::Mode::Hit) {
    491             if (Inserted)
    492               State.SkipWithError("Emplaced a duplicate element");
    493           } else {
    494             if (!Inserted)
    495               State.SkipWithError("Failed to emplace a new element");
    496           }
    497 #endif
    498         }
    499       }
    500 
    501       State.PauseTiming();
    502       Data = makeTestingSets(MapSize, Mode(),
    503                              Order::value == ::Order::Random ? Shuffle::Keys
    504                                                              : Shuffle::None,
    505                              1000);
    506       State.ResumeTiming();
    507     }
    508   }
    509 
    510   std::string name() const {
    511     return "BM_Emplace" + baseName() + Mode::name() + Order::name();
    512   }
    513 };
    514 
    515 template <class Mode, class Hint>
    516 struct EmplaceHint : Base {
    517   using Base::Base;
    518 
    519   template < ::Hint hint>
    520   typename std::enable_if<hint == ::Hint::Correct>::type
    521   run(benchmark::State& State) const {
    522     auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
    523     while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
    524       for (size_t I = 0; I < Data.Maps.size(); ++I) {
    525         auto& Map = Data.Maps[I];
    526         auto H = Data.Hints[I].begin();
    527         for (auto K : Data.Keys) {
    528 #ifndef VALIDATE
    529           benchmark::DoNotOptimize(Map.emplace_hint(*H, K, 1));
    530 #else
    531           auto Inserted = Map.emplace_hint(*H, K, 1);
    532           if (Mode() == ::Mode::Hit) {
    533             if (Inserted != *H)
    534               State.SkipWithError("Emplaced a duplicate element");
    535           } else {
    536             if (++Inserted != *H)
    537               State.SkipWithError("Failed to emplace a new element");
    538           }
    539 #endif
    540           ++H;
    541         }
    542       }
    543 
    544       State.PauseTiming();
    545       Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
    546       State.ResumeTiming();
    547     }
    548   }
    549 
    550   template < ::Hint hint>
    551   typename std::enable_if<hint != ::Hint::Correct>::type
    552   run(benchmark::State& State) const {
    553     auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
    554     while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
    555       for (size_t I = 0; I < Data.Maps.size(); ++I) {
    556         auto& Map = Data.Maps[I];
    557         auto Third = *(Data.Hints[I].begin() + 2);
    558         for (auto K : Data.Keys) {
    559           auto Itor = hint == ::Hint::Begin
    560                           ? Map.begin()
    561                           : hint == ::Hint::Third ? Third : Map.end();
    562 #ifndef VALIDATE
    563           benchmark::DoNotOptimize(Map.emplace_hint(Itor, K, 1));
    564 #else
    565           size_t Size = Map.size();
    566           Map.emplace_hint(Itor, K, 1);
    567           if (Mode() == ::Mode::Hit) {
    568             if (Size != Map.size())
    569               State.SkipWithError("Emplaced a duplicate element");
    570           } else {
    571             if (Size + 1 != Map.size())
    572               State.SkipWithError("Failed to emplace a new element");
    573           }
    574 #endif
    575         }
    576       }
    577 
    578       State.PauseTiming();
    579       Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
    580       State.ResumeTiming();
    581     }
    582   }
    583 
    584   void run(benchmark::State& State) const {
    585     static constexpr auto h = Hint();
    586     run<h>(State);
    587   }
    588 
    589   std::string name() const {
    590     return "BM_EmplaceHint" + baseName() + Mode::name() + Hint::name();
    591   }
    592 };
    593 
    594 template <class Mode, class Order>
    595 struct TryEmplace : Base {
    596   using Base::Base;
    597 
    598   void run(benchmark::State& State) const {
    599 
    600     auto Data = makeTestingSets(
    601         MapSize, Mode(),
    602         Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
    603     while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
    604       for (auto& Map : Data.Maps) {
    605         for (auto K : Data.Keys) {
    606 #ifndef VALIDATE
    607           benchmark::DoNotOptimize(Map.try_emplace(K, 1));
    608 #else
    609           bool Inserted = Map.try_emplace(K, 1).second;
    610           if (Mode() == ::Mode::Hit) {
    611             if (Inserted)
    612               State.SkipWithError("Emplaced a duplicate element");
    613           } else {
    614             if (!Inserted)
    615               State.SkipWithError("Failed to emplace a new element");
    616           }
    617 #endif
    618         }
    619       }
    620 
    621       State.PauseTiming();
    622       Data = makeTestingSets(MapSize, Mode(),
    623                              Order::value == ::Order::Random ? Shuffle::Keys
    624                                                              : Shuffle::None,
    625                              1000);
    626       State.ResumeTiming();
    627     }
    628   }
    629 
    630   std::string name() const {
    631     return "BM_TryEmplace" + baseName() + Mode::name() + Order::name();
    632   }
    633 };
    634 
    635 template <class Mode, class Hint>
    636 struct TryEmplaceHint : Base {
    637   using Base::Base;
    638 
    639   template < ::Hint hint>
    640   typename std::enable_if<hint == ::Hint::Correct>::type
    641   run(benchmark::State& State) const {
    642     auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
    643     while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
    644       for (size_t I = 0; I < Data.Maps.size(); ++I) {
    645         auto& Map = Data.Maps[I];
    646         auto H = Data.Hints[I].begin();
    647         for (auto K : Data.Keys) {
    648 #ifndef VALIDATE
    649           benchmark::DoNotOptimize(Map.try_emplace(*H, K, 1));
    650 #else
    651           auto Inserted = Map.try_emplace(*H, K, 1);
    652           if (Mode() == ::Mode::Hit) {
    653             if (Inserted != *H)
    654               State.SkipWithError("Emplaced a duplicate element");
    655           } else {
    656             if (++Inserted != *H)
    657               State.SkipWithError("Failed to emplace a new element");
    658           }
    659 #endif
    660           ++H;
    661         }
    662       }
    663 
    664       State.PauseTiming();
    665       Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
    666       State.ResumeTiming();
    667     }
    668   }
    669 
    670   template < ::Hint hint>
    671   typename std::enable_if<hint != ::Hint::Correct>::type
    672   run(benchmark::State& State) const {
    673     auto Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
    674     while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
    675       for (size_t I = 0; I < Data.Maps.size(); ++I) {
    676         auto& Map = Data.Maps[I];
    677         auto Third = *(Data.Hints[I].begin() + 2);
    678         for (auto K : Data.Keys) {
    679           auto Itor = hint == ::Hint::Begin
    680                           ? Map.begin()
    681                           : hint == ::Hint::Third ? Third : Map.end();
    682 #ifndef VALIDATE
    683           benchmark::DoNotOptimize(Map.try_emplace(Itor, K, 1));
    684 #else
    685           size_t Size = Map.size();
    686           Map.try_emplace(Itor, K, 1);
    687           if (Mode() == ::Mode::Hit) {
    688             if (Size != Map.size())
    689               State.SkipWithError("Emplaced a duplicate element");
    690           } else {
    691             if (Size + 1 != Map.size())
    692               State.SkipWithError("Failed to emplace a new element");
    693           }
    694 #endif
    695         }
    696       }
    697 
    698       State.PauseTiming();
    699       Data = makeTestingSets(MapSize, Mode(), Shuffle::None, 1000);
    700       State.ResumeTiming();
    701     }
    702   }
    703 
    704   void run(benchmark::State& State) const {
    705     static constexpr auto h = Hint();
    706     run<h>(State);
    707   }
    708 
    709   std::string name() const {
    710     return "BM_TryEmplaceHint" + baseName() + Mode::name() + Hint::name();
    711   }
    712 };
    713 
    714 template <class Mode, class Order>
    715 struct Erase : Base {
    716   using Base::Base;
    717 
    718   void run(benchmark::State& State) const {
    719     auto Data = makeTestingSets(
    720         MapSize, Mode(),
    721         Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1000);
    722     while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
    723       for (auto& Map : Data.Maps) {
    724         for (auto K : Data.Keys) {
    725 #ifndef VALIDATE
    726           benchmark::DoNotOptimize(Map.erase(K));
    727 #else
    728           size_t I = Map.erase(K);
    729           if (Mode() == ::Mode::Hit) {
    730             if (I == 0)
    731               State.SkipWithError("Did not find the existing element");
    732           } else {
    733             if (I == 1)
    734               State.SkipWithError("Did find the non-existing element");
    735           }
    736 #endif
    737         }
    738       }
    739 
    740       State.PauseTiming();
    741       Data = makeTestingSets(MapSize, Mode(),
    742                              Order::value == ::Order::Random ? Shuffle::Keys
    743                                                              : Shuffle::None,
    744                              1000);
    745       State.ResumeTiming();
    746     }
    747   }
    748 
    749   std::string name() const {
    750     return "BM_Erase" + baseName() + Mode::name() + Order::name();
    751   }
    752 };
    753 
    754 template <class Order>
    755 struct EraseIterator : Base {
    756   using Base::Base;
    757 
    758   void run(benchmark::State& State) const {
    759     auto Data = makeTestingSets(
    760         MapSize, Mode::Hit,
    761         Order::value == ::Order::Random ? Shuffle::Hints : Shuffle::None, 1000);
    762     while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
    763       for (size_t I = 0; I < Data.Maps.size(); ++I) {
    764         auto& Map = Data.Maps[I];
    765         for (auto H : Data.Hints[I]) {
    766           benchmark::DoNotOptimize(Map.erase(H));
    767         }
    768 #ifdef VALIDATE
    769         if (!Map.empty())
    770           State.SkipWithError("Did not erase the entire map");
    771 #endif
    772       }
    773 
    774       State.PauseTiming();
    775       Data = makeTestingSets(MapSize, Mode::Hit,
    776                              Order::value == ::Order::Random ? Shuffle::Hints
    777                                                              : Shuffle::None,
    778                              1000);
    779       State.ResumeTiming();
    780     }
    781   }
    782 
    783   std::string name() const {
    784     return "BM_EraseIterator" + baseName() + Order::name();
    785   }
    786 };
    787 
    788 struct EraseRange : Base {
    789   using Base::Base;
    790 
    791   void run(benchmark::State& State) const {
    792     auto Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
    793     while (State.KeepRunningBatch(MapSize * Data.Maps.size())) {
    794       for (auto& Map : Data.Maps) {
    795 #ifndef VALIDATE
    796         benchmark::DoNotOptimize(Map.erase(Map.begin(), Map.end()));
    797 #else
    798         Map.erase(Map.begin(), Map.end());
    799         if (!Map.empty())
    800           State.SkipWithError("Did not erase the entire map");
    801 #endif
    802       }
    803 
    804       State.PauseTiming();
    805       Data = makeTestingSets(MapSize, Mode::Hit, Shuffle::None, 1000);
    806       State.ResumeTiming();
    807     }
    808   }
    809 
    810   std::string name() const { return "BM_EraseRange" + baseName(); }
    811 };
    812 
    813 //*******************************************************************|
    814 //                            Lookup                                 |
    815 //*******************************************************************|
    816 
    817 template <class Mode, class Order>
    818 struct Count : Base {
    819   using Base::Base;
    820 
    821   void run(benchmark::State& State) const {
    822     auto Data = makeTestingSets(
    823         MapSize, Mode(),
    824         Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1);
    825     auto& Map = Data.Maps.front();
    826     while (State.KeepRunningBatch(MapSize)) {
    827       for (auto K : Data.Keys) {
    828 #ifndef VALIDATE
    829         benchmark::DoNotOptimize(Map.count(K));
    830 #else
    831         size_t I = Map.count(K);
    832         if (Mode() == ::Mode::Hit) {
    833           if (I == 0)
    834             State.SkipWithError("Did not find the existing element");
    835         } else {
    836           if (I == 1)
    837             State.SkipWithError("Did find the non-existing element");
    838         }
    839 #endif
    840       }
    841     }
    842   }
    843 
    844   std::string name() const {
    845     return "BM_Count" + baseName() + Mode::name() + Order::name();
    846   }
    847 };
    848 
    849 template <class Mode, class Order>
    850 struct Find : Base {
    851   using Base::Base;
    852 
    853   void run(benchmark::State& State) const {
    854     auto Data = makeTestingSets(
    855         MapSize, Mode(),
    856         Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1);
    857     auto& Map = Data.Maps.front();
    858     while (State.KeepRunningBatch(MapSize)) {
    859       for (auto K : Data.Keys) {
    860 #ifndef VALIDATE
    861         benchmark::DoNotOptimize(Map.find(K));
    862 #else
    863         auto Itor = Map.find(K);
    864         if (Mode() == ::Mode::Hit) {
    865           if (Itor == Map.end())
    866             State.SkipWithError("Did not find the existing element");
    867         } else {
    868           if (Itor != Map.end())
    869             State.SkipWithError("Did find the non-existing element");
    870         }
    871 #endif
    872       }
    873     }
    874   }
    875 
    876   std::string name() const {
    877     return "BM_Find" + baseName() + Mode::name() + Order::name();
    878   }
    879 };
    880 
    881 template <class Mode, class Order>
    882 struct EqualRange : Base {
    883   using Base::Base;
    884 
    885   void run(benchmark::State& State) const {
    886     auto Data = makeTestingSets(
    887         MapSize, Mode(),
    888         Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1);
    889     auto& Map = Data.Maps.front();
    890     while (State.KeepRunningBatch(MapSize)) {
    891       for (auto K : Data.Keys) {
    892 #ifndef VALIDATE
    893         benchmark::DoNotOptimize(Map.equal_range(K));
    894 #else
    895         auto Range = Map.equal_range(K);
    896         if (Mode() == ::Mode::Hit) {
    897           // Adjust validation for the last element.
    898           auto Key = K;
    899           if (Range.second == Map.end() && K == 2 * MapSize) {
    900             --Range.second;
    901             Key -= 2;
    902           }
    903           if (Range.first == Map.end() || Range.first->first != K ||
    904               Range.second == Map.end() || Range.second->first - 2 != Key)
    905             State.SkipWithError("Did not find the existing element");
    906         } else {
    907           if (Range.first == Map.end() || Range.first->first - 1 != K ||
    908               Range.second == Map.end() || Range.second->first - 1 != K)
    909             State.SkipWithError("Did find the non-existing element");
    910         }
    911 #endif
    912       }
    913     }
    914   }
    915 
    916   std::string name() const {
    917     return "BM_EqualRange" + baseName() + Mode::name() + Order::name();
    918   }
    919 };
    920 
    921 template <class Mode, class Order>
    922 struct LowerBound : Base {
    923   using Base::Base;
    924 
    925   void run(benchmark::State& State) const {
    926     auto Data = makeTestingSets(
    927         MapSize, Mode(),
    928         Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1);
    929     auto& Map = Data.Maps.front();
    930     while (State.KeepRunningBatch(MapSize)) {
    931       for (auto K : Data.Keys) {
    932 #ifndef VALIDATE
    933         benchmark::DoNotOptimize(Map.lower_bound(K));
    934 #else
    935         auto Itor = Map.lower_bound(K);
    936         if (Mode() == ::Mode::Hit) {
    937           if (Itor == Map.end() || Itor->first != K)
    938             State.SkipWithError("Did not find the existing element");
    939         } else {
    940           if (Itor == Map.end() || Itor->first - 1 != K)
    941             State.SkipWithError("Did find the non-existing element");
    942         }
    943 #endif
    944       }
    945     }
    946   }
    947 
    948   std::string name() const {
    949     return "BM_LowerBound" + baseName() + Mode::name() + Order::name();
    950   }
    951 };
    952 
    953 template <class Mode, class Order>
    954 struct UpperBound : Base {
    955   using Base::Base;
    956 
    957   void run(benchmark::State& State) const {
    958     auto Data = makeTestingSets(
    959         MapSize, Mode(),
    960         Order::value == ::Order::Random ? Shuffle::Keys : Shuffle::None, 1);
    961     auto& Map = Data.Maps.front();
    962     while (State.KeepRunningBatch(MapSize)) {
    963       for (auto K : Data.Keys) {
    964 #ifndef VALIDATE
    965         benchmark::DoNotOptimize(Map.upper_bound(K));
    966 #else
    967         std::map<uint64_t, int64_t>::iterator Itor = Map.upper_bound(K);
    968         if (Mode() == ::Mode::Hit) {
    969           // Adjust validation for the last element.
    970           auto Key = K;
    971           if (Itor == Map.end() && K == 2 * MapSize) {
    972             --Itor;
    973             Key -= 2;
    974           }
    975           if (Itor == Map.end() || Itor->first - 2 != Key)
    976             State.SkipWithError("Did not find the existing element");
    977         } else {
    978           if (Itor == Map.end() || Itor->first - 1 != K)
    979             State.SkipWithError("Did find the non-existing element");
    980         }
    981 #endif
    982       }
    983     }
    984   }
    985 
    986   std::string name() const {
    987     return "BM_UpperBound" + baseName() + Mode::name() + Order::name();
    988   }
    989 };
    990 
    991 } // namespace
    992 
    993 int main(int argc, char** argv) {
    994   benchmark::Initialize(&argc, argv);
    995   if (benchmark::ReportUnrecognizedArguments(argc, argv))
    996     return 1;
    997 
    998 #ifdef VALIDATE
    999   const std::vector<size_t> MapSize{10};
   1000 #else
   1001   const std::vector<size_t> MapSize{10, 100, 1000, 10000, 100000, 1000000};
   1002 #endif
   1003 
   1004   // Member functions
   1005   makeCartesianProductBenchmark<ConstructorDefault>();
   1006   makeCartesianProductBenchmark<ConstructorIterator>(MapSize);
   1007   makeCartesianProductBenchmark<ConstructorCopy>(MapSize);
   1008   makeCartesianProductBenchmark<ConstructorMove>(MapSize);
   1009 
   1010   // Capacity
   1011   makeCartesianProductBenchmark<Empty>(MapSize);
   1012   makeCartesianProductBenchmark<Size>(MapSize);
   1013 
   1014   // Modifiers
   1015   makeCartesianProductBenchmark<Clear>(MapSize);
   1016   makeCartesianProductBenchmark<Insert, AllModes, AllOrders>(MapSize);
   1017   makeCartesianProductBenchmark<InsertHint, AllModes, AllHints>(MapSize);
   1018   makeCartesianProductBenchmark<InsertAssign, AllModes, AllOrders>(MapSize);
   1019   makeCartesianProductBenchmark<InsertAssignHint, AllModes, AllHints>(MapSize);
   1020 
   1021   makeCartesianProductBenchmark<Emplace, AllModes, AllOrders>(MapSize);
   1022   makeCartesianProductBenchmark<EmplaceHint, AllModes, AllHints>(MapSize);
   1023   makeCartesianProductBenchmark<TryEmplace, AllModes, AllOrders>(MapSize);
   1024   makeCartesianProductBenchmark<TryEmplaceHint, AllModes, AllHints>(MapSize);
   1025   makeCartesianProductBenchmark<Erase, AllModes, AllOrders>(MapSize);
   1026   makeCartesianProductBenchmark<EraseIterator, AllOrders>(MapSize);
   1027   makeCartesianProductBenchmark<EraseRange>(MapSize);
   1028 
   1029   // Lookup
   1030   makeCartesianProductBenchmark<Count, AllModes, AllOrders>(MapSize);
   1031   makeCartesianProductBenchmark<Find, AllModes, AllOrders>(MapSize);
   1032   makeCartesianProductBenchmark<EqualRange, AllModes, AllOrders>(MapSize);
   1033   makeCartesianProductBenchmark<LowerBound, AllModes, AllOrders>(MapSize);
   1034   makeCartesianProductBenchmark<UpperBound, AllModes, AllOrders>(MapSize);
   1035 
   1036   benchmark::RunSpecifiedBenchmarks();
   1037 }
   1038