| #include <array> | |
| #include <algorithm> | |
| #include <cassert> | |
| #include <cstdint> | |
| #include <tuple> | |
| #include <vector> | |
| #include "benchmark/benchmark.h" | |
| #include "CartesianBenchmarks.h" | |
| #include "GenerateInput.h" | |
| namespace { | |
| template <typename I, typename N> | |
| std::array<I, 10> every_10th_percentile_N(I first, N n) { | |
| N step = n / 10; | |
| std::array<I, 10> res; | |
| for (size_t i = 0; i < 10; ++i) { | |
| res[i] = first; | |
| std::advance(first, step); | |
| } | |
| return res; | |
| } | |
| template <class IntT> | |
| struct TestIntBase { | |
| static std::vector<IntT> generateInput(size_t size) { | |
| std::vector<IntT> Res(size); | |
| std::generate(Res.begin(), Res.end(), | |
| [] { return getRandomInteger<IntT>(); }); | |
| return Res; | |
| } | |
| }; | |
| struct TestInt32 : TestIntBase<std::int32_t> { | |
| static constexpr const char* Name = "TestInt32"; | |
| }; | |
| struct TestInt64 : TestIntBase<std::int64_t> { | |
| static constexpr const char* Name = "TestInt64"; | |
| }; | |
| struct TestUint32 : TestIntBase<std::uint32_t> { | |
| static constexpr const char* Name = "TestUint32"; | |
| }; | |
| struct TestMediumString { | |
| static constexpr const char* Name = "TestMediumString"; | |
| static constexpr size_t StringSize = 32; | |
| static std::vector<std::string> generateInput(size_t size) { | |
| std::vector<std::string> Res(size); | |
| std::generate(Res.begin(), Res.end(), [] { return getRandomString(StringSize); }); | |
| return Res; | |
| } | |
| }; | |
| using AllTestTypes = std::tuple<TestInt32, TestInt64, TestUint32, TestMediumString>; | |
| struct LowerBoundAlg { | |
| template <class I, class V> | |
| I operator()(I first, I last, const V& value) const { | |
| return std::lower_bound(first, last, value); | |
| } | |
| static constexpr const char* Name = "LowerBoundAlg"; | |
| }; | |
| struct UpperBoundAlg { | |
| template <class I, class V> | |
| I operator()(I first, I last, const V& value) const { | |
| return std::upper_bound(first, last, value); | |
| } | |
| static constexpr const char* Name = "UpperBoundAlg"; | |
| }; | |
| struct EqualRangeAlg { | |
| template <class I, class V> | |
| std::pair<I, I> operator()(I first, I last, const V& value) const { | |
| return std::equal_range(first, last, value); | |
| } | |
| static constexpr const char* Name = "EqualRangeAlg"; | |
| }; | |
| using AllAlgs = std::tuple<LowerBoundAlg, UpperBoundAlg, EqualRangeAlg>; | |
| template <class Alg, class TestType> | |
| struct PartitionPointBench { | |
| size_t Quantity; | |
| std::string name() const { | |
| return std::string("PartitionPointBench_") + Alg::Name + "_" + | |
| TestType::Name + '/' + std::to_string(Quantity); | |
| } | |
| void run(benchmark::State& state) const { | |
| auto Data = TestType::generateInput(Quantity); | |
| std::sort(Data.begin(), Data.end()); | |
| auto Every10Percentile = every_10th_percentile_N(Data.begin(), Data.size()); | |
| for (auto _ : state) { | |
| for (auto Test : Every10Percentile) | |
| benchmark::DoNotOptimize(Alg{}(Data.begin(), Data.end(), *Test)); | |
| } | |
| } | |
| }; | |
| } // namespace | |
| int main(int argc, char** argv) { | |
| benchmark::Initialize(&argc, argv); | |
| if (benchmark::ReportUnrecognizedArguments(argc, argv)) | |
| return 1; | |
| const std::vector<size_t> Quantities = {1 << 8, 1 << 10, 1 << 20}; | |
| makeCartesianProductBenchmark<PartitionPointBench, AllAlgs, AllTestTypes>( | |
| Quantities); | |
| benchmark::RunSpecifiedBenchmarks(); | |
| } |