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
| 6641 | /// This is effectively an implementation of std::function without any such optimizations; |
| 6642 | /// it may be slow, but it is consistently slow. |
| 6643 | struct BenchmarkFunction { |
| 6644 | private: |
| 6645 | struct callable { |
| 6646 | virtual void call(Chronometer meter) const = 0; |
| 6647 | virtual callable* clone() const = 0; |
| 6648 | virtual ~callable() = default; |
| 6649 | }; |
| 6650 | template <typename Fun> |
| 6651 | struct model : public callable { |
| 6652 | model(Fun&& fun) : fun(std::move(fun)) {} |
| 6653 | model(Fun const& fun) : fun(fun) {} |
| 6654 | |
| 6655 | model<Fun>* clone() const override { return new model<Fun>(*this); } |
| 6656 | |
| 6657 | void call(Chronometer meter) const override { |
| 6658 | call(meter, is_callable<Fun(Chronometer)>()); |
| 6659 | } |
| 6660 | void call(Chronometer meter, std::true_type) const { |
| 6661 | fun(meter); |
| 6662 | } |
| 6663 | void call(Chronometer meter, std::false_type) const { |
| 6664 | meter.measure(fun); |
| 6665 | } |
| 6666 | |
| 6667 | Fun fun; |
| 6668 | }; |
| 6669 | |
| 6670 | struct do_nothing { void operator()() const {} }; |
| 6671 | |
| 6672 | template <typename T> |
| 6673 | BenchmarkFunction(model<T>* c) : f(c) {} |
| 6674 | |
| 6675 | public: |
| 6676 | BenchmarkFunction() |
| 6677 | : f(new model<do_nothing>{ {} }) {} |
| 6678 | |
| 6679 | template <typename Fun, |
| 6680 | typename std::enable_if<!is_related<Fun, BenchmarkFunction>::value, int>::type = 0> |
| 6681 | BenchmarkFunction(Fun&& fun) |
| 6682 | : f(new model<typename std::decay<Fun>::type>(std::forward<Fun>(fun))) {} |
| 6683 | |
| 6684 | BenchmarkFunction(BenchmarkFunction&& that) |
| 6685 | : f(std::move(that.f)) {} |
| 6686 | |
| 6687 | BenchmarkFunction(BenchmarkFunction const& that) |
| 6688 | : f(that.f->clone()) {} |
| 6689 | |
| 6690 | BenchmarkFunction& operator=(BenchmarkFunction&& that) { |
| 6691 | f = std::move(that.f); |
| 6692 | return *this; |
| 6693 | } |
| 6694 | |
| 6695 | BenchmarkFunction& operator=(BenchmarkFunction const& that) { |
| 6696 | f.reset(that.f->clone()); |
| 6697 | return *this; |
| 6698 | } |
| 6699 | |
| 6700 | void operator()(Chronometer meter) const { f->call(meter); } |