#ifndef LIBDIOL_API_HEADER_GUARD #define LIBDIOL_API_HEADER_GUARD #include "diol.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace diol { namespace detail { template void for_each_impl(std::index_sequence, F &&f, std::tuple const &tup) { int _unused[] = {0, (f(std::get(tup)), 0)...}; } } // namespace detail template struct Tuple { std::tuple inner; Tuple(std::tuple inner) : inner{std::move(inner)} {} friend std::ostream &operator<<(std::ostream &os, Tuple const &tup) { os << "["; char const *sep = ""; detail::for_each_impl( std::make_index_sequence{}, [&](auto const &elem) { os << sep << elem; sep = ", "; }, tup.inner); os << "]"; return os; } template friend decltype(auto) get(Tuple const &t) { return std::get(t.inner); } template friend decltype(auto) get(Tuple &t) { return std::get(t.inner); } template friend decltype(auto) get(Tuple const &&t) { return std::get(std::move(t.inner)); } template friend decltype(auto) get(Tuple &&t) { return std::get(std::move(t.inner)); } }; using Monotonicity = LibDiolMonotonicity; template using Ptr = T *; template using FnPtr = void (*)(Ts...); struct PlotArg { constexpr PlotArg(std::uintptr_t n) noexcept : n{n} {} std::uintptr_t n; friend std::ostream &operator<<(std::ostream &os, PlotArg arg) { os << arg.n; return os; } }; struct Bencher { Bencher() = delete; Bencher(Bencher const &) = delete; Bencher &operator=(Bencher const &) = delete; Bencher(Bencher &&) = delete; Bencher &operator=(Bencher &&) = delete; template void bench(F f) && { libdiol_bencher_bench( this->ptr, [](void *data) { std::move (*static_cast(data))(); }, static_cast(std::addressof(f))); } private: explicit Bencher(LibDiolBencher *ptr) noexcept : ptr{ptr} {} friend struct Bench; LibDiolBencher *ptr; }; template struct Function { std::string name; FnPtr f; }; struct BenchConfig { ~BenchConfig() noexcept { if (this->ptr != nullptr) { libdiol_config_drop(this->ptr); } } BenchConfig() noexcept : ptr{nullptr} {} BenchConfig(BenchConfig const &bench) = delete; BenchConfig &operator=(BenchConfig const &bench) = delete; BenchConfig(BenchConfig &&bench) noexcept : ptr{bench.ptr} { bench.ptr = nullptr; } BenchConfig &operator=(BenchConfig &&bench) noexcept { if (&bench != this) { auto __tmp = std::move(*this); this->ptr = bench.ptr; bench.ptr = nullptr; } return *this; } static BenchConfig from_args() { auto config = libdiol_config_from_args(); return BenchConfig{config}; } void set_metric(std::string name, Monotonicity mono, double (*metric)(std::uintptr_t n, double time_secs)) { libdiol_config_set_metric(this->ptr, LibDiolStringUtf8Ref{ name.data(), name.size(), }, mono, metric); } private: explicit BenchConfig(LibDiolConfig *ptr) : ptr{ptr} {} friend struct Bench; LibDiolConfig *ptr; }; struct Bench { ~Bench() noexcept { if (this->ptr != nullptr) { libdiol_bench_drop(this->ptr); } } Bench() noexcept : ptr{nullptr} {} Bench(Bench const &bench) = delete; Bench &operator=(Bench const &bench) = delete; Bench(Bench &&bench) noexcept : ptr{bench.ptr} { bench.ptr = nullptr; } Bench &operator=(Bench &&bench) noexcept { if (&bench != this) { auto __tmp = std::move(*this); this->ptr = bench.ptr; bench.ptr = nullptr; } return *this; } static Bench from_config(BenchConfig const &config) { auto bench = libdiol_bench_from_config(config.ptr); return Bench{bench}; } template void register_funcs(std::span> funcs, std::span args) { std::vector func_names; std::vector func_data; std::vector> func_ptrs; std::vector arg_ptrs; func_names.reserve(funcs.size()); func_data.reserve(funcs.size()); func_ptrs.reserve(funcs.size()); arg_ptrs.reserve(args.size()); for (std::size_t i = 0; i < funcs.size(); ++i) { func_names.push_back(LibDiolStringUtf8Ref{ funcs[i].name.data(), funcs[i].name.size(), }); func_data.push_back(reinterpret_cast(funcs[i].f)); func_ptrs.push_back([](void const *func_data, LibDiolBencher *bencher, void *arg) { auto ptr = reinterpret_cast>(const_cast(func_data)); (*ptr)(Bencher{bencher}, static_cast(*static_cast(arg))); }); } for (std::size_t i = 0; i < args.size(); ++i) { arg_ptrs.push_back(std::addressof(args[i])); } libdiol_bench_register( this->ptr, func_names.data(), func_data.data(), func_ptrs.data(), funcs.size(), arg_ptrs.data(), args.size(), +[](void const *ptr) { return static_cast(new T(*Ptr(ptr))); }, +[](void *ptr) { delete Ptr(ptr); }, +[](void const *ptr) { std::ostringstream s; s << (*Ptr(ptr)); std::string str = std::move(s).str(); auto data = static_cast(std::malloc(str.size())); std::memcpy(data, str.data(), str.size()); return LibDiolStringUtf8{ data, str.size(), +[](char *ptr, std::uintptr_t) { std::free(ptr); }}; }, std::is_same::value); } void run() { libdiol_bench_run(this->ptr); } private: explicit Bench(LibDiolBench *ptr) : ptr{ptr} {} LibDiolBench *ptr; }; } // namespace diol namespace std { template struct tuple_size> : tuple_size> {}; template struct tuple_element> : tuple_element> {}; } // namespace std #endif /* LIBDIOL_API_HEADER_GUARD */