38 {
39
40
41
42
43template <typename T> struct is_function_pointer {
44 static constexpr bool value = false;
45};
46
47template <typename R, typename... Args>
48struct is_function_pointer<R(*)(Args...)> {
49 static constexpr bool value = true;
50};
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70template <typename> class function;
71
72template <typename R, typename... Args>
74private:
76
77
78
79
80 enum class Op :
fl::u8 { Destroy, Copy, Move };
81
82
83 using Invoker = R (*)(const void* src, Args...);
84
85
86
87
88
89
90
91
92 using Manager = void (*)(void* dst, void* src, Op op);
93
94
96 Invoker mInvoker;
97 Manager mManager;
98 bool mHasValue;
99
100
101
102
103 template <typename R2>
104 static typename enable_if<!is_void<R2>::value, R2>::type
106
107 template <typename R2>
108 static typename enable_if<is_void<R2>::value, R2>::type
110
111 static R null_invoker(
const void* , Args... )
FL_NO_EXCEPT {
112 return null_return_impl<R>();
113 }
114 static void null_manager(
void* ,
void* , Op )
FL_NO_EXCEPT {}
115
116
117
118
119
120 template <typename Func>
124 Func* f = static_cast<Func*>(static_cast<void*>(tmp));
125 return (*f)(
args...);
126 }
127
128
129
130
131 template <fl::size N>
132 static void trivial_manager(
void* dst,
void* src, Op op)
FL_NO_EXCEPT {
133 switch (op) {
134 case Op::Destroy:
135
136 break;
137 case Op::Copy:
138 case Op::Move:
140 break;
141 }
142 }
143
144
145 template <typename Func>
146 static void non_trivial_manager(
void* dst,
void* src, Op op)
FL_NO_EXCEPT {
147 switch (op) {
148 case Op::Destroy: {
149 Func* f = static_cast<Func*>(dst);
150 f->~Func();
151 break;
152 }
153 case Op::Copy: {
154 const Func* sf = static_cast<const Func*>(static_cast<const void*>(src));
155 new (dst) Func(*sf);
156 break;
157 }
158 case Op::Move: {
159 Func* sf = static_cast<Func*>(src);
161 break;
162 }
163 }
164 }
165
166
167
168
169
170
171
172
173 template <typename Func>
174 struct HeapHolder {
175 fl::shared_ptr<Func> ptr;
177 return (*ptr)(
args...);
178 }
179 };
180
181
182
183
184
185 template <typename Func>
187 using FBare = typename remove_reference<Func>::type;
189 "Callable requires stricter alignment than SBO provides.");
191 integral_constant<bool, (sizeof(FBare) <= kSboSize)>{});
192 }
193
194 template <typename Func>
195 void init_with_impl(Func&& f, true_type )
FL_NO_EXCEPT {
196 using FBare = typename remove_reference<Func>::type;
198 mInvoker = &functor_invoker<FBare>;
199 mManager = is_trivially_copyable<FBare>::value
200 ? &trivial_manager<sizeof(FBare)>
201 : &non_trivial_manager<FBare>;
202 mHasValue = true;
203 }
204
205 template <typename Func>
206 void init_with_impl(Func&& f, false_type )
FL_NO_EXCEPT {
207 using FBare = typename remove_reference<Func>::type;
208#ifdef FL_FUNCTION_NO_HEAP_FALLBACK
209
210
211
212 (void)f;
214 "fl::function: capture exceeds FASTLED_INLINE_LAMBDA_SIZE "
215 "and FL_FUNCTION_NO_HEAP_FALLBACK is defined. "
216 "Either reduce the captured state, or bump "
217 "FASTLED_INLINE_LAMBDA_SIZE for this build, or "
218 "undef FL_FUNCTION_NO_HEAP_FALLBACK to re-enable "
219 "the shared_ptr-backed heap fallback.");
220#else
221 using Holder = HeapHolder<FBare>;
223 "shared_ptr too large for SBO; bump FASTLED_INLINE_LAMBDA_SIZE.");
225 mInvoker = &functor_invoker<Holder>;
226
227
228 mManager = &non_trivial_manager<Holder>;
229 mHasValue = true;
230#endif
231 }
232
233
235 if (mHasValue) {
236 mManager(mBytes, nullptr, Op::Destroy);
237 mHasValue = false;
238 }
239 mInvoker = &null_invoker;
240 mManager = &null_manager;
241 }
242
243
244
245
246
247 template <typename C>
248 struct NonConstMemberWrapper {
249 C* obj;
250 R (C::*mf)(Args...);
252 return (obj->*mf)(
args...);
253 }
254 };
255
256 template <typename C>
257 struct ConstMemberWrapper {
258 const C* obj;
259 R (C::*mf)(Args...) const;
261 return (obj->*mf)(
args...);
262 }
263 };
264
265public:
267 : mInvoker(&null_invoker), mManager(&null_manager), mHasValue(false) {
268
269
271 }
272
273
275 : mInvoker(other.mInvoker), mManager(other.mManager), mHasValue(other.mHasValue) {
277 if (mHasValue) {
278
279
280
281 mManager(mBytes, const_cast<char*>(other.mBytes), Op::Copy);
282 }
283 }
284
285
287 : mInvoker(other.mInvoker), mManager(other.mManager), mHasValue(other.mHasValue) {
289 if (mHasValue) {
290 mManager(mBytes, other.mBytes, Op::Move);
291
292 other.reset();
293 }
294 }
295
296
297 function& operator=(
const function& other)
FL_NO_EXCEPT {
298 if (this == &other) return *this;
299 reset();
300 mInvoker = other.mInvoker;
301 mManager = other.mManager;
302 mHasValue = other.mHasValue;
303 if (mHasValue) {
304 mManager(mBytes, const_cast<char*>(other.mBytes), Op::Copy);
305 }
306 return *this;
307 }
308
309
311 if (this == &other) return *this;
312 reset();
313 mInvoker = other.mInvoker;
314 mManager = other.mManager;
315 mHasValue = other.mHasValue;
316 if (mHasValue) {
317 mManager(mBytes, other.mBytes, Op::Move);
318 other.reset();
319 }
320 return *this;
321 }
322
324 reset();
325 }
326
327
329 : mInvoker(&null_invoker), mManager(&null_manager), mHasValue(false) {
331 if (fp) {
332 init_with(fp);
333 }
334 }
335
336
337
338 template <typename Func,
339 typename = enable_if_t<!is_member_function_pointer<Func>::value &&
340 !is_function_pointer<Func>::value &&
341 !is_same<typename remove_reference<Func>::type, function>::value>>
343 : mInvoker(&null_invoker), mManager(&null_manager), mHasValue(false) {
346 }
347
348
349 template <typename C>
351 : mInvoker(&null_invoker), mManager(&null_manager), mHasValue(false) {
353 init_with(NonConstMemberWrapper<C>{obj, mf});
354 }
355
356
357 template <typename C>
358 function(R (C::*mf)(Args...)
const,
const C* obj)
FL_NO_EXCEPT
359 : mInvoker(&null_invoker), mManager(&null_manager), mHasValue(false) {
361 init_with(ConstMemberWrapper<C>{obj, mf});
362 }
363
365 return mInvoker(mBytes,
args...);
366 }
367
368 explicit operator bool() const
FL_NO_EXCEPT {
return mHasValue; }
369
371
373
374 return mHasValue == o.mHasValue;
375 }
376
378};
379
380
381
382
383
384
385
386template <typename T>
387class function_list {
389 "function_list requires a void returning function signature.");
390};
391
392
393
394template <typename... Args>
395class function_list<void(Args...)> {
396 private:
397 using FunctionType = function<void(Args...)>;
398
399 struct FunctionEntry {
400 int id;
401 int priority;
402 FunctionType fn;
403
404 FunctionEntry()
FL_NO_EXCEPT :
id(0), priority(0), fn() {}
405 FunctionEntry(
int idParam,
int priorityParam, FunctionType fnParam)
FL_NO_EXCEPT
406 : id(idParam), priority(priorityParam), fn(fnParam) {}
407 };
408
409 using FunctionVector = fl::vector<FunctionEntry>;
410
411 FunctionVector mFunctions;
412 int mIdCounter = 0;
413
414 bool mNeedsCompact = false;
415
416 public:
417 function_list()
FL_NO_EXCEPT : mFunctions(), mIdCounter(0), mNeedsCompact(false) {}
419 : mFunctions(other.mFunctions), mIdCounter(other.mIdCounter), mNeedsCompact(other.mNeedsCompact) {}
421 : mFunctions(
fl::move(other.mFunctions)), mIdCounter(other.mIdCounter), mNeedsCompact(other.mNeedsCompact) {}
422 function_list& operator=(
const function_list& other)
FL_NO_EXCEPT {
423 if (this != &other) {
424 mFunctions = other.mFunctions;
425 mIdCounter = other.mIdCounter;
426 mNeedsCompact = other.mNeedsCompact;
427 }
428 return *this;
429 }
430 function_list& operator=(function_list&& other)
FL_NO_EXCEPT {
431 if (this != &other) {
432 mFunctions =
fl::move(other.mFunctions);
433 mIdCounter = other.mIdCounter;
434 mNeedsCompact = other.mNeedsCompact;
435 }
436 return *this;
437 }
438 ~function_list() = default;
439
441 int id = mIdCounter++;
442 mFunctions.push_back(FunctionEntry(id, priority, fn));
443 return id;
444 }
445
447
448 for (size_t i = 0; i < mFunctions.size(); ++i) {
449 if (mFunctions[i].id == id) {
450 mFunctions[i].fn.clear();
451 mNeedsCompact = true;
452 }
453 }
454 }
455
457 mFunctions.clear();
458 }
459
460
461
463 if (!mNeedsCompact) return;
464 size_t write_pos = 0;
465 for (size_t read_pos = 0; read_pos < mFunctions.size(); ++read_pos) {
466 if (mFunctions[read_pos].fn) {
467 if (write_pos != read_pos) {
468 mFunctions[write_pos] = mFunctions[read_pos];
469 }
470 write_pos++;
471 }
472 }
473 mFunctions.resize(write_pos);
474 mNeedsCompact = false;
475 }
476
477
479 fl::size count = 0;
480 for (const auto& entry : mFunctions) {
481 if (entry.fn) {
482 ++count;
483 }
484 }
485 return count;
486 }
488
489
490 explicit operator bool() const
FL_NO_EXCEPT {
return !empty(); }
491
493 if (mFunctions.empty()) return;
494
495 compact();
496
497 const size_t invoke_size = mFunctions.size();
498
499 if (invoke_size == 0) {
500 return;
501 }
502
503
505 for (size_t i = 0; i < invoke_size; ++i) {
506 if (!mFunctions[i].fn) continue;
507
508 int p = mFunctions[i].priority;
509
510 if (priorities.
find(p) == priorities.
end()) {
512 }
513 }
514
515
517
518
519 for (
size_t p_idx = 0; p_idx < priorities.
size(); ++p_idx) {
520 int current_priority = priorities[p_idx];
521 for (size_t i = 0; i < invoke_size; ++i) {
522 if (mFunctions.empty()) {
523 return;
524 }
525 if (mFunctions[i].fn && mFunctions[i].priority == current_priority) {
526 mFunctions[i].fn(
args...);
527 }
528 }
529 }
530 compact();
531 }
532
533
536 }
537};
538
539
540
541template <typename R, typename... Args>
542class function_list<R(Args...)> {
544 "function_list only supports void return type. "
545 "Use function_list<void(Args...)> instead of function_list<ReturnType(Args...)>.");
546};
547
548}
fl::size size() const FL_NO_EXCEPT
void push_back(const T &value) FL_NO_EXCEPT
iterator find(const T &value) FL_NO_EXCEPT
iterator end() FL_NO_EXCEPT
iterator begin() FL_NO_EXCEPT
#define FASTLED_INLINE_LAMBDA_SIZE
constexpr remove_reference< T >::type && move(T &&t) FL_NO_EXCEPT
void clear(CRGB(&arr)[N])
void * memcpy(void *dest, const void *src, size_t n) FL_NO_EXCEPT
Iterator remove(Iterator first, Iterator last, const T &value) FL_NO_EXCEPT
FASTLED_FORCE_INLINE bool operator==(const CRGB &lhs, const CRGB &rhs) FL_NO_EXCEPT
Check if two CRGB objects have the same color data.
shared_ptr< T > make_shared(Args &&... args) FL_NO_EXCEPT
void * memset(void *s, int c, size_t n) FL_NO_EXCEPT
constexpr T && forward(typename remove_reference< T >::type &t) FL_NO_EXCEPT
float add(float &a, float &b)
auto invoke(F &&f, T1 &&t1, Args &&... args) FL_NO_EXCEPT -> 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)...))>
VectorN< T, INLINED_SIZE > vector_inlined
void sort(Iterator first, Iterator last, Compare comp) FL_NO_EXCEPT
FASTLED_FORCE_INLINE bool operator!=(const CRGB &lhs, const CRGB &rhs) FL_NO_EXCEPT
Check if two CRGB objects do not have the same color data.
#define FL_STATIC_ASSERT(...)