| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #ifndef SkFunction_DEFINED | 8 #ifndef SkFunction_DEFINED |
| 9 #define SkFunction_DEFINED | 9 #define SkFunction_DEFINED |
| 10 | 10 |
| 11 // TODO: document | 11 // TODO: document |
| 12 | 12 |
| 13 #include "SkTypes.h" | 13 #include "SkTypes.h" |
| 14 #include "SkTLogic.h" | 14 #include "SkTLogic.h" |
| 15 | 15 |
| 16 template <typename> class SkFunction; | 16 template <typename> class SkFunction; |
| 17 | 17 |
| 18 template <typename R, typename... Args> | 18 template <typename R, typename... Args> |
| 19 class SkFunction<R(Args...)> : SkNoncopyable { | 19 class SkFunction<R(Args...)> : SkNoncopyable { |
| 20 public: | 20 public: |
| 21 explicit SkFunction(R (*fn)(Args...)) : fVTable(GetFunctionPointerVTable())
{ | 21 explicit SkFunction(R (*fn)(Args...)) : fVTable(GetFunctionPointerVTable())
{ |
| 22 // We've been passed a function pointer. We'll just store it. | 22 // We've been passed a function pointer. We'll just store it. |
| 23 fFunction = reinterpret_cast<void*>(fn); | 23 fFunction = reinterpret_cast<void*>(fn); |
| 24 } | 24 } |
| 25 | 25 |
| 26 template <typename Fn> | 26 template <typename Fn> |
| 27 explicit SkFunction(Fn fn, SK_WHEN_C((sizeof(Fn) > sizeof(void*)), void*) =
nullptr) | 27 explicit SkFunction(Fn fn, SK_WHEN_C((sizeof(Fn) > sizeof(void*)), void*) =
nullptr) |
| 28 : fVTable(GetOutlineVTable<Fn>()) { | 28 : fVTable(GetOutlineVTable<Fn>()) { |
| 29 // We've got a functor larger than a pointer. We've go to copy it onto
the heap. | 29 // We've got a functor larger than a pointer. We've go to copy it onto
the heap. |
| 30 fFunction = SkNEW_ARGS(Fn, (fn)); | 30 fFunction = SkNEW_ARGS(Fn, (Forward(fn))); |
| 31 } | 31 } |
| 32 | 32 |
| 33 template <typename Fn> | 33 template <typename Fn> |
| 34 explicit SkFunction(Fn fn, SK_WHEN_C((sizeof(Fn) <= sizeof(void*)), void*) =
nullptr) | 34 explicit SkFunction(Fn fn, SK_WHEN_C((sizeof(Fn) <= sizeof(void*)), void*) =
nullptr) |
| 35 : fVTable(GetInlineVTable<Fn>()) { | 35 : fVTable(GetInlineVTable<Fn>()) { |
| 36 // We've got a functor that fits in a pointer. We copy it right inline. | 36 // We've got a functor that fits in a pointer. We copy it right inline. |
| 37 SkNEW_PLACEMENT_ARGS(&fFunction, Fn, (fn)); | 37 fFunction = NULL; // Quiets a (spurious) warning that fFunction might b
e uninitialized. |
| 38 SkNEW_PLACEMENT_ARGS(&fFunction, Fn, (Forward(fn))); |
| 38 } | 39 } |
| 39 | 40 |
| 40 ~SkFunction() { fVTable.fCleanUp(fFunction); } | 41 ~SkFunction() { fVTable.fCleanUp(fFunction); } |
| 41 | 42 |
| 42 R operator()(Args... args) { return fVTable.fCall(fFunction, args...); } | 43 R operator()(Args... args) { return fVTable.fCall(fFunction, Forward(args)..
.); } |
| 43 | 44 |
| 44 private: | 45 private: |
| 46 // ~= std::forward. This moves its argument if possible, falling back to a
copy if not. |
| 47 template <typename T> static T&& Forward(T& v) { return (T&&)v; } |
| 48 |
| 45 struct VTable { | 49 struct VTable { |
| 46 R (*fCall)(void*, Args...); | 50 R (*fCall)(void*, Args...); |
| 47 void (*fCleanUp)(void*); | 51 void (*fCleanUp)(void*); |
| 48 }; | 52 }; |
| 49 | 53 |
| 50 // Used when fFunction is a function pointer of type R(*)(Args...). | 54 // Used when fFunction is a function pointer of type R(*)(Args...). |
| 51 static const VTable& GetFunctionPointerVTable() { | 55 static const VTable& GetFunctionPointerVTable() { |
| 52 static const VTable vtable = { | 56 static const VTable vtable = { |
| 53 [](void* fn, Args... args) { return reinterpret_cast<R(*)(Args...)>(
fn)(args...); }, | 57 [](void* fn, Args... args) { |
| 58 return reinterpret_cast<R(*)(Args...)>(fn)(Forward(args)...); |
| 59 }, |
| 54 [](void*) { /* Nothing to clean up for function pointers. */ } | 60 [](void*) { /* Nothing to clean up for function pointers. */ } |
| 55 }; | 61 }; |
| 56 return vtable; | 62 return vtable; |
| 57 } | 63 } |
| 58 | 64 |
| 59 // Used when fFunction is a pointer to a functor of type Fn on the heap (we
own it). | 65 // Used when fFunction is a pointer to a functor of type Fn on the heap (we
own it). |
| 60 template <typename Fn> | 66 template <typename Fn> |
| 61 static const VTable& GetOutlineVTable() { | 67 static const VTable& GetOutlineVTable() { |
| 62 static const VTable vtable = { | 68 static const VTable vtable = { |
| 63 [](void* fn, Args... args) { return (*static_cast<Fn*>(fn))(args...)
; }, | 69 [](void* fn, Args... args) { return (*static_cast<Fn*>(fn))(Forward(
args)...); }, |
| 64 [](void* fn) { SkDELETE(static_cast<Fn*>(fn)); }, | 70 [](void* fn) { SkDELETE(static_cast<Fn*>(fn)); }, |
| 65 }; | 71 }; |
| 66 return vtable; | 72 return vtable; |
| 67 } | 73 } |
| 68 | 74 |
| 69 // Used when fFunction _is_ a functor of type Fn, not a pointer to the funct
or. | 75 // Used when fFunction _is_ a functor of type Fn, not a pointer to the funct
or. |
| 70 template <typename Fn> | 76 template <typename Fn> |
| 71 static const VTable& GetInlineVTable() { | 77 static const VTable& GetInlineVTable() { |
| 72 static const VTable vtable = { | 78 static const VTable vtable = { |
| 73 [](void* fn, Args... args) { | 79 [](void* fn, Args... args) { |
| 74 union { void* p; Fn f; } pun = { fn }; | 80 union { void** p; Fn* f; } pun = { &fn }; |
| 75 return pun.f(args...); | 81 return (*pun.f)(Forward(args)...); |
| 76 }, | 82 }, |
| 77 [](void* fn) { | 83 [](void* fn) { |
| 78 union { void* p; Fn f; } pun = { fn }; | 84 union { void** p; Fn* f; } pun = { &fn }; |
| 79 pun.f.~Fn(); | 85 (*pun.f).~Fn(); |
| 80 (void)(pun.f); // Otherwise, when ~Fn() is trivial, MSVC compl
ains pun is unused. | 86 (void)(pun.f); // Otherwise, when ~Fn() is trivial, MSVC compl
ains pun is unused. |
| 81 } | 87 } |
| 82 }; | 88 }; |
| 83 return vtable; | 89 return vtable; |
| 84 } | 90 } |
| 85 | 91 |
| 86 | 92 |
| 87 void* fFunction; // A function pointer, a pointer to a functor, or an
inlined functor. | 93 void* fFunction; // A function pointer, a pointer to a functor, or an
inlined functor. |
| 88 const VTable& fVTable; // How to call, delete (and one day copy, move) fFun
ction. | 94 const VTable& fVTable; // How to call, delete (and one day copy, move) fFun
ction. |
| 89 }; | 95 }; |
| 90 | 96 |
| 91 // TODO: | 97 // TODO: |
| 92 // - is it worth moving fCall out of the VTable into SkFunction itself to avoi
d the indirection? | 98 // - is it worth moving fCall out of the VTable into SkFunction itself to avoi
d the indirection? |
| 93 // - should constructors be implicit? | 99 // - should constructors be implicit? |
| 94 // - make SkFunction copyable | 100 // - make SkFunction copyable |
| 95 // - emulate std::forward for moveable functors (e.g. lambdas) | |
| 96 // - forward args too? | |
| 97 | 101 |
| 98 #endif//SkFunction_DEFINED | 102 #endif//SkFunction_DEFINED |
| OLD | NEW |