45 {
46
47
48
49
50template <typename T> struct is_function_pointer {
51 static constexpr bool value = false;
52};
53
54template <typename R, typename... Args>
55struct is_function_pointer<R(*)(Args...)> {
56 static constexpr bool value = true;
57};
58
59
60
61
62
63
64
65
66
67
68template <typename> class function;
69
70template <typename R, typename... Args>
72private:
73#if FL_FUNCTION_FULL_VARIANT
74 struct CallableBase {
77 };
78
79 template <typename F>
80 struct Callable : CallableBase {
81 F f;
84 };
85#endif
86
87
88 struct FreeFunctionCallable {
89 R (*func_ptr)(Args...);
90
91 FreeFunctionCallable(R (*fp)(Args...))
FL_NOEXCEPT : func_ptr(fp) {}
92
94 return func_ptr(
args...);
95 }
96 };
97
98
99
100
102
103 struct InlinedLambda {
104
105
107
108
109 R (*invoker)(
const InlinedLambda& storage, Args...
args);
110 void (*destructor)(InlinedLambda& storage);
111
112 template <typename Function>
115 "Lambda/functor too large for inline storage");
117 "Lambda/functor requires stricter alignment than storage provides");
118
119
121
122
124
125
126 invoker = &invoke_lambda<Function>;
127 destructor = &destroy_lambda<Function>;
128 }
129
130
131 InlinedLambda(
const InlinedLambda& other)
FL_NOEXCEPT
132 : invoker(other.invoker), destructor(other.destructor) {
133
134
135 fl::memcpy(bytes, other.bytes, kInlineLambdaSize);
136 }
137
138
140 : invoker(other.invoker), destructor(other.destructor) {
141 fl::memcpy(bytes, other.bytes, kInlineLambdaSize);
142
143 other.destructor = nullptr;
144 }
145
147 if (destructor) {
148 destructor(*this);
149 }
150 }
151
152 template <typename FUNCTOR>
153 static R invoke_lambda(
const InlinedLambda& storage, Args...
args)
FL_NOEXCEPT {
154
155 FL_ALIGN_AS(FUNCTOR)
char temp_storage[
sizeof(FUNCTOR)];
156
157 fl::memcpy(temp_storage, storage.bytes,
sizeof(FUNCTOR));
158
159 FUNCTOR* f = static_cast<FUNCTOR*>(static_cast<void*>(temp_storage));
160
161 return (*f)(
args...);
162 }
163
164 template <typename FUNCTOR>
165 static void destroy_lambda(InlinedLambda& storage)
FL_NOEXCEPT {
166
167
168
169
170
171
172
173 FUNCTOR* obj_ptr = static_cast<FUNCTOR*>(static_cast<void*>(storage.bytes));
174 obj_ptr->~FUNCTOR();
175 }
176
178 return invoker(*
this,
args...);
179 }
180 };
181
182#if FL_FUNCTION_FULL_VARIANT
183
184 struct MemberCallableBase {
186 virtual ~MemberCallableBase()
FL_NOEXCEPT = default;
187 };
188
189
190 struct NonConstMemberCallable : MemberCallableBase {
191 void* obj;
192
193 union MemberFuncStorage {
194 char bytes[sizeof(R (NonConstMemberCallable::*)(Args...))];
195
196 void* alignment_dummy;
197 } member_func_storage;
198
199
200 R (*invoker)(
void* obj,
const MemberFuncStorage& mfp, Args...
args);
201
202 template <typename C>
203 NonConstMemberCallable(C* o, R (C::*mf)(Args...))
FL_NOEXCEPT : obj(o) {
204
206 "Member function pointer too large");
207 fl::memcpy(member_func_storage.bytes, &mf,
sizeof(mf));
208
209 invoker = &invoke_nonconst_member<C>;
210 }
211
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...);
218 }
219
221 return invoker(obj, member_func_storage,
args...);
222 }
223 };
224
225
226 struct ConstMemberCallable : MemberCallableBase {
227 const void* obj;
228
229 union MemberFuncStorage {
230 char bytes[sizeof(R (ConstMemberCallable::*)(Args...) const)];
231
232 void* alignment_dummy;
233 } member_func_storage;
234
235
236 R (*invoker)(
const void* obj,
const MemberFuncStorage& mfp, Args...
args);
237
238 template <typename C>
239 ConstMemberCallable(
const C* o, R (C::*mf)(Args...)
const)
FL_NOEXCEPT : obj(o) {
240
242 "Member function pointer too large");
243 fl::memcpy(member_func_storage.bytes, &mf,
sizeof(mf));
244
245 invoker = &invoke_const_member<C>;
246 }
247
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...);
254 }
255
257 return invoker(obj, member_func_storage,
args...);
258 }
259 };
260#endif
261
262
263
264
265
266#if FL_FUNCTION_FULL_VARIANT
267 using Storage = variant<fl::shared_ptr<CallableBase>, FreeFunctionCallable, InlinedLambda, NonConstMemberCallable, ConstMemberCallable>;
268#else
269 using Storage = variant<FreeFunctionCallable, InlinedLambda>;
270#endif
271 Storage mStorage;
272
273
274 template<typename ReturnType>
275 typename enable_if<!is_void<ReturnType>::value, ReturnType>::type
277 return ReturnType{};
278 }
279
280 template<typename ReturnType>
281 typename enable_if<is_void<ReturnType>::value, ReturnType>::type
283 return;
284 }
285
286public:
288
289
290 function(const function& other)
FL_NOEXCEPT : mStorage(other.mStorage) {}
291
292
294
295
296 function& operator=(
const function& other)
FL_NOEXCEPT {
297 if (this != &other) {
298 mStorage = other.mStorage;
299 }
300 return *this;
301 }
302
303
304 function& operator=(function&& other)
FL_NOEXCEPT {
305 if (this != &other) {
306 mStorage =
fl::move(other.mStorage);
307 }
308 return *this;
309 }
310
311
313 mStorage = FreeFunctionCallable(fp);
314 }
315
316
317 template <typename F, typename = enable_if_t<!is_member_function_pointer<F>::value && !is_function_pointer<F>::value>>
319
320 construct_lambda_or_functor(
fl::move(f),
typename conditional<
sizeof(F) <= kInlineLambdaSize, true_type, false_type>::type{});
321 }
322
323#if FL_FUNCTION_FULL_VARIANT
324
325 template <typename C>
326 function(R (C::*mf)(Args...), C* obj)
FL_NOEXCEPT {
327 mStorage = NonConstMemberCallable(obj, mf);
328 }
329
330
331 template <typename C>
332 function(R (C::*mf)(Args...)
const,
const C* obj)
FL_NOEXCEPT {
333 mStorage = ConstMemberCallable(obj, mf);
334 }
335#endif
336
338
339#if FL_FUNCTION_FULL_VARIANT
340 if (auto* heap_callable = mStorage.template ptr<fl::shared_ptr<CallableBase>>()) {
341 return (*heap_callable)->invoke(
args...);
342 } else if (auto* free_func = mStorage.template ptr<FreeFunctionCallable>()) {
343#else
344 if (auto* free_func = mStorage.template ptr<FreeFunctionCallable>()) {
345#endif
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...);
354#endif
355 }
356
357 return default_return_helper<R>();
358 }
359
361 return !mStorage.empty();
362 }
363
365 mStorage = Storage{};
366 }
367
369
370
371 return mStorage.empty() == o.mStorage.empty();
372 }
373
375 return !(*this == o);
376 }
377
378private:
379
380 template <typename F>
381 void construct_lambda_or_functor(F f, true_type )
FL_NOEXCEPT {
382 mStorage = InlinedLambda(
fl::move(f));
383 }
384
385#if FL_FUNCTION_FULL_VARIANT
386
387 template <typename F>
388 void construct_lambda_or_functor(F f, false_type )
FL_NOEXCEPT {
390 }
391#else
392
393
394
395
396
397
398
399 template <typename F>
400 void construct_lambda_or_functor(F , false_type )
FL_NOEXCEPT {
401 mStorage = Storage{};
402 }
403#endif
404};
405
406
407
408
409
410
411
412template <typename T>
413class function_list {
415 "function_list requires a void returning function signature.");
416};
417
418
419
420template <typename... Args>
421class function_list<void(Args...)> {
422 private:
423 using FunctionType = function<void(Args...)>;
424
425 struct FunctionEntry {
426 int id;
427 int priority;
428 FunctionType fn;
429
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) {}
433 };
434
435 using FunctionVector = fl::vector<FunctionEntry>;
436
437 FunctionVector mFunctions;
438 int mIdCounter = 0;
439
440 bool mNeedsCompact = false;
441
442 public:
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;
453 }
454 return *this;
455 }
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;
461 }
462 return *this;
463 }
464 ~function_list() = default;
465
466 int add(function<
void(Args...)> fn,
int priority = 0)
FL_NOEXCEPT {
467 int id = mIdCounter++;
468 mFunctions.push_back(FunctionEntry(id, priority, fn));
469 return id;
470 }
471
473
474 for (size_t i = 0; i < mFunctions.size(); ++i) {
475 if (mFunctions[i].id == id) {
476 mFunctions[i].fn.clear();
477 mNeedsCompact = true;
478 }
479 }
480 }
481
483 mFunctions.clear();
484 }
485
486
487
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];
495 }
496 write_pos++;
497 }
498 }
499 mFunctions.resize(write_pos);
500 mNeedsCompact = false;
501 }
502
503
505 fl::size count = 0;
506 for (const auto& entry : mFunctions) {
507 if (entry.fn) {
508 ++count;
509 }
510 }
511 return count;
512 }
513 bool empty() const
FL_NOEXCEPT {
return size() == 0; }
514
515
516 explicit operator bool() const
FL_NOEXCEPT {
return !empty(); }
517
519 if (mFunctions.empty()) return;
520
521 compact();
522
523 const size_t invoke_size = mFunctions.size();
524
525 if (invoke_size == 0) {
526 return;
527 }
528
529
531 for (size_t i = 0; i < invoke_size; ++i) {
532 if (!mFunctions[i].fn) continue;
533
534 int p = mFunctions[i].priority;
535
536 if (priorities.
find(p) == priorities.
end()) {
538 }
539 }
540
541
543
544
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()) {
549 return;
550 }
551 if (mFunctions[i].fn && mFunctions[i].priority == current_priority) {
552 mFunctions[i].fn(
args...);
553 }
554 }
555 }
556 compact();
557 }
558
559
562 }
563};
564
565
566
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...)>.");
572};
573
574}
fl::size size() const FL_NOEXCEPT
iterator begin() FL_NOEXCEPT
iterator find(const T &value) FL_NOEXCEPT
iterator end() FL_NOEXCEPT
void push_back(const T &value) FL_NOEXCEPT
#define FASTLED_INLINE_LAMBDA_SIZE
void * memcpy(void *dest, const void *src, size_t n) FL_NOEXCEPT
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
void clear(CRGB(&arr)[N])
void * memset(void *s, int c, size_t n) FL_NOEXCEPT
FASTLED_FORCE_INLINE bool operator!=(const CRGB &lhs, const CRGB &rhs) FL_NOEXCEPT
Check if two CRGB objects do not have the same color data.
FASTLED_FORCE_INLINE bool operator==(const CRGB &lhs, const CRGB &rhs) FL_NOEXCEPT
Check if two CRGB objects have the same color data.
shared_ptr< T > make_shared(Args &&... args) FL_NOEXCEPT
float add(float &a, float &b)
auto invoke(F &&f, T1 &&t1, Args &&... args) FL_NOEXCEPT -> enable_if_t< is_member_function_pointer< typename remove_reference< F >::type >::value &&!detail::use_pointer_syntax< T1 >::value, decltype((fl::forward< T1 >(t1).*f)(fl::forward< Args >(args)...))>
void sort(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT
VectorN< T, INLINED_SIZE > vector_inlined
Iterator remove(Iterator first, Iterator last, const T &value) FL_NOEXCEPT
#define FL_STATIC_ASSERT(...)