mtklein | 4a9426f | 2015-03-31 14:24:27 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2015 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
| 8 | #ifndef SkFunction_DEFINED |
| 9 | #define SkFunction_DEFINED |
| 10 | |
mtklein | 0d992db | 2015-05-06 07:40:25 -0700 | [diff] [blame] | 11 | // TODO: document, more pervasive move support in constructors, small-Fn optimization |
mtklein | 4a9426f | 2015-03-31 14:24:27 -0700 | [diff] [blame] | 12 | |
mtklein | 0d992db | 2015-05-06 07:40:25 -0700 | [diff] [blame] | 13 | #include "SkTemplates.h" |
mtklein | 4a9426f | 2015-03-31 14:24:27 -0700 | [diff] [blame] | 14 | #include "SkTypes.h" |
| 15 | |
| 16 | template <typename> class SkFunction; |
| 17 | |
| 18 | template <typename R, typename... Args> |
mtklein | 0d992db | 2015-05-06 07:40:25 -0700 | [diff] [blame] | 19 | class SkFunction<R(Args...)> { |
mtklein | 4a9426f | 2015-03-31 14:24:27 -0700 | [diff] [blame] | 20 | public: |
mtklein | 0d992db | 2015-05-06 07:40:25 -0700 | [diff] [blame] | 21 | SkFunction() {} |
mtklein | 4a9426f | 2015-03-31 14:24:27 -0700 | [diff] [blame] | 22 | |
| 23 | template <typename Fn> |
mtklein | 0d992db | 2015-05-06 07:40:25 -0700 | [diff] [blame] | 24 | SkFunction(const Fn& fn) : fFunction(SkNEW_ARGS(LambdaImpl<Fn>, (fn))) {} |
| 25 | |
| 26 | SkFunction(R (*fn)(Args...)) : fFunction(SkNEW_ARGS(FnPtrImpl, (fn))) {} |
| 27 | |
| 28 | SkFunction(const SkFunction& other) { *this = other; } |
| 29 | SkFunction& operator=(const SkFunction& other) { |
| 30 | if (this != &other) { |
| 31 | fFunction.reset(other.fFunction ? other.fFunction->clone() : nullptr); |
| 32 | } |
| 33 | return *this; |
mtklein | 4a9426f | 2015-03-31 14:24:27 -0700 | [diff] [blame] | 34 | } |
| 35 | |
mtklein | 0d992db | 2015-05-06 07:40:25 -0700 | [diff] [blame] | 36 | R operator()(Args... args) const { |
| 37 | SkASSERT(fFunction.get()); |
| 38 | return fFunction->call(Forward(args)...); |
mtklein | 97312d0 | 2015-04-01 08:11:16 -0700 | [diff] [blame] | 39 | } |
| 40 | |
mtklein | 4a9426f | 2015-03-31 14:24:27 -0700 | [diff] [blame] | 41 | private: |
mtklein | 7441527 | 2015-04-01 11:26:31 -0700 | [diff] [blame] | 42 | // ~= std::forward. This moves its argument if possible, falling back to a copy if not. |
| 43 | template <typename T> static T&& Forward(T& v) { return (T&&)v; } |
| 44 | |
mtklein | 0d992db | 2015-05-06 07:40:25 -0700 | [diff] [blame] | 45 | struct Interface { |
| 46 | virtual ~Interface() {} |
| 47 | virtual R call(Args...) const = 0; |
| 48 | virtual Interface* clone() const = 0; |
mtklein | 4a9426f | 2015-03-31 14:24:27 -0700 | [diff] [blame] | 49 | }; |
| 50 | |
mtklein | 4a9426f | 2015-03-31 14:24:27 -0700 | [diff] [blame] | 51 | template <typename Fn> |
mtklein | 0d992db | 2015-05-06 07:40:25 -0700 | [diff] [blame] | 52 | class LambdaImpl final : public Interface { |
| 53 | public: |
| 54 | LambdaImpl(const Fn& fn) : fFn(fn) {} |
mtklein | 4a9426f | 2015-03-31 14:24:27 -0700 | [diff] [blame] | 55 | |
mtklein | 0d992db | 2015-05-06 07:40:25 -0700 | [diff] [blame] | 56 | R call(Args... args) const override { return fFn(Forward(args)...); } |
| 57 | Interface* clone() const { return SkNEW_ARGS(LambdaImpl<Fn>, (fFn)); } |
| 58 | private: |
| 59 | Fn fFn; |
| 60 | }; |
mtklein | 97312d0 | 2015-04-01 08:11:16 -0700 | [diff] [blame] | 61 | |
mtklein | 0d992db | 2015-05-06 07:40:25 -0700 | [diff] [blame] | 62 | class FnPtrImpl final : public Interface { |
| 63 | public: |
| 64 | FnPtrImpl(R (*fn)(Args...)) : fFn(fn) {} |
mtklein | 97312d0 | 2015-04-01 08:11:16 -0700 | [diff] [blame] | 65 | |
mtklein | 0d992db | 2015-05-06 07:40:25 -0700 | [diff] [blame] | 66 | R call(Args... args) const override { return fFn(Forward(args)...); } |
| 67 | Interface* clone() const { return SkNEW_ARGS(FnPtrImpl, (fFn)); } |
| 68 | private: |
| 69 | R (*fFn)(Args...); |
| 70 | }; |
| 71 | |
| 72 | SkAutoTDelete<Interface> fFunction; |
mtklein | 4a9426f | 2015-03-31 14:24:27 -0700 | [diff] [blame] | 73 | }; |
| 74 | |
mtklein | 4a9426f | 2015-03-31 14:24:27 -0700 | [diff] [blame] | 75 | #endif//SkFunction_DEFINED |