| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | #include <string> |
| | #include <tuple> |
| | #include <type_traits> |
| | #include <vector> |
| |
|
| | #include "benchmark/benchmark.h" |
| | #include "test_macros.h" |
| |
|
| | namespace internal { |
| |
|
| | template <class D, class E, size_t I> |
| | struct EnumValue : std::integral_constant<E, static_cast<E>(I)> { |
| | static std::string name() { return std::string("_") + D::Names[I]; } |
| | }; |
| |
|
| | template <class D, class E, size_t ...Idxs> |
| | constexpr auto makeEnumValueTuple(std::index_sequence<Idxs...>) { |
| | return std::make_tuple(EnumValue<D, E, Idxs>{}...); |
| | } |
| |
|
| | template <class B> |
| | static auto skip(const B& Bench, int) -> decltype(Bench.skip()) { |
| | return Bench.skip(); |
| | } |
| | template <class B> |
| | static auto skip(const B& Bench, char) { |
| | return false; |
| | } |
| |
|
| | template <class B, class Args, size_t... Is> |
| | void makeBenchmarkFromValuesImpl(const Args& A, std::index_sequence<Is...>) { |
| | for (auto& V : A) { |
| | B Bench{std::get<Is>(V)...}; |
| | if (!internal::skip(Bench, 0)) { |
| | benchmark::RegisterBenchmark(Bench.name().c_str(), |
| | [=](benchmark::State& S) { Bench.run(S); }); |
| | } |
| | } |
| | } |
| |
|
| | template <class B, class... Args> |
| | void makeBenchmarkFromValues(const std::vector<std::tuple<Args...> >& A) { |
| | makeBenchmarkFromValuesImpl<B>(A, std::index_sequence_for<Args...>()); |
| | } |
| |
|
| | template <template <class...> class B, class Args, class... U> |
| | void makeBenchmarkImpl(const Args& A, std::tuple<U...> t) { |
| | makeBenchmarkFromValues<B<U...> >(A); |
| | } |
| |
|
| | template <template <class...> class B, class Args, class... U, |
| | class... T, class... Tuples> |
| | void makeBenchmarkImpl(const Args& A, std::tuple<U...>, std::tuple<T...>, |
| | Tuples... rest) { |
| | (internal::makeBenchmarkImpl<B>(A, std::tuple<U..., T>(), rest...), ...); |
| | } |
| |
|
| | template <class R, class T> |
| | void allValueCombinations(R& Result, const T& Final) { |
| | return Result.push_back(Final); |
| | } |
| |
|
| | template <class R, class T, class V, class... Vs> |
| | void allValueCombinations(R& Result, const T& Prev, const V& Value, |
| | const Vs&... Values) { |
| | for (const auto& E : Value) { |
| | allValueCombinations(Result, std::tuple_cat(Prev, std::make_tuple(E)), |
| | Values...); |
| | } |
| | } |
| |
|
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | template <class Derived, class EnumType, size_t NumLabels> |
| | using EnumValuesAsTuple = |
| | decltype(internal::makeEnumValueTuple<Derived, EnumType>( |
| | std::make_index_sequence<NumLabels>{})); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | template <template <class...> class B, class... Tuples, class... Args> |
| | int makeCartesianProductBenchmark(const Args&... A) { |
| | std::vector<std::tuple<typename Args::value_type...> > V; |
| | internal::allValueCombinations(V, std::tuple<>(), A...); |
| | internal::makeBenchmarkImpl<B>(V, std::tuple<>(), Tuples()...); |
| | return 0; |
| | } |
| |
|
| | template <class B, class... Args> |
| | int makeCartesianProductBenchmark(const Args&... A) { |
| | std::vector<std::tuple<typename Args::value_type...> > V; |
| | internal::allValueCombinations(V, std::tuple<>(), A...); |
| | internal::makeBenchmarkFromValues<B>(V); |
| | return 0; |
| | } |
| |
|
| | |
| | |
| | |
| | template <class T> |
| | TEST_ALWAYS_INLINE inline T maybeOpaque(T value, bool opaque) { |
| | if (opaque) benchmark::DoNotOptimize(value); |
| | return value; |
| | } |
| |
|
| |
|