2015-03-31 21:24:27 +00:00
|
|
|
/*
|
|
|
|
* 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"
|
2015-04-01 15:11:16 +00:00
|
|
|
#include "SkTLogic.h"
|
2015-03-31 21:24:27 +00:00
|
|
|
|
|
|
|
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>
|
2015-04-01 15:11:16 +00:00
|
|
|
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.
|
2015-04-01 18:26:31 +00:00
|
|
|
fFunction = SkNEW_ARGS(Fn, (Forward(fn)));
|
2015-03-31 21:24:27 +00:00
|
|
|
}
|
|
|
|
|
2015-04-01 15:11:16 +00:00
|
|
|
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.
|
2015-04-01 18:26:31 +00:00
|
|
|
fFunction = NULL; // Quiets a (spurious) warning that fFunction might be uninitialized.
|
|
|
|
SkNEW_PLACEMENT_ARGS(&fFunction, Fn, (Forward(fn)));
|
2015-04-01 15:11:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
~SkFunction() { fVTable.fCleanUp(fFunction); }
|
2015-03-31 21:24:27 +00:00
|
|
|
|
2015-04-01 18:26:31 +00:00
|
|
|
R operator()(Args... args) { return fVTable.fCall(fFunction, Forward(args)...); }
|
2015-03-31 21:24:27 +00:00
|
|
|
|
|
|
|
private:
|
2015-04-01 18:26:31 +00:00
|
|
|
// ~= 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; }
|
|
|
|
|
2015-03-31 21:24:27 +00:00
|
|
|
struct VTable {
|
|
|
|
R (*fCall)(void*, Args...);
|
2015-04-01 15:11:16 +00:00
|
|
|
void (*fCleanUp)(void*);
|
2015-03-31 21:24:27 +00:00
|
|
|
};
|
|
|
|
|
2015-04-01 15:11:16 +00:00
|
|
|
// Used when fFunction is a function pointer of type R(*)(Args...).
|
2015-03-31 21:24:27 +00:00
|
|
|
static const VTable& GetFunctionPointerVTable() {
|
|
|
|
static const VTable vtable = {
|
2015-04-01 18:26:31 +00:00
|
|
|
[](void* fn, Args... args) {
|
|
|
|
return reinterpret_cast<R(*)(Args...)>(fn)(Forward(args)...);
|
|
|
|
},
|
2015-04-01 15:11:16 +00:00
|
|
|
[](void*) { /* Nothing to clean up for function pointers. */ }
|
2015-03-31 21:24:27 +00:00
|
|
|
};
|
|
|
|
return vtable;
|
|
|
|
}
|
|
|
|
|
2015-04-01 15:11:16 +00:00
|
|
|
// Used when fFunction is a pointer to a functor of type Fn on the heap (we own it).
|
2015-03-31 21:24:27 +00:00
|
|
|
template <typename Fn>
|
2015-04-01 15:11:16 +00:00
|
|
|
static const VTable& GetOutlineVTable() {
|
2015-03-31 21:24:27 +00:00
|
|
|
static const VTable vtable = {
|
2015-04-01 18:26:31 +00:00
|
|
|
[](void* fn, Args... args) { return (*static_cast<Fn*>(fn))(Forward(args)...); },
|
2015-03-31 21:24:27 +00:00
|
|
|
[](void* fn) { SkDELETE(static_cast<Fn*>(fn)); },
|
|
|
|
};
|
|
|
|
return vtable;
|
|
|
|
}
|
|
|
|
|
2015-04-01 15:11:16 +00:00
|
|
|
// 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) {
|
2015-04-01 18:26:31 +00:00
|
|
|
union { void** p; Fn* f; } pun = { &fn };
|
|
|
|
return (*pun.f)(Forward(args)...);
|
2015-04-01 15:11:16 +00:00
|
|
|
},
|
|
|
|
[](void* fn) {
|
2015-04-01 18:26:31 +00:00
|
|
|
union { void** p; Fn* f; } pun = { &fn };
|
|
|
|
(*pun.f).~Fn();
|
2015-04-01 15:11:16 +00:00
|
|
|
(void)(pun.f); // Otherwise, when ~Fn() is trivial, MSVC complains pun is unused.
|
|
|
|
}
|
|
|
|
};
|
|
|
|
return vtable;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void* fFunction; // A function pointer, a pointer to a functor, or an inlined functor.
|
2015-03-31 21:24:27 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
#endif//SkFunction_DEFINED
|