aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkFunction.h
diff options
context:
space:
mode:
authorGravatar mtklein <mtklein@chromium.org>2015-03-31 14:24:27 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-03-31 14:24:27 -0700
commit4a9426f0fa812c0f1bffa84f0dae0926607a9543 (patch)
treee95198a50449f804c18c2328ac966258e740d032 /src/core/SkFunction.h
parent7c3a2f834e0ba3f11a3129d5348b393efcc9b0e1 (diff)
Sketch SkFunction
Let's start with baby steps in case some bot can't handle this. I have left many TODOs, most of which I know how to do if this looks feasible and useful. BUG=skia: Review URL: https://codereview.chromium.org/1049223003
Diffstat (limited to 'src/core/SkFunction.h')
-rw-r--r--src/core/SkFunction.h70
1 files changed, 70 insertions, 0 deletions
diff --git a/src/core/SkFunction.h b/src/core/SkFunction.h
new file mode 100644
index 0000000000..9ec421e2a6
--- /dev/null
+++ b/src/core/SkFunction.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkFunction_DEFINED
+#define SkFunction_DEFINED
+
+// TODO: document
+
+#include "SkTypes.h"
+
+template <typename> class SkFunction;
+
+template <typename R, typename... Args>
+class SkFunction<R(Args...)> : SkNoncopyable {
+public:
+ explicit SkFunction(R (*fn)(Args...)) : fVTable(GetFunctionPointerVTable()) {
+ // We've been passed a function pointer. We'll just store it.
+ fFunction = reinterpret_cast<void*>(fn);
+ }
+
+ 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.
+ fFunction = SkNEW_ARGS(Fn, (fn));
+ }
+
+ ~SkFunction() { fVTable.fDelete(fFunction); }
+
+ R operator()(Args... args) { return fVTable.fCall(fFunction, args...); }
+
+private:
+ struct VTable {
+ R (*fCall)(void*, Args...);
+ void (*fDelete)(void*);
+ };
+
+ 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. */ },
+ };
+ return vtable;
+ }
+
+ template <typename Fn>
+ static const VTable& GetVTable() {
+ static const VTable vtable = {
+ [](void* fn, Args... args) { return (*static_cast<Fn*>(fn))(args...); },
+ [](void* fn) { SkDELETE(static_cast<Fn*>(fn)); },
+ };
+ return vtable;
+ }
+
+ void* fFunction; // Either a function pointer, or a pointer to a functor.
+ const VTable& fVTable; // How to call, delete (and one day copy, move) fFunction.
+};
+
+// TODO:
+// - 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?
+// - implement small-object optimization to store functors inline
+
+#endif//SkFunction_DEFINED