Created
June 17, 2021 09:24
-
-
Save phire/970da483f1454082efc9fb88c03fc368 to your computer and use it in GitHub Desktop.
Literal std::function experment. Can be passed as template argument.
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
#include <type_traits> | |
#include <utility> | |
template<class ReturnType, class...Xs> | |
struct CallableBase { | |
virtual ReturnType operator()(Xs...) const = 0; | |
virtual ReturnType operator()(Xs...) = 0; | |
virtual void copy(void*) const = 0; | |
}; | |
template<class F, class ReturnType, class...Xs> | |
struct Callable final | |
: CallableBase<ReturnType, Xs...> | |
{ | |
F f; | |
Callable(F const& f) : f(f) {} | |
virtual void copy(void* memory) const { | |
new (memory) Callable<F, ReturnType, Xs...>(f); | |
} | |
virtual ReturnType operator()(Xs... xs) const { | |
return f(xs...); | |
} | |
virtual ReturnType operator()(Xs... xs) { | |
return f(xs...); | |
} | |
}; | |
template<class F, class ReturnType, class...Xs> | |
struct CallablePtr final | |
: CallableBase<ReturnType, Xs...> | |
{ | |
F *f; | |
CallablePtr(F const* f) : f(f) {} | |
virtual void copy(void* memory) const { | |
new (memory) CallablePtr<F, ReturnType, Xs...>(f); | |
} | |
virtual ReturnType operator()(Xs... xs) const { | |
return f(xs...); | |
} | |
virtual ReturnType operator()(Xs... xs) { | |
return f(xs...); | |
} | |
}; | |
template<class Signature, unsigned size=128> | |
class LiteralFn; | |
template<class ReturnType, class...Xs, unsigned size> | |
class LiteralFn<ReturnType(Xs...), size> { | |
char memory[size]; | |
bool allocated = false; | |
using Base = CallableBase<ReturnType, Xs...>; | |
public: | |
constexpr LiteralFn(){} | |
template<class F> | |
constexpr LiteralFn(F const&f) { | |
if constexpr (std::is_function<F>::value) { | |
static_assert(sizeof(CallablePtr<F, ReturnType, Xs...>) <= sizeof(memory)); | |
new (memory) CallablePtr<F, ReturnType, Xs...>(f); | |
} else { | |
static_assert(sizeof(Callable<F, ReturnType, Xs...>) <= sizeof(memory)); | |
new (memory) Callable<F, ReturnType, Xs...>(f); | |
} | |
allocated = true; | |
} | |
template<class...Ys> | |
constexpr ReturnType operator()(Ys&&...ys) { | |
if (allocated) { | |
return (*reinterpret_cast<Base*>(memory))(std::forward<Ys>(ys)...); | |
} | |
return {}; | |
} | |
template<class...Ys> | |
constexpr ReturnType operator()(Ys&&...ys)const { | |
if (allocated) { | |
return *reinterpret_cast<Base*>(memory)(std::forward<Ys>(ys)...); | |
} | |
return {}; | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment