Index: src/core/SkFunction.h |
diff --git a/src/core/SkFunction.h b/src/core/SkFunction.h |
index 9ec421e2a6789c69db1d1691091dd80fbfe8151e..300959342139646064c533c12ef7d3a9bfab821a 100644 |
--- a/src/core/SkFunction.h |
+++ b/src/core/SkFunction.h |
@@ -11,6 +11,7 @@ |
// TODO: document |
#include "SkTypes.h" |
+#include "SkTLogic.h" |
template <typename> class SkFunction; |
@@ -23,31 +24,41 @@ public: |
} |
template <typename Fn> |
- explicit SkFunction(Fn fn) : fVTable(GetVTable<Fn>()) { |
- // We've got a functor. The basic thing we can always do is copy it onto the heap. |
+ explicit SkFunction(Fn fn, SK_WHEN_C((sizeof(Fn) > sizeof(void*)), void*) = nullptr) |
+ : fVTable(GetOutlineVTable<Fn>()) { |
+ // We've got a functor larger than a pointer. We've go to copy it onto the heap. |
fFunction = SkNEW_ARGS(Fn, (fn)); |
} |
- ~SkFunction() { fVTable.fDelete(fFunction); } |
+ template <typename Fn> |
+ explicit SkFunction(Fn fn, SK_WHEN_C((sizeof(Fn) <= sizeof(void*)), void*) = nullptr) |
+ : fVTable(GetInlineVTable<Fn>()) { |
+ // We've got a functor that fits in a pointer. We copy it right inline. |
+ SkNEW_PLACEMENT_ARGS(&fFunction, Fn, (fn)); |
+ } |
+ |
+ ~SkFunction() { fVTable.fCleanUp(fFunction); } |
R operator()(Args... args) { return fVTable.fCall(fFunction, args...); } |
private: |
struct VTable { |
R (*fCall)(void*, Args...); |
- void (*fDelete)(void*); |
+ void (*fCleanUp)(void*); |
}; |
+ // Used when fFunction is a function pointer of type R(*)(Args...). |
static const VTable& GetFunctionPointerVTable() { |
static const VTable vtable = { |
[](void* fn, Args... args) { return reinterpret_cast<R(*)(Args...)>(fn)(args...); }, |
- [](void*) { /* Don't delete function pointers. */ }, |
+ [](void*) { /* Nothing to clean up for function pointers. */ } |
}; |
return vtable; |
} |
+ // Used when fFunction is a pointer to a functor of type Fn on the heap (we own it). |
template <typename Fn> |
- static const VTable& GetVTable() { |
+ static const VTable& GetOutlineVTable() { |
static const VTable vtable = { |
[](void* fn, Args... args) { return (*static_cast<Fn*>(fn))(args...); }, |
[](void* fn) { SkDELETE(static_cast<Fn*>(fn)); }, |
@@ -55,7 +66,25 @@ private: |
return vtable; |
} |
- void* fFunction; // Either a function pointer, or a pointer to a functor. |
+ // Used when fFunction _is_ a functor of type Fn, not a pointer to the functor. |
+ template <typename Fn> |
+ static const VTable& GetInlineVTable() { |
+ static const VTable vtable = { |
+ [](void* fn, Args... args) { |
+ union { void* p; Fn f; } pun = { fn }; |
+ return pun.f(args...); |
+ }, |
+ [](void* fn) { |
+ union { void* p; Fn f; } pun = { fn }; |
+ pun.f.~Fn(); |
+ (void)(pun.f); // Otherwise, when ~Fn() is trivial, MSVC complains pun is unused. |
+ } |
+ }; |
+ return vtable; |
+ } |
+ |
+ |
+ void* fFunction; // A function pointer, a pointer to a functor, or an inlined functor. |
const VTable& fVTable; // How to call, delete (and one day copy, move) fFunction. |
}; |
@@ -65,6 +94,5 @@ private: |
// - make SkFunction copyable |
// - emulate std::forward for moveable functors (e.g. lambdas) |
// - forward args too? |
-// - implement small-object optimization to store functors inline |
#endif//SkFunction_DEFINED |