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