Index: src/core/SkFunction.h |
diff --git a/src/core/SkFunction.h b/src/core/SkFunction.h |
index 300959342139646064c533c12ef7d3a9bfab821a..98ae789cae2c70d8f29bd542034e0ecf397af691 100644 |
--- a/src/core/SkFunction.h |
+++ b/src/core/SkFunction.h |
@@ -27,21 +27,25 @@ public: |
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)); |
+ fFunction = SkNEW_ARGS(Fn, (Forward(fn))); |
} |
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)); |
+ fFunction = NULL; // Quiets a (spurious) warning that fFunction might be uninitialized. |
+ SkNEW_PLACEMENT_ARGS(&fFunction, Fn, (Forward(fn))); |
} |
~SkFunction() { fVTable.fCleanUp(fFunction); } |
- R operator()(Args... args) { return fVTable.fCall(fFunction, args...); } |
+ R operator()(Args... args) { return fVTable.fCall(fFunction, Forward(args)...); } |
private: |
+ // ~= std::forward. This moves its argument if possible, falling back to a copy if not. |
+ template <typename T> static T&& Forward(T& v) { return (T&&)v; } |
+ |
struct VTable { |
R (*fCall)(void*, Args...); |
void (*fCleanUp)(void*); |
@@ -50,7 +54,9 @@ private: |
// 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* fn, Args... args) { |
+ return reinterpret_cast<R(*)(Args...)>(fn)(Forward(args)...); |
+ }, |
[](void*) { /* Nothing to clean up for function pointers. */ } |
}; |
return vtable; |
@@ -60,7 +66,7 @@ private: |
template <typename Fn> |
static const VTable& GetOutlineVTable() { |
static const VTable vtable = { |
- [](void* fn, Args... args) { return (*static_cast<Fn*>(fn))(args...); }, |
+ [](void* fn, Args... args) { return (*static_cast<Fn*>(fn))(Forward(args)...); }, |
[](void* fn) { SkDELETE(static_cast<Fn*>(fn)); }, |
}; |
return vtable; |
@@ -71,12 +77,12 @@ private: |
static const VTable& GetInlineVTable() { |
static const VTable vtable = { |
[](void* fn, Args... args) { |
- union { void* p; Fn f; } pun = { fn }; |
- return pun.f(args...); |
+ union { void** p; Fn* f; } pun = { &fn }; |
+ return (*pun.f)(Forward(args)...); |
}, |
[](void* fn) { |
- union { void* p; Fn f; } pun = { fn }; |
- pun.f.~Fn(); |
+ union { void** p; Fn* f; } pun = { &fn }; |
+ (*pun.f).~Fn(); |
(void)(pun.f); // Otherwise, when ~Fn() is trivial, MSVC complains pun is unused. |
} |
}; |
@@ -92,7 +98,5 @@ private: |
// - is it worth moving fCall out of the VTable into SkFunction itself to avoid the indirection? |
// - should constructors be implicit? |
// - make SkFunction copyable |
-// - emulate std::forward for moveable functors (e.g. lambdas) |
-// - forward args too? |
#endif//SkFunction_DEFINED |