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
This commit is contained in:
parent
7c3a2f834e
commit
4a9426f0fa
@ -105,6 +105,7 @@
|
|||||||
'../tests/FontNamesTest.cpp',
|
'../tests/FontNamesTest.cpp',
|
||||||
'../tests/FontObjTest.cpp',
|
'../tests/FontObjTest.cpp',
|
||||||
'../tests/FrontBufferedStreamTest.cpp',
|
'../tests/FrontBufferedStreamTest.cpp',
|
||||||
|
'../tests/FunctionTest.cpp',
|
||||||
'../tests/GLInterfaceValidationTest.cpp',
|
'../tests/GLInterfaceValidationTest.cpp',
|
||||||
'../tests/GLProgramsTest.cpp',
|
'../tests/GLProgramsTest.cpp',
|
||||||
'../tests/GeometryTest.cpp',
|
'../tests/GeometryTest.cpp',
|
||||||
|
70
src/core/SkFunction.h
Normal file
70
src/core/SkFunction.h
Normal file
@ -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
|
27
tests/FunctionTest.cpp
Normal file
27
tests/FunctionTest.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Google Inc.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SkFunction.h"
|
||||||
|
#include "Test.h"
|
||||||
|
|
||||||
|
static void test_add_five(skiatest::Reporter* r, SkFunction<int(int)>&& f) {
|
||||||
|
REPORTER_ASSERT(r, f(4) == 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_five(int x) { return x + 5; }
|
||||||
|
|
||||||
|
struct AddFive {
|
||||||
|
int operator()(int x) { return x + 5; };
|
||||||
|
};
|
||||||
|
|
||||||
|
DEF_TEST(Function, r) {
|
||||||
|
// We should be able to turn a static function, an explicit functor, or a lambda
|
||||||
|
// all into an SkFunction equally well.
|
||||||
|
test_add_five(r, SkFunction<int(int)>(&add_five));
|
||||||
|
test_add_five(r, SkFunction<int(int)>(AddFive()));
|
||||||
|
test_add_five(r, SkFunction<int(int)>([](int x) { return x + 5; }));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user