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::functi
| 6696 | /// This is effectively an implementation of std::function without any such optimizations; |
| 6697 | /// it may be slow, but it is consistently slow. |
| 6698 | struct BenchmarkFunction { |
| 6699 | private: |
| 6700 | struct callable { |
| 6701 | virtual void call(Chronometer meter) const = 0; |
| 6702 | virtual callable* clone() const = 0; |
| 6703 | virtual ~callable() = default; |
| 6704 | }; |
| 6705 | template <typename Fun> |
| 6706 | struct model : public callable { |
| 6707 | model(Fun&& fun) : fun(std::move(fun)) {} |
| 6708 | model(Fun const& fun) : fun(fun) {} |
| 6709 | |
| 6710 | model<Fun>* clone() const override { return new model<Fun>(*this); } |
| 6711 | |
| 6712 | void call(Chronometer meter) const override { |
| 6713 | call(meter, is_callable<Fun(Chronometer)>()); |
| 6714 | } |
| 6715 | void call(Chronometer meter, std::true_type) const { |
| 6716 | fun(meter); |
| 6717 | } |
| 6718 | void call(Chronometer meter, std::false_type) const { |
| 6719 | meter.measure(fun); |
| 6720 | } |
| 6721 | |
| 6722 | Fun fun; |
| 6723 | }; |
| 6724 | |
| 6725 | struct do_nothing { void operator()() const {} }; |
| 6726 | |
| 6727 | template <typename T> |
| 6728 | BenchmarkFunction(model<T>* c) : f(c) {} |
| 6729 | |
| 6730 | public: |
| 6731 | BenchmarkFunction() |
| 6732 | : f(new model<do_nothing>{ {} }) {} |
| 6733 | |
| 6734 | template <typename Fun, |
| 6735 | typename std::enable_if<!is_related<Fun, BenchmarkFunction>::value, int>::type = 0> |
| 6736 | BenchmarkFunction(Fun&& fun) |
| 6737 | : f(new model<typename std::decay<Fun>::type>(std::forward<Fun>(fun))) {} |
| 6738 | |
| 6739 | BenchmarkFunction(BenchmarkFunction&& that) |
| 6740 | : f(std::move(that.f)) {} |
| 6741 | |
| 6742 | BenchmarkFunction(BenchmarkFunction const& that) |
| 6743 | : f(that.f->clone()) {} |
| 6744 | |
| 6745 | BenchmarkFunction& operator=(BenchmarkFunction&& that) { |
| 6746 | f = std::move(that.f); |
| 6747 | return *this; |
| 6748 | } |
| 6749 | |
| 6750 | BenchmarkFunction& operator=(BenchmarkFunction const& that) { |
| 6751 | f.reset(that.f->clone()); |
| 6752 | return *this; |
| 6753 | } |
| 6754 | |
| 6755 | void operator()(Chronometer meter) const { f->call(meter); } |