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 | 15 |
15 template <typename> class SkFunction; | 16 template <typename> class SkFunction; |
16 | 17 |
17 template <typename R, typename... Args> | 18 template <typename R, typename... Args> |
18 class SkFunction<R(Args...)> : SkNoncopyable { | 19 class SkFunction<R(Args...)> : SkNoncopyable { |
19 public: | 20 public: |
20 explicit SkFunction(R (*fn)(Args...)) : fVTable(GetFunctionPointerVTable())
{ | 21 explicit SkFunction(R (*fn)(Args...)) : fVTable(GetFunctionPointerVTable())
{ |
21 // 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. |
22 fFunction = reinterpret_cast<void*>(fn); | 23 fFunction = reinterpret_cast<void*>(fn); |
23 } | 24 } |
24 | 25 |
25 template <typename Fn> | 26 template <typename Fn> |
26 explicit SkFunction(Fn fn) : fVTable(GetVTable<Fn>()) { | 27 explicit SkFunction(Fn fn, SK_WHEN_C((sizeof(Fn) > sizeof(void*)), void*) =
nullptr) |
27 // We've got a functor. The basic thing we can always do is copy it ont
o the heap. | 28 : fVTable(GetOutlineVTable<Fn>()) { |
| 29 // We've got a functor larger than a pointer. We've go to copy it onto
the heap. |
28 fFunction = SkNEW_ARGS(Fn, (fn)); | 30 fFunction = SkNEW_ARGS(Fn, (fn)); |
29 } | 31 } |
30 | 32 |
31 ~SkFunction() { fVTable.fDelete(fFunction); } | 33 template <typename Fn> |
| 34 explicit SkFunction(Fn fn, SK_WHEN_C((sizeof(Fn) <= sizeof(void*)), void*) =
nullptr) |
| 35 : fVTable(GetInlineVTable<Fn>()) { |
| 36 // We've got a functor that fits in a pointer. We copy it right inline. |
| 37 SkNEW_PLACEMENT_ARGS(&fFunction, Fn, (fn)); |
| 38 } |
| 39 |
| 40 ~SkFunction() { fVTable.fCleanUp(fFunction); } |
32 | 41 |
33 R operator()(Args... args) { return fVTable.fCall(fFunction, args...); } | 42 R operator()(Args... args) { return fVTable.fCall(fFunction, args...); } |
34 | 43 |
35 private: | 44 private: |
36 struct VTable { | 45 struct VTable { |
37 R (*fCall)(void*, Args...); | 46 R (*fCall)(void*, Args...); |
38 void (*fDelete)(void*); | 47 void (*fCleanUp)(void*); |
39 }; | 48 }; |
40 | 49 |
| 50 // Used when fFunction is a function pointer of type R(*)(Args...). |
41 static const VTable& GetFunctionPointerVTable() { | 51 static const VTable& GetFunctionPointerVTable() { |
42 static const VTable vtable = { | 52 static const VTable vtable = { |
43 [](void* fn, Args... args) { return reinterpret_cast<R(*)(Args...)>(
fn)(args...); }, | 53 [](void* fn, Args... args) { return reinterpret_cast<R(*)(Args...)>(
fn)(args...); }, |
44 [](void*) { /* Don't delete function pointers. */ }, | 54 [](void*) { /* Nothing to clean up for function pointers. */ } |
45 }; | 55 }; |
46 return vtable; | 56 return vtable; |
47 } | 57 } |
48 | 58 |
| 59 // Used when fFunction is a pointer to a functor of type Fn on the heap (we
own it). |
49 template <typename Fn> | 60 template <typename Fn> |
50 static const VTable& GetVTable() { | 61 static const VTable& GetOutlineVTable() { |
51 static const VTable vtable = { | 62 static const VTable vtable = { |
52 [](void* fn, Args... args) { return (*static_cast<Fn*>(fn))(args...)
; }, | 63 [](void* fn, Args... args) { return (*static_cast<Fn*>(fn))(args...)
; }, |
53 [](void* fn) { SkDELETE(static_cast<Fn*>(fn)); }, | 64 [](void* fn) { SkDELETE(static_cast<Fn*>(fn)); }, |
54 }; | 65 }; |
55 return vtable; | 66 return vtable; |
56 } | 67 } |
57 | 68 |
58 void* fFunction; // Either a function pointer, or a pointer to a func
tor. | 69 // Used when fFunction _is_ a functor of type Fn, not a pointer to the funct
or. |
| 70 template <typename Fn> |
| 71 static const VTable& GetInlineVTable() { |
| 72 static const VTable vtable = { |
| 73 [](void* fn, Args... args) { |
| 74 union { void* p; Fn f; } pun = { fn }; |
| 75 return pun.f(args...); |
| 76 }, |
| 77 [](void* fn) { |
| 78 union { void* p; Fn f; } pun = { fn }; |
| 79 pun.f.~Fn(); |
| 80 (void)(pun.f); // Otherwise, when ~Fn() is trivial, MSVC compl
ains pun is unused. |
| 81 } |
| 82 }; |
| 83 return vtable; |
| 84 } |
| 85 |
| 86 |
| 87 void* fFunction; // A function pointer, a pointer to a functor, or an
inlined functor. |
59 const VTable& fVTable; // How to call, delete (and one day copy, move) fFun
ction. | 88 const VTable& fVTable; // How to call, delete (and one day copy, move) fFun
ction. |
60 }; | 89 }; |
61 | 90 |
62 // TODO: | 91 // TODO: |
63 // - is it worth moving fCall out of the VTable into SkFunction itself to avoi
d the indirection? | 92 // - is it worth moving fCall out of the VTable into SkFunction itself to avoi
d the indirection? |
64 // - should constructors be implicit? | 93 // - should constructors be implicit? |
65 // - make SkFunction copyable | 94 // - make SkFunction copyable |
66 // - emulate std::forward for moveable functors (e.g. lambdas) | 95 // - emulate std::forward for moveable functors (e.g. lambdas) |
67 // - forward args too? | 96 // - forward args too? |
68 // - implement small-object optimization to store functors inline | |
69 | 97 |
70 #endif//SkFunction_DEFINED | 98 #endif//SkFunction_DEFINED |
OLD | NEW |