FastLED 3.9.15
Loading...
Searching...
No Matches
algorithm.h
Go to the documentation of this file.
1#pragma once
2
4#include "fl/stl/move.h"
5#include "fl/math/random.h"
6#include "fl/stl/noexcept.h"
7
8namespace fl {
9
10template <typename Iterator>
11void reverse(Iterator first, Iterator last) FL_NOEXCEPT {
12 while ((first != last) && (first != --last)) {
13 swap(*first++, *last);
14 }
15}
16
17template <typename Iterator>
18Iterator max_element(Iterator first, Iterator last) FL_NOEXCEPT {
19 if (first == last) {
20 return last;
21 }
22
23 Iterator max_iter = first;
24 ++first;
25
26 while (first != last) {
27 if (*max_iter < *first) {
28 max_iter = first;
29 }
30 ++first;
31 }
32
33 return max_iter;
34}
35
36template <typename Iterator, typename Compare>
37Iterator max_element(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT {
38 if (first == last) {
39 return last;
40 }
41
42 Iterator max_iter = first;
43 ++first;
44
45 while (first != last) {
46 if (comp(*max_iter, *first)) {
47 max_iter = first;
48 }
49 ++first;
50 }
51
52 return max_iter;
53}
54
55template <typename Iterator>
56Iterator min_element(Iterator first, Iterator last) FL_NOEXCEPT {
57 if (first == last) {
58 return last;
59 }
60
61 Iterator min_iter = first;
62 ++first;
63
64 while (first != last) {
65 if (*first < *min_iter) {
66 min_iter = first;
67 }
68 ++first;
69 }
70
71 return min_iter;
72}
73
74template <typename Iterator, typename Compare>
75Iterator min_element(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT {
76 if (first == last) {
77 return last;
78 }
79
80 Iterator min_iter = first;
81 ++first;
82
83 while (first != last) {
84 if (comp(*first, *min_iter)) {
85 min_iter = first;
86 }
87 ++first;
88 }
89
90 return min_iter;
91}
92
93
94
95template <typename Iterator1, typename Iterator2>
96bool equal(Iterator1 first1, Iterator1 last1, Iterator2 first2) FL_NOEXCEPT {
97 while (first1 != last1) {
98 if (*first1 != *first2) {
99 return false;
100 }
101 ++first1;
102 ++first2;
103 }
104 return true;
105}
106
107template <typename Iterator1, typename Iterator2, typename BinaryPredicate>
108bool equal(Iterator1 first1, Iterator1 last1, Iterator2 first2, BinaryPredicate pred) FL_NOEXCEPT {
109 while (first1 != last1) {
110 if (!pred(*first1, *first2)) {
111 return false;
112 }
113 ++first1;
114 ++first2;
115 }
116 return true;
117}
118
119template <typename Iterator1, typename Iterator2>
120bool equal(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) FL_NOEXCEPT {
121 while (first1 != last1 && first2 != last2) {
122 if (*first1 != *first2) {
123 return false;
124 }
125 ++first1;
126 ++first2;
127 }
128 return first1 == last1 && first2 == last2;
129}
130
131template <typename Iterator1, typename Iterator2, typename BinaryPredicate>
132bool equal(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2, BinaryPredicate pred) FL_NOEXCEPT {
133 while (first1 != last1 && first2 != last2) {
134 if (!pred(*first1, *first2)) {
135 return false;
136 }
137 ++first1;
138 ++first2;
139 }
140 return first1 == last1 && first2 == last2;
141}
142
143// Lexicographical comparison - compares two ranges element by element
144// Returns true if the first range is lexicographically less than the second
145template <typename Iterator1, typename Iterator2>
146bool lexicographical_compare(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) FL_NOEXCEPT {
147 while (first1 != last1 && first2 != last2) {
148 if (*first1 < *first2) {
149 return true;
150 }
151 if (*first2 < *first1) {
152 return false;
153 }
154 ++first1;
155 ++first2;
156 }
157 // If we've exhausted first1 but not first2, first1 is less
158 // If we've exhausted both, they're equal (return false)
159 // If we've exhausted first2 but not first1, first2 is less (return false)
160 return (first1 == last1) && (first2 != last2);
161}
162
163// Lexicographical comparison with custom comparator
164template <typename Iterator1, typename Iterator2, typename Compare>
165bool lexicographical_compare(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2, Compare comp) FL_NOEXCEPT {
166 while (first1 != last1 && first2 != last2) {
167 if (comp(*first1, *first2)) {
168 return true;
169 }
170 if (comp(*first2, *first1)) {
171 return false;
172 }
173 ++first1;
174 ++first2;
175 }
176 // If we've exhausted first1 but not first2, first1 is less
177 // If we've exhausted both, they're equal (return false)
178 // If we've exhausted first2 but not first1, first2 is less (return false)
179 return (first1 == last1) && (first2 != last2);
180}
181
182template <typename Container1, typename Container2>
183bool equal_container(const Container1& c1, const Container2& c2) FL_NOEXCEPT {
184 fl::size size1 = c1.size();
185 fl::size size2 = c2.size();
186 if (size1 != size2) {
187 return false;
188 }
189 return equal(c1.begin(), c1.end(), c2.begin(), c2.end());
190}
191
192template <typename Container1, typename Container2, typename BinaryPredicate>
193bool equal_container(const Container1& c1, const Container2& c2, BinaryPredicate pred) FL_NOEXCEPT {
194 fl::size size1 = c1.size();
195 fl::size size2 = c2.size();
196 if (size1 != size2) {
197 return false;
198 }
199 return equal(c1.begin(), c1.end(), c2.begin(), c2.end(), pred);
200}
201
202
203template <typename Iterator, typename T>
204void fill(Iterator first, Iterator last, const T& value) FL_NOEXCEPT {
205 while (first != last) {
206 *first = value;
207 ++first;
208 }
209}
210
211template <typename Iterator, typename T>
212Iterator find(Iterator first, Iterator last, const T& value) FL_NOEXCEPT {
213 while (first != last) {
214 if (*first == value) {
215 return first;
216 }
217 ++first;
218 }
219 return last;
220}
221
222template <typename Iterator, typename UnaryPredicate>
223Iterator find_if(Iterator first, Iterator last, UnaryPredicate pred) FL_NOEXCEPT {
224 while (first != last) {
225 if (pred(*first)) {
226 return first;
227 }
228 ++first;
229 }
230 return last;
231}
232
233template <typename Iterator, typename UnaryPredicate>
234Iterator find_if_not(Iterator first, Iterator last, UnaryPredicate pred) FL_NOEXCEPT {
235 while (first != last) {
236 if (!pred(*first)) {
237 return first;
238 }
239 ++first;
240 }
241 return last;
242}
243
244template <typename Iterator, typename T>
245void replace(Iterator first, Iterator last, const T& old_value, const T& new_value) FL_NOEXCEPT {
246 while (first != last) {
247 if (*first == old_value) {
248 *first = new_value;
249 }
250 ++first;
251 }
252}
253
254template <typename Iterator, typename UnaryPredicate, typename T>
255void replace_if(Iterator first, Iterator last, UnaryPredicate pred, const T& new_value) FL_NOEXCEPT {
256 while (first != last) {
257 if (pred(*first)) {
258 *first = new_value;
259 }
260 ++first;
261 }
262}
263
264template <typename Iterator, typename T>
265Iterator remove(Iterator first, Iterator last, const T& value) FL_NOEXCEPT {
266 Iterator result = first;
267 while (first != last) {
268 if (!(*first == value)) {
269 if (result != first) {
270 *result = fl::move(*first);
271 }
272 ++result;
273 }
274 ++first;
275 }
276 return result;
277}
278
279template <typename Iterator, typename UnaryPredicate>
280Iterator remove_if(Iterator first, Iterator last, UnaryPredicate pred) FL_NOEXCEPT {
281 Iterator result = first;
282 while (first != last) {
283 if (!pred(*first)) {
284 if (result != first) {
285 *result = fl::move(*first);
286 }
287 ++result;
288 }
289 ++first;
290 }
291 return result;
292}
293
294namespace detail {
295
296// Insertion sort implementation for small arrays
297template <typename Iterator, typename Compare>
298void insertion_sort(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT {
299 if (first == last) return;
300
301 for (Iterator i = first + 1; i != last; ++i) {
302 auto value = fl::move(*i);
303 Iterator j = i;
304
305 while (j != first && comp(value, *(j - 1))) {
306 *j = fl::move(*(j - 1));
307 --j;
308 }
309
310 *j = fl::move(value);
311 }
312}
313
314// Median-of-three pivot selection
315template <typename Iterator, typename Compare>
316Iterator median_of_three(Iterator first, Iterator middle, Iterator last, Compare comp) FL_NOEXCEPT {
317 if (comp(*middle, *first)) {
318 if (comp(*last, *middle)) {
319 return middle;
320 } else if (comp(*last, *first)) {
321 return last;
322 } else {
323 return first;
324 }
325 } else {
326 if (comp(*last, *first)) {
327 return first;
328 } else if (comp(*last, *middle)) {
329 return last;
330 } else {
331 return middle;
332 }
333 }
334}
335
336// Partition function for quicksort
337template <typename Iterator, typename Compare>
338Iterator partition(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT {
339 Iterator middle = first + (last - first) / 2;
340 Iterator pivot_iter = median_of_three(first, middle, last - 1, comp);
341
342 // Move pivot to end
343 swap(*pivot_iter, *(last - 1));
344 Iterator pivot = last - 1;
345
346 Iterator i = first;
347 for (Iterator j = first; j != pivot; ++j) {
348 if (comp(*j, *pivot)) {
349 swap(*i, *j);
350 ++i;
351 }
352 }
353
354 swap(*i, *pivot);
355 return i;
356}
357
358// Heapsort implementation (fallback for deep recursion)
359template <typename Iterator, typename Compare>
360void sift_down(Iterator first, Iterator start, Iterator end, Compare comp) FL_NOEXCEPT {
361 Iterator root = start;
362
363 while (root - first <= (end - first - 2) / 2) {
364 Iterator child = first + 2 * (root - first) + 1;
365 Iterator swap_iter = root;
366
367 if (comp(*swap_iter, *child)) {
368 swap_iter = child;
369 }
370
371 if (child + 1 <= end && comp(*swap_iter, *(child + 1))) {
372 swap_iter = child + 1;
373 }
374
375 if (swap_iter == root) {
376 return;
377 } else {
378 swap(*root, *swap_iter);
379 root = swap_iter;
380 }
381 }
382}
383
384template <typename Iterator, typename Compare>
385void heapify(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT {
386 Iterator start = first + (last - first - 2) / 2;
387
388 while (true) {
389 sift_down(first, start, last - 1, comp);
390 if (start == first) {
391 break;
392 }
393 --start;
394 }
395}
396
397template <typename Iterator, typename Compare>
398void heap_sort(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT {
399 heapify(first, last, comp);
400
401 Iterator end = last - 1;
402 while (end > first) {
403 swap(*end, *first);
404 sift_down(first, first, end - 1, comp);
405 --end;
406 }
407}
408
409// Quicksort implementation
410template <typename Iterator, typename Compare>
411void quicksort_impl(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT {
412 if (last - first <= 16) { // Use insertion sort for small arrays
413 insertion_sort(first, last, comp);
414 return;
415 }
416
417 Iterator pivot = partition(first, last, comp);
418 quicksort_impl(first, pivot, comp);
419 quicksort_impl(pivot + 1, last, comp);
420}
421
422// Rotate elements in range [first, last) so that middle becomes the new first
423template <typename Iterator>
424void rotate_impl(Iterator first, Iterator middle, Iterator last) FL_NOEXCEPT {
425 if (first == middle || middle == last) {
426 return;
427 }
428
429 Iterator next = middle;
430 while (first != next) {
431 swap(*first++, *next++);
432 if (next == last) {
433 next = middle;
434 } else if (first == middle) {
435 middle = next;
436 }
437 }
438}
439
440// Find the position where value should be inserted in sorted range [first, last)
441template <typename Iterator, typename T, typename Compare>
442Iterator lower_bound_impl(Iterator first, Iterator last, const T& value, Compare comp) FL_NOEXCEPT {
443 auto count = last - first;
444 while (count > 0) {
445 auto step = count / 2;
446 Iterator it = first + step;
447 if (comp(*it, value)) {
448 first = ++it;
449 count -= step + 1;
450 } else {
451 count = step;
452 }
453 }
454 return first;
455}
456
457// In-place merge operation for merge sort (stable sort)
458template <typename Iterator, typename Compare>
459void merge_inplace(Iterator first, Iterator middle, Iterator last, Compare comp) FL_NOEXCEPT {
460 // If one of the ranges is empty, nothing to merge
461 if (first == middle || middle == last) {
462 return;
463 }
464
465 // If arrays are small enough, use insertion-based merge
466 auto left_size = middle - first;
467 auto right_size = last - middle;
468 if (left_size + right_size <= 32) {
469 // Simple insertion-based merge for small arrays
470 Iterator left = first;
471 Iterator right = middle;
472
473 while (left < middle && right < last) {
474 if (!comp(*right, *left)) {
475 // left element is in correct position
476 ++left;
477 } else {
478 // right element needs to be inserted into left part
479 auto value = fl::move(*right);
480 Iterator shift_end = right;
481 Iterator shift_start = left;
482
483 // Shift elements to make room
484 while (shift_end > shift_start) {
485 *shift_end = fl::move(*(shift_end - 1));
486 --shift_end;
487 }
488
489 *left = fl::move(value);
490 ++left;
491 ++middle; // middle has shifted right
492 ++right;
493 }
494 }
495 return;
496 }
497
498 // For larger arrays, use rotation-based merge
499 if (left_size == 0 || right_size == 0) {
500 return;
501 }
502
503 if (left_size == 1) {
504 // Find insertion point for the single left element in right array
505 Iterator pos = lower_bound_impl(middle, last, *first, comp);
506 rotate_impl(first, middle, pos);
507 return;
508 }
509
510 if (right_size == 1) {
511 // Find insertion point for the single right element in left array
512 Iterator pos = lower_bound_impl(first, middle, *(last - 1), comp);
513 rotate_impl(pos, middle, last);
514 return;
515 }
516
517 // Divide both arrays and recursively merge
518 Iterator left_mid = first + left_size / 2;
519 Iterator right_mid = lower_bound_impl(middle, last, *left_mid, comp);
520
521 // Rotate to bring the two middle parts together
522 rotate_impl(left_mid, middle, right_mid);
523
524 // Update middle position
525 Iterator new_middle = left_mid + (right_mid - middle);
526
527 // Recursively merge the two parts
528 merge_inplace(first, left_mid, new_middle, comp);
529 merge_inplace(new_middle, right_mid, last, comp);
530}
531
532// Merge sort implementation (stable, in-place)
533template <typename Iterator, typename Compare>
534void mergesort_impl(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT {
535 auto size = last - first;
536 if (size <= 16) { // Use insertion sort for small arrays (it's stable)
537 insertion_sort(first, last, comp);
538 return;
539 }
540
541 Iterator middle = first + size / 2;
542 mergesort_impl(first, middle, comp);
543 mergesort_impl(middle, last, comp);
544 merge_inplace(first, middle, last, comp);
545}
546
547} // namespace detail
548
549// Lower bound: find first position in sorted [first, last) where value could be inserted.
550template <typename Iterator, typename T, typename Compare>
551Iterator lower_bound(Iterator first, Iterator last, const T& value, Compare comp) FL_NOEXCEPT {
552 return detail::lower_bound_impl(first, last, value, comp);
553}
554
555template <typename Iterator, typename T>
556Iterator lower_bound(Iterator first, Iterator last, const T& value) FL_NOEXCEPT {
557 typedef typename fl::remove_reference<decltype(*first)>::type value_type;
558 return detail::lower_bound_impl(first, last, value,
559 [](const value_type& a, const T& b) { return a < b; });
560}
561
562// Sort function with custom comparator (using quicksort)
563template <typename Iterator, typename Compare>
564void sort(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT {
565 if (first == last || first + 1 == last) {
566 return; // Already sorted or empty
567 }
568
569 detail::quicksort_impl(first, last, comp);
570}
571
572// Sort function with default comparator
573template <typename Iterator>
574void sort(Iterator first, Iterator last) FL_NOEXCEPT {
575 // Use explicit template parameter to avoid C++14 auto in lambda
576 typedef typename fl::remove_reference<decltype(*first)>::type value_type;
577 sort(first, last, [](const value_type& a, const value_type& b) { return a < b; });
578}
579
580// Stable sort function with custom comparator (using merge sort)
581template <typename Iterator, typename Compare>
582void stable_sort(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT {
583 if (first == last || first + 1 == last) {
584 return; // Already sorted or empty
585 }
586
587 detail::mergesort_impl(first, last, comp);
588}
589
590// Stable sort function with default comparator
591template <typename Iterator>
592void stable_sort(Iterator first, Iterator last) FL_NOEXCEPT {
593 // Use explicit template parameter to avoid C++14 auto in lambda
594 typedef typename fl::remove_reference<decltype(*first)>::type value_type;
595 stable_sort(first, last, [](const value_type& a, const value_type& b) { return a < b; });
596}
597
598// Direct call to insertion sort — meant for call sites with statically
599// bounded input (typically <= 16-32 elements). Skips the runtime fall-through
600// inside `quicksort_impl`, so the compiler does NOT instantiate the
601// quicksort + partition + heap_sort body at all. Per-instantiation savings
602// land in the function symbol that anchors the static-init chain
603// (`ClocklessIdf5` on ESP32-S3). See #2886 / #2907.
604//
605// Use `sort_small` when:
606// - the container's max size is bounded by construction (e.g. fl::vector_inlined<T, N>)
607// and N is small (rule of thumb: <= 32);
608// - O(n^2) worst-case is acceptable.
609//
610// Use `fl::sort` (quicksort) when the container is unbounded or large.
611template <typename Iterator, typename Compare>
612void sort_small(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT {
613 if (first == last || first + 1 == last) {
614 return; // Already sorted or empty
615 }
616 detail::insertion_sort(first, last, comp);
617}
618
619template <typename Iterator>
620void sort_small(Iterator first, Iterator last) FL_NOEXCEPT {
621 typedef typename fl::remove_reference<decltype(*first)>::type value_type;
622 sort_small(first, last,
623 [](const value_type& a, const value_type& b) { return a < b; });
624}
625
626// Shuffle function with custom random generator (Fisher-Yates shuffle)
627template <typename Iterator, typename RandomGenerator>
628void shuffle(Iterator first, Iterator last, RandomGenerator& g) FL_NOEXCEPT {
629 if (first == last) {
630 return; // Empty range, nothing to shuffle
631 }
632
633 auto n = last - first;
634 for (auto i = n - 1; i > 0; --i) {
635 // Generate random index from 0 to i (inclusive)
636 auto j = g() % (i + 1);
637
638 // Swap elements at positions i and j
639 swap(*(first + i), *(first + j));
640 }
641}
642
643// Shuffle function with fl::math::random instance
644template <typename Iterator>
645void shuffle(Iterator first, Iterator last, math::random& rng) FL_NOEXCEPT {
646 if (first == last) {
647 return; // Empty range, nothing to shuffle
648 }
649
650 auto n = last - first;
651 for (auto i = n - 1; i > 0; --i) {
652 // Generate random index from 0 to i (inclusive)
653 auto j = rng(static_cast<u32>(i + 1));
654
655 // Swap elements at positions i and j
656 swap(*(first + i), *(first + j));
657 }
658}
659
660// Shuffle function with default random generator
661template <typename Iterator>
662void shuffle(Iterator first, Iterator last) FL_NOEXCEPT {
663 shuffle(first, last, default_random());
664}
665
666} // namespace fl
uint8_t pos
Definition Blur.ino:11
A random number generator class that wraps FastLED's random functions.
Definition random.h:25
void rotate_impl(Iterator first, Iterator middle, Iterator last) FL_NOEXCEPT
Definition algorithm.h:424
void quicksort_impl(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT
Definition algorithm.h:411
void heapify(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT
Definition algorithm.h:385
void sift_down(Iterator first, Iterator start, Iterator end, Compare comp) FL_NOEXCEPT
Definition algorithm.h:360
void mergesort_impl(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT
Definition algorithm.h:534
void merge_inplace(Iterator first, Iterator middle, Iterator last, Compare comp) FL_NOEXCEPT
Definition algorithm.h:459
Iterator median_of_three(Iterator first, Iterator middle, Iterator last, Compare comp) FL_NOEXCEPT
Definition algorithm.h:316
Iterator partition(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT
Definition algorithm.h:338
void heap_sort(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT
Definition algorithm.h:398
Iterator lower_bound_impl(Iterator first, Iterator last, const T &value, Compare comp) FL_NOEXCEPT
Definition algorithm.h:442
void insertion_sort(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT
Definition algorithm.h:298
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
Definition s16x16x4.h:28
Iterator find(Iterator first, Iterator last, const T &value) FL_NOEXCEPT
Definition algorithm.h:212
constexpr int type_rank< T >::value
Iterator find_if(Iterator first, Iterator last, UnaryPredicate pred) FL_NOEXCEPT
Definition algorithm.h:223
constexpr T * end(T(&array)[N]) FL_NOEXCEPT
bool lexicographical_compare(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) FL_NOEXCEPT
Definition algorithm.h:146
bool equal(Iterator1 first1, Iterator1 last1, Iterator2 first2) FL_NOEXCEPT
Definition algorithm.h:96
Iterator min_element(Iterator first, Iterator last) FL_NOEXCEPT
Definition algorithm.h:56
void replace_if(Iterator first, Iterator last, UnaryPredicate pred, const T &new_value) FL_NOEXCEPT
Definition algorithm.h:255
void swap(array< T, N > &lhs, array< T, N > &rhs) FL_NOEXCEPT
Definition array.h:209
void stable_sort(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT
Definition algorithm.h:582
math::random & default_random()
Global default random number generator instance.
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
Iterator remove_if(Iterator first, Iterator last, UnaryPredicate pred) FL_NOEXCEPT
Definition algorithm.h:280
constexpr enable_if< is_fixed_point< T >::value, T >::type step(T edge, T x) FL_NOEXCEPT
void sort(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT
Definition algorithm.h:564
void sort_small(Iterator first, Iterator last, Compare comp) FL_NOEXCEPT
Definition algorithm.h:612
Iterator lower_bound(Iterator first, Iterator last, const T &value, Compare comp) FL_NOEXCEPT
Definition algorithm.h:551
void shuffle(Iterator first, Iterator last, RandomGenerator &g) FL_NOEXCEPT
Definition algorithm.h:628
void fill(Iterator first, Iterator last, const T &value) FL_NOEXCEPT
Definition algorithm.h:204
Iterator max_element(Iterator first, Iterator last) FL_NOEXCEPT
Definition algorithm.h:18
void reverse(Iterator first, Iterator last) FL_NOEXCEPT
Definition algorithm.h:11
void replace(Iterator first, Iterator last, const T &old_value, const T &new_value) FL_NOEXCEPT
Definition algorithm.h:245
Iterator remove(Iterator first, Iterator last, const T &value) FL_NOEXCEPT
Definition algorithm.h:265
Iterator find_if_not(Iterator first, Iterator last, UnaryPredicate pred) FL_NOEXCEPT
Definition algorithm.h:234
bool equal_container(const Container1 &c1, const Container2 &c2) FL_NOEXCEPT
Definition algorithm.h:183
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_NOEXCEPT