Last active
September 23, 2015 01:29
-
-
Save bazhenovc/bdb82db9b88d6188ee43 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace internal | |
{ | |
template <typename R, typename ...Args> | |
struct FunctionImplBase | |
{ | |
virtual FORCE_INLINE ~FunctionImplBase() {} | |
virtual R Invoke(Args... args) const = 0; | |
virtual FunctionImplBase* Clone(uint8_t* storage) = 0; | |
}; | |
template <typename T, typename R, typename ...Args> | |
struct FunctionImpl final : public FunctionImplBase<R, Args...> | |
{ | |
mutable T _function; | |
FORCE_INLINE FunctionImpl(T func) : _function(func) {} | |
virtual FORCE_INLINE R Invoke(Args... args) const override | |
{ | |
return _function(static_cast<Args&&>(args)...); | |
} | |
virtual FunctionImplBase* Clone(uint8_t* storage) override | |
{ | |
return new (storage) FunctionImpl(*this); | |
} | |
}; | |
} | |
template <size_t C, typename T> struct FunctionBase; | |
template <size_t C, typename R, typename ...Args> | |
class FunctionBase<C, R(Args...)> final | |
{ | |
private: | |
enum | |
{ | |
kDesiredSize = C, | |
kMaxCapacity = kDesiredSize - sizeof(internal::FunctionImplBase<R, Args...>*) | |
}; | |
uint8_t _storage[kMaxCapacity]; | |
internal::FunctionImplBase<R, Args...>* _function = nullptr; | |
public: | |
FORCE_INLINE FunctionBase() { static_assert(sizeof(FunctionBase) == kDesiredSize, "Error: wrong function size!"); } | |
FORCE_INLINE ~FunctionBase() | |
{ | |
static_assert(sizeof(FunctionBase) == kDesiredSize, "Error: wrong function size!"); | |
if (_function != nullptr) _function->~FunctionImplBase(); | |
} | |
FORCE_INLINE FunctionBase(const FunctionBase& other) | |
{ | |
static_assert(sizeof(FunctionBase) == kDesiredSize, "Error: wrong function size!"); | |
if (other._function != nullptr) | |
_function = other._function->Clone(_storage); | |
} | |
template <typename T> | |
FORCE_INLINE FunctionBase(T fn) | |
{ | |
static_assert(sizeof(FunctionBase) == kDesiredSize, "Error: wrong function size!"); | |
static_assert(sizeof(T) <= kMaxCapacity, "Error: function size is too big!"); | |
_function = new (_storage) internal::FunctionImpl<T, R, Args...>(fn); | |
} | |
FORCE_INLINE FunctionBase& operator=(const FunctionBase& other) | |
{ | |
static_assert(sizeof(FunctionBase) == kDesiredSize, "Error: wrong function size!"); | |
if (_function != nullptr) { | |
_function->~FunctionImplBase(); | |
_function = nullptr; | |
} | |
if (other._function != nullptr) | |
_function = other._function->Clone(_storage); | |
return *this; | |
} | |
template <typename T> | |
FORCE_INLINE FunctionBase& operator=(T fn) | |
{ | |
static_assert(sizeof(FunctionBase) == kDesiredSize, "Error: wrong function size!"); | |
static_assert(sizeof(T) <= kMaxCapacity, "Error: function size is too big!"); | |
if (_function) | |
_function->~FunctionImplBase(); | |
_function = new (_storage) internal::FunctionImpl<T, R, Args...>(fn); | |
return *this; | |
} | |
FORCE_INLINE R operator()(Args... args) | |
{ | |
return _function->Invoke(static_cast<Args&&>(args)...); | |
} | |
FORCE_INLINE R operator()(Args... args) const | |
{ | |
return _function->Invoke(static_cast<Args&&>(args)...); | |
} | |
FORCE_INLINE operator bool() const { return _function != nullptr; } | |
}; | |
template <typename T> | |
using Function = FunctionBase<32, T>; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment