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 |