#include <array> #include <algorithm> #include <cassert> #include <cstdint> #include <tuple> #include <vector> #include "benchmark/benchmark.h" #include "CartesianBenchmarks.hpp" #include "GenerateInput.hpp" 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(); }