50template <
typename T>
struct is_function_pointer {
51 static constexpr bool value =
false;
54template <
typename R,
typename... Args>
55struct is_function_pointer<R(*)(Args...)> {
56 static constexpr bool value =
true;
68template <
typename>
class function;
70template <
typename R,
typename... Args>
73#if FL_FUNCTION_FULL_VARIANT
80 struct Callable : CallableBase {
88 struct FreeFunctionCallable {
89 R (*func_ptr)(Args...);
91 FreeFunctionCallable(R (*fp)(Args...))
FL_NOEXCEPT : func_ptr(fp) {}
94 return func_ptr(
args...);
103 struct InlinedLambda {
109 R (*invoker)(
const InlinedLambda& storage, Args...
args);
110 void (*destructor)(InlinedLambda& storage);
112 template <
typename Function>
115 "Lambda/functor too large for inline storage");
117 "Lambda/functor requires stricter alignment than storage provides");
126 invoker = &invoke_lambda<Function>;
127 destructor = &destroy_lambda<Function>;
131 InlinedLambda(
const InlinedLambda& other)
FL_NOEXCEPT
132 : invoker(other.invoker), destructor(other.destructor) {
135 fl::memcpy(bytes, other.bytes, kInlineLambdaSize);
140 : invoker(other.invoker), destructor(other.destructor) {
141 fl::memcpy(bytes, other.bytes, kInlineLambdaSize);
143 other.destructor =
nullptr;
152 template <
typename FUNCTOR>
153 static R invoke_lambda(
const InlinedLambda& storage, Args...
args)
FL_NOEXCEPT {
155 FL_ALIGN_AS(FUNCTOR)
char temp_storage[
sizeof(FUNCTOR)];
157 fl::memcpy(temp_storage, storage.bytes,
sizeof(FUNCTOR));
159 FUNCTOR* f =
static_cast<FUNCTOR*
>(
static_cast<void*
>(temp_storage));
161 return (*f)(
args...);
164 template <
typename FUNCTOR>
165 static void destroy_lambda(InlinedLambda& storage)
FL_NOEXCEPT {
173 FUNCTOR* obj_ptr =
static_cast<FUNCTOR*
>(
static_cast<void*
>(storage.bytes));
178 return invoker(*
this,
args...);
182#if FL_FUNCTION_FULL_VARIANT
184 struct MemberCallableBase {
186 virtual ~MemberCallableBase()
FL_NOEXCEPT =
default;
190 struct NonConstMemberCallable : MemberCallableBase {
193 union MemberFuncStorage {
194 char bytes[
sizeof(R (NonConstMemberCallable::*)(Args...))];
196 void* alignment_dummy;
197 } member_func_storage;
200 R (*invoker)(
void* obj,
const MemberFuncStorage& mfp, Args...
args);
202 template <
typename C>
203 NonConstMemberCallable(C* o, R (C::*mf)(Args...))
FL_NOEXCEPT : obj(o) {
206 "Member function pointer too large");
207 fl::memcpy(member_func_storage.bytes, &mf,
sizeof(mf));
209 invoker = &invoke_nonconst_member<C>;
212 template <
typename C>
213 static R invoke_nonconst_member(
void* obj,
const MemberFuncStorage& mfp, Args...
args)
FL_NOEXCEPT {
214 C* typed_obj =
static_cast<C*
>(obj);
215 R (C::*typed_mf)(Args...);
216 fl::memcpy(&typed_mf, mfp.bytes,
sizeof(typed_mf));
217 return (typed_obj->*typed_mf)(
args...);
221 return invoker(obj, member_func_storage,
args...);
226 struct ConstMemberCallable : MemberCallableBase {
229 union MemberFuncStorage {
230 char bytes[
sizeof(R (ConstMemberCallable::*)(Args...)
const)];
232 void* alignment_dummy;
233 } member_func_storage;
236 R (*invoker)(
const void* obj,
const MemberFuncStorage& mfp, Args...
args);
238 template <
typename C>
239 ConstMemberCallable(
const C* o, R (C::*mf)(Args...)
const)
FL_NOEXCEPT : obj(o) {
242 "Member function pointer too large");
243 fl::memcpy(member_func_storage.bytes, &mf,
sizeof(mf));
245 invoker = &invoke_const_member<C>;
248 template <
typename C>
249 static R invoke_const_member(
const void* obj,
const MemberFuncStorage& mfp, Args...
args)
FL_NOEXCEPT {
250 const C* typed_obj =
static_cast<const C*
>(obj);
251 R (C::*typed_mf)(Args...)
const;
252 fl::memcpy(&typed_mf, mfp.bytes,
sizeof(typed_mf));
253 return (typed_obj->*typed_mf)(
args...);
257 return invoker(obj, member_func_storage,
args...);
266#if FL_FUNCTION_FULL_VARIANT
267 using Storage = variant<fl::shared_ptr<CallableBase>, FreeFunctionCallable, InlinedLambda, NonConstMemberCallable, ConstMemberCallable>;
269 using Storage = variant<FreeFunctionCallable, InlinedLambda>;
274 template<
typename ReturnType>
275 typename enable_if<!is_void<ReturnType>::value, ReturnType>::type
280 template<
typename ReturnType>
281 typename enable_if<is_void<ReturnType>::value, ReturnType>::type
290 function(
const function& other)
FL_NOEXCEPT : mStorage(other.mStorage) {}
296 function& operator=(
const function& other)
FL_NOEXCEPT {
297 if (
this != &other) {
298 mStorage = other.mStorage;
304 function& operator=(function&& other)
FL_NOEXCEPT {
305 if (
this != &other) {
306 mStorage =
fl::move(other.mStorage);
313 mStorage = FreeFunctionCallable(fp);
317 template <typename F, typename = enable_if_t<!is_member_function_pointer<F>::value && !is_function_pointer<F>::value>>
320 construct_lambda_or_functor(
fl::move(f),
typename conditional<
sizeof(F) <= kInlineLambdaSize, true_type, false_type>::type{});
323#if FL_FUNCTION_FULL_VARIANT
325 template <
typename C>
326 function(R (C::*mf)(Args...), C* obj)
FL_NOEXCEPT {
327 mStorage = NonConstMemberCallable(obj, mf);
331 template <
typename C>
332 function(R (C::*mf)(Args...)
const,
const C* obj)
FL_NOEXCEPT {
333 mStorage = ConstMemberCallable(obj, mf);
339#if FL_FUNCTION_FULL_VARIANT
341 return (*heap_callable)->invoke(
args...);
342 }
else if (
auto* free_func = mStorage.template ptr<FreeFunctionCallable>()) {
344 if (
auto* free_func = mStorage.template ptr<FreeFunctionCallable>()) {
346 return free_func->invoke(
args...);
347 }
else if (
auto* inlined_lambda = mStorage.template ptr<InlinedLambda>()) {
348 return inlined_lambda->invoke(
args...);
349#if FL_FUNCTION_FULL_VARIANT
350 }
else if (
auto* nonconst_member = mStorage.template ptr<NonConstMemberCallable>()) {
351 return nonconst_member->invoke(
args...);
352 }
else if (
auto* const_member = mStorage.template ptr<ConstMemberCallable>()) {
353 return const_member->invoke(
args...);
357 return default_return_helper<R>();
361 return !mStorage.empty();
365 mStorage = Storage{};
368 bool operator==(
const function& o)
const FL_NOEXCEPT {
371 return mStorage.empty() == o.mStorage.empty();
374 bool operator!=(
const function& o)
const FL_NOEXCEPT {
375 return !(*
this == o);
380 template <
typename F>
381 void construct_lambda_or_functor(F f, true_type )
FL_NOEXCEPT {
382 mStorage = InlinedLambda(
fl::move(f));
385#if FL_FUNCTION_FULL_VARIANT
387 template <
typename F>
388 void construct_lambda_or_functor(F f, false_type )
FL_NOEXCEPT {
399 template <
typename F>
400 void construct_lambda_or_functor(F , false_type )
FL_NOEXCEPT {
401 mStorage = Storage{};
415 "function_list requires a void returning function signature.");
420template <
typename... Args>
421class function_list<void(Args...)> {
423 using FunctionType = function<void(Args...)>;
425 struct FunctionEntry {
430 FunctionEntry()
FL_NOEXCEPT : id(0), priority(0), fn() {}
431 FunctionEntry(
int idParam,
int priorityParam, FunctionType fnParam)
FL_NOEXCEPT
432 : id(idParam), priority(priorityParam), fn(fnParam) {}
437 FunctionVector mFunctions;
440 bool mNeedsCompact =
false;
443 function_list()
FL_NOEXCEPT : mFunctions(), mIdCounter(0), mNeedsCompact(
false) {}
444 function_list(
const function_list& other)
FL_NOEXCEPT
445 : mFunctions(other.mFunctions), mIdCounter(other.mIdCounter), mNeedsCompact(other.mNeedsCompact) {}
447 : mFunctions(
fl::move(other.mFunctions)), mIdCounter(other.mIdCounter), mNeedsCompact(other.mNeedsCompact) {}
448 function_list& operator=(
const function_list& other)
FL_NOEXCEPT {
449 if (
this != &other) {
450 mFunctions = other.mFunctions;
451 mIdCounter = other.mIdCounter;
452 mNeedsCompact = other.mNeedsCompact;
456 function_list& operator=(function_list&& other)
FL_NOEXCEPT {
457 if (
this != &other) {
458 mFunctions =
fl::move(other.mFunctions);
459 mIdCounter = other.mIdCounter;
460 mNeedsCompact = other.mNeedsCompact;
464 ~function_list() =
default;
466 int add(function<
void(Args...)> fn,
int priority = 0)
FL_NOEXCEPT {
467 int id = mIdCounter++;
468 mFunctions.push_back(FunctionEntry(
id, priority, fn));
474 for (
size_t i = 0; i < mFunctions.size(); ++i) {
475 if (mFunctions[i].
id ==
id) {
476 mFunctions[i].fn.clear();
477 mNeedsCompact =
true;
489 if (!mNeedsCompact)
return;
490 size_t write_pos = 0;
491 for (
size_t read_pos = 0; read_pos < mFunctions.size(); ++read_pos) {
492 if (mFunctions[read_pos].fn) {
493 if (write_pos != read_pos) {
494 mFunctions[write_pos] = mFunctions[read_pos];
499 mFunctions.resize(write_pos);
500 mNeedsCompact =
false;
506 for (
const auto& entry : mFunctions) {
513 bool empty()
const FL_NOEXCEPT {
return size() == 0; }
516 explicit operator bool()
const FL_NOEXCEPT {
return !empty(); }
519 if (mFunctions.empty())
return;
523 const size_t invoke_size = mFunctions.size();
525 if (invoke_size == 0) {
531 for (
size_t i = 0; i < invoke_size; ++i) {
532 if (!mFunctions[i].fn)
continue;
534 int p = mFunctions[i].priority;
536 if (priorities.
find(p) == priorities.
end()) {
545 for (
size_t p_idx = 0; p_idx < priorities.
size(); ++p_idx) {
546 int current_priority = priorities[p_idx];
547 for (
size_t i = 0; i < invoke_size; ++i) {
548 if (mFunctions.empty()) {
551 if (mFunctions[i].fn && mFunctions[i].priority == current_priority) {
552 mFunctions[i].fn(
args...);
567template <
typename R,
typename... Args>
568class function_list<R(Args...)> {
570 "function_list only supports void return type. "
571 "Use function_list<void(Args...)> instead of function_list<ReturnType(Args...)>.");