| 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
|
|
|