diff options
author | mtklein <mtklein@chromium.org> | 2015-03-31 14:24:27 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-03-31 14:24:27 -0700 |
commit | 4a9426f0fa812c0f1bffa84f0dae0926607a9543 (patch) | |
tree | e95198a50449f804c18c2328ac966258e740d032 /src/core/SkFunction.h | |
parent | 7c3a2f834e0ba3f11a3129d5348b393efcc9b0e1 (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.h | 70 |
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 |