24template <
typename T>
struct is_function_pointer {
25 static constexpr bool value =
false;
28template <
typename R,
typename... Args>
29struct is_function_pointer<R(*)(Args...)> {
30 static constexpr bool value =
true;
42template <
typename>
class function;
46template <
typename R,
typename... Args>
50 virtual R invoke(Args...
args) = 0;
51 virtual ~CallableBase() =
default;
55 struct Callable : CallableBase {
57 Callable(F fn) : f(fn) {}
58 R invoke(Args...
args)
override {
return f(
args...); }
62 struct FreeFunctionCallable {
63 R (*func_ptr)(Args...);
65 FreeFunctionCallable(R (*fp)(Args...)) : func_ptr(fp) {}
67 R invoke(Args...
args)
const {
68 return func_ptr(
args...);
77 struct InlinedLambda {
80 alignas(max_align_t)
char bytes[kInlineLambdaSize];
83 R (*invoker)(
const InlinedLambda& storage, Args...
args);
84 void (*destructor)(InlinedLambda& storage);
86 template <
typename Function>
87 InlinedLambda(Function f) {
88 static_assert(
sizeof(Function) <= kInlineLambdaSize,
89 "Lambda/functor too large for inline storage");
90 static_assert(
alignof(Function) <=
alignof(max_align_t),
91 "Lambda/functor requires stricter alignment than storage provides");
100 invoker = &invoke_lambda<Function>;
101 destructor = &destroy_lambda<Function>;
105 InlinedLambda(
const InlinedLambda& other)
106 : invoker(other.invoker), destructor(other.destructor) {
109 fl::memcopy(bytes, other.bytes, kInlineLambdaSize);
113 InlinedLambda(InlinedLambda&& other)
114 : invoker(other.invoker), destructor(other.destructor) {
115 fl::memcopy(bytes, other.bytes, kInlineLambdaSize);
117 other.destructor =
nullptr;
126 template <
typename FUNCTOR>
127 static R invoke_lambda(
const InlinedLambda& storage, Args...
args) {
129 alignas(FUNCTOR)
char temp_storage[
sizeof(FUNCTOR)];
131 fl::memcopy(temp_storage, storage.bytes,
sizeof(FUNCTOR));
133 FUNCTOR* f =
static_cast<FUNCTOR*
>(
static_cast<void*
>(temp_storage));
135 return (*f)(
args...);
138 template <
typename FUNCTOR>
139 static void destroy_lambda(InlinedLambda& storage) {
147 FUNCTOR* obj_ptr =
static_cast<FUNCTOR*
>(
static_cast<void*
>(storage.bytes));
151 R invoke(Args...
args)
const {
152 return invoker(*
this,
args...);
157 struct MemberCallableBase {
158 virtual R invoke(Args...
args)
const = 0;
159 virtual ~MemberCallableBase() =
default;
163 struct NonConstMemberCallable : MemberCallableBase {
166 union MemberFuncStorage {
167 char bytes[
sizeof(R (NonConstMemberCallable::*)(Args...))];
169 void* alignment_dummy;
170 } member_func_storage;
173 R (*invoker)(
void* obj,
const MemberFuncStorage& mfp, Args...
args);
175 template <
typename C>
176 NonConstMemberCallable(C* o, R (C::*mf)(Args...)) : obj(o) {
178 static_assert(
sizeof(mf) <=
sizeof(member_func_storage),
179 "Member function pointer too large");
180 fl::memcopy(member_func_storage.bytes, &mf,
sizeof(mf));
182 invoker = &invoke_nonconst_member<C>;
185 template <
typename C>
186 static R invoke_nonconst_member(
void* obj,
const MemberFuncStorage& mfp, Args...
args) {
187 C* typed_obj =
static_cast<C*
>(obj);
188 R (C::*typed_mf)(Args...);
189 fl::memcopy(&typed_mf, mfp.bytes,
sizeof(typed_mf));
190 return (typed_obj->*typed_mf)(
args...);
193 R invoke(Args...
args)
const override {
194 return invoker(obj, member_func_storage,
args...);
199 struct ConstMemberCallable : MemberCallableBase {
202 union MemberFuncStorage {
203 char bytes[
sizeof(R (ConstMemberCallable::*)(Args...)
const)];
205 void* alignment_dummy;
206 } member_func_storage;
209 R (*invoker)(
const void* obj,
const MemberFuncStorage& mfp, Args...
args);
211 template <
typename C>
212 ConstMemberCallable(
const C* o, R (C::*mf)(Args...)
const) : obj(o) {
214 static_assert(
sizeof(mf) <=
sizeof(member_func_storage),
215 "Member function pointer too large");
216 fl::memcopy(member_func_storage.bytes, &mf,
sizeof(mf));
218 invoker = &invoke_const_member<C>;
221 template <
typename C>
222 static R invoke_const_member(
const void* obj,
const MemberFuncStorage& mfp, Args...
args) {
223 const C* typed_obj =
static_cast<const C*
>(obj);
224 R (C::*typed_mf)(Args...)
const;
225 fl::memcopy(&typed_mf, mfp.bytes,
sizeof(typed_mf));
226 return (typed_obj->*typed_mf)(
args...);
229 R invoke(Args...
args)
const override {
230 return invoker(obj, member_func_storage,
args...);
235 using Storage = Variant<fl::shared_ptr<CallableBase>, FreeFunctionCallable, InlinedLambda, NonConstMemberCallable, ConstMemberCallable>;
239 template<
typename ReturnType>
240 typename enable_if<!is_void<ReturnType>::value, ReturnType>::type
241 default_return_helper()
const {
245 template<
typename ReturnType>
246 typename enable_if<is_void<ReturnType>::value, ReturnType>::type
247 default_return_helper()
const {
252 function() =
default;
255 function(
const function& other) : storage_(other.storage_) {}
258 function(function&& other) noexcept : storage_(
fl::move(other.storage_)) {}
261 function& operator=(
const function& other) {
262 if (
this != &other) {
263 storage_ = other.storage_;
269 function& operator=(function&& other)
noexcept {
270 if (
this != &other) {
271 storage_ =
fl::move(other.storage_);
277 function(R (*fp)(Args...)) {
278 storage_ = FreeFunctionCallable(fp);
282 template <typename F, typename = enable_if_t<!is_member_function_pointer<F>::value && !is_function_pointer<F>::value>>
285 construct_lambda_or_functor(
fl::move(f),
typename conditional<
sizeof(F) <= kInlineLambdaSize, true_type, false_type>::type{});
289 template <
typename C>
290 function(R (C::*mf)(Args...), C* obj) {
291 storage_ = NonConstMemberCallable(obj, mf);
295 template <
typename C>
296 function(R (C::*mf)(Args...)
const,
const C* obj) {
297 storage_ = ConstMemberCallable(obj, mf);
300 R operator()(Args...
args)
const {
303 return (*heap_callable)->invoke(
args...);
304 }
else if (
auto* free_func = storage_.template ptr<FreeFunctionCallable>()) {
305 return free_func->invoke(
args...);
306 }
else if (
auto* inlined_lambda = storage_.template ptr<InlinedLambda>()) {
307 return inlined_lambda->invoke(
args...);
308 }
else if (
auto* nonconst_member = storage_.template ptr<NonConstMemberCallable>()) {
309 return nonconst_member->invoke(
args...);
310 }
else if (
auto* const_member = storage_.template ptr<ConstMemberCallable>()) {
311 return const_member->invoke(
args...);
314 return default_return_helper<R>();
317 explicit operator bool()
const {
318 return !storage_.empty();
322 storage_ = Storage{};
328 return storage_.empty() == o.storage_.empty();
332 return !(*
this == o);
337 template <
typename F>
338 void construct_lambda_or_functor(F f, true_type ) {
339 storage_ = InlinedLambda(
fl::move(f));
343 template <
typename F>
344 void construct_lambda_or_functor(F f, false_type ) {