Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(142)

Unified Diff: src/core/SkFunction.h

Issue 1056673002: Make SkFunction copyable so it can go in containers. (Closed) Base URL: https://skia.googlesource.com/skia@master
Patch Set: ben Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tests/FunctionTest.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/core/SkFunction.h
diff --git a/src/core/SkFunction.h b/src/core/SkFunction.h
index 43438dd9e29970f1ea619cc3e6067fcf4abc11a2..429c6f5ade327543e62a92b72296c4809179545e 100644
--- a/src/core/SkFunction.h
+++ b/src/core/SkFunction.h
@@ -8,94 +8,68 @@
#ifndef SkFunction_DEFINED
#define SkFunction_DEFINED
-// TODO: document
+// TODO: document, more pervasive move support in constructors, small-Fn optimization
+#include "SkTemplates.h"
#include "SkTypes.h"
-#include "SkTLogic.h"
template <typename> class SkFunction;
template <typename R, typename... Args>
-class SkFunction<R(Args...)> : SkNoncopyable {
+class SkFunction<R(Args...)> {
public:
- SkFunction(R (*fn)(Args...)) : fVTable(GetFunctionPointerVTable()) {
- // We've been passed a function pointer. We'll just store it.
- fFunction = reinterpret_cast<void*>(fn);
- }
+ SkFunction() {}
template <typename Fn>
- 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, (Forward(fn)));
- }
+ SkFunction(const Fn& fn) : fFunction(SkNEW_ARGS(LambdaImpl<Fn>, (fn))) {}
- template <typename Fn>
- 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.
- fFunction = NULL; // Quiets a (spurious) warning that fFunction might be uninitialized.
- SkNEW_PLACEMENT_ARGS(&fFunction, Fn, (Forward(fn)));
- }
+ SkFunction(R (*fn)(Args...)) : fFunction(SkNEW_ARGS(FnPtrImpl, (fn))) {}
- ~SkFunction() { fVTable.fCleanUp(fFunction); }
+ SkFunction(const SkFunction& other) { *this = other; }
+ SkFunction& operator=(const SkFunction& other) {
+ if (this != &other) {
+ fFunction.reset(other.fFunction ? other.fFunction->clone() : nullptr);
+ }
+ return *this;
+ }
- R operator()(Args... args) { return fVTable.fCall(fFunction, Forward(args)...); }
+ R operator()(Args... args) const {
+ SkASSERT(fFunction.get());
+ return fFunction->call(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*);
+ struct Interface {
+ virtual ~Interface() {}
+ virtual R call(Args...) const = 0;
+ virtual Interface* clone() const = 0;
};
- // 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)(Forward(args)...);
- },
- [](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& GetOutlineVTable() {
- static const VTable vtable = {
- [](void* fn, Args... args) { return (*static_cast<Fn*>(fn))(Forward(args)...); },
- [](void* fn) { SkDELETE(static_cast<Fn*>(fn)); },
- };
- return vtable;
- }
+ class LambdaImpl final : public Interface {
+ public:
+ LambdaImpl(const Fn& fn) : fFn(fn) {}
+
+ R call(Args... args) const override { return fFn(Forward(args)...); }
+ Interface* clone() const { return SkNEW_ARGS(LambdaImpl<Fn>, (fFn)); }
+ private:
+ Fn fFn;
+ };
- // 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)(Forward(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;
- }
+ class FnPtrImpl final : public Interface {
+ public:
+ FnPtrImpl(R (*fn)(Args...)) : fFn(fn) {}
+ R call(Args... args) const override { return fFn(Forward(args)...); }
+ Interface* clone() const { return SkNEW_ARGS(FnPtrImpl, (fFn)); }
+ private:
+ R (*fFn)(Args...);
+ };
- 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.
+ SkAutoTDelete<Interface> fFunction;
};
-// TODO:
-// - is it worth moving fCall out of the VTable into SkFunction itself to avoid the indirection?
-// - make SkFunction copyable
-
#endif//SkFunction_DEFINED
« no previous file with comments | « no previous file | tests/FunctionTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698