/* * Created by Joachim on 16/04/2019. * Adapted from donated nonius code. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ // Dumb std::function implementation for consistent call overhead #ifndef TWOBLUECUBES_CATCH_DETAIL_BENCHMARK_FUNCTION_HPP_INCLUDED #define TWOBLUECUBES_CATCH_DETAIL_BENCHMARK_FUNCTION_HPP_INCLUDED #include "../catch_chronometer.hpp" #include "catch_complete_invoke.hpp" #include "../../catch_meta.hpp" #include #include #include #include namespace Catch { namespace Benchmark { namespace Detail { template using Decay = typename std::decay::type; template struct is_related : std::is_same, Decay> {}; /// We need to reinvent std::function because every piece of code that might add overhead /// in a measurement context needs to have consistent performance characteristics so that we /// can account for it in the measurement. /// Implementations of std::function with optimizations that aren't always applicable, like /// small buffer optimizations, are not uncommon. /// This is effectively an implementation of std::function without any such optimizations; /// it may be slow, but it is consistently slow. struct BenchmarkFunction { private: struct callable { virtual void call(Chronometer meter) const = 0; virtual callable* clone() const = 0; virtual ~callable() = default; }; template struct model : public callable { model(Fun&& fun) : fun(std::move(fun)) {} model(Fun const& fun) : fun(fun) {} model* clone() const override { return new model(*this); } void call(Chronometer meter) const override { call(meter, is_callable()); } void call(Chronometer meter, std::true_type) const { fun(meter); } void call(Chronometer meter, std::false_type) const { meter.measure(fun); } Fun fun; }; struct do_nothing { void operator()() const {} }; template BenchmarkFunction(model* c) : f(c) {} public: BenchmarkFunction() : f(new model{ {} }) {} template ::value, int>::type = 0> BenchmarkFunction(Fun&& fun) : f(new model::type>(std::forward(fun))) {} BenchmarkFunction(BenchmarkFunction&& that) : f(std::move(that.f)) {} BenchmarkFunction(BenchmarkFunction const& that) : f(that.f->clone()) {} BenchmarkFunction& operator=(BenchmarkFunction&& that) { f = std::move(that.f); return *this; } BenchmarkFunction& operator=(BenchmarkFunction const& that) { f.reset(that.f->clone()); return *this; } void operator()(Chronometer meter) const { f->call(meter); } private: std::unique_ptr f; }; } // namespace Detail } // namespace Benchmark } // namespace Catch #endif // TWOBLUECUBES_CATCH_DETAIL_BENCHMARK_FUNCTION_HPP_INCLUDED