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
| 6485 | /// This is effectively an implementation of std::function without any such optimizations; |
| 6486 | /// it may be slow, but it is consistently slow. |
| 6487 | struct BenchmarkFunction { |
| 6488 | private: |
| 6489 | struct callable { |
| 6490 | virtual void call(Chronometer meter) const = 0; |
| 6491 | virtual callable* clone() const = 0; |
| 6492 | virtual ~callable() = default; |
| 6493 | }; |
| 6494 | template <typename Fun> |
| 6495 | struct model : public callable { |
| 6496 | model(Fun&& fun) : fun(std::move(fun)) {} |
| 6497 | model(Fun const& fun) : fun(fun) {} |
| 6498 | |
| 6499 | model<Fun>* clone() const override { return new model<Fun>(*this); } |
| 6500 | |
| 6501 | void call(Chronometer meter) const override { |
| 6502 | call(meter, is_callable<Fun(Chronometer)>()); |
| 6503 | } |
| 6504 | void call(Chronometer meter, std::true_type) const { |
| 6505 | fun(meter); |
| 6506 | } |
| 6507 | void call(Chronometer meter, std::false_type) const { |
| 6508 | meter.measure(fun); |
| 6509 | } |
| 6510 | |
| 6511 | Fun fun; |
| 6512 | }; |
| 6513 | |
| 6514 | struct do_nothing { void operator()() const {} }; |
| 6515 | |
| 6516 | template <typename T> |
| 6517 | BenchmarkFunction(model<T>* c) : f(c) {} |
| 6518 | |
| 6519 | public: |
| 6520 | BenchmarkFunction() |
| 6521 | : f(new model<do_nothing>{ {} }) {} |
| 6522 | |
| 6523 | template <typename Fun, |
| 6524 | typename std::enable_if<!is_related<Fun, BenchmarkFunction>::value, int>::type = 0> |
| 6525 | BenchmarkFunction(Fun&& fun) |
| 6526 | : f(new model<typename std::decay<Fun>::type>(std::forward<Fun>(fun))) {} |
| 6527 | |
| 6528 | BenchmarkFunction(BenchmarkFunction&& that) |
| 6529 | : f(std::move(that.f)) {} |
| 6530 | |
| 6531 | BenchmarkFunction(BenchmarkFunction const& that) |
| 6532 | : f(that.f->clone()) {} |
| 6533 | |
| 6534 | BenchmarkFunction& operator=(BenchmarkFunction&& that) { |
| 6535 | f = std::move(that.f); |
| 6536 | return *this; |
| 6537 | } |
| 6538 | |
| 6539 | BenchmarkFunction& operator=(BenchmarkFunction const& that) { |
| 6540 | f.reset(that.f->clone()); |
| 6541 | return *this; |
| 6542 | } |
| 6543 | |
| 6544 | void operator()(Chronometer meter) const { f->call(meter); } |