FastLED 3.9.15
Loading...
Searching...
No Matches
algorithm.h
Go to the documentation of this file.
1#pragma once
2
3#include "fl/type_traits.h"
4#include "fl/move.h"
5#include "fl/random.h"
6
7namespace fl {
8
9template <typename Iterator>
10void reverse(Iterator first, Iterator last) {
11 while ((first != last) && (first != --last)) {
12 swap(*first++, *last);
13 }
14}
15
16template <typename Iterator>
17Iterator max_element(Iterator first, Iterator last) {
18 if (first == last) {
19 return last;
20 }
21
22 Iterator max_iter = first;
23 ++first;
24
25 while (first != last) {
26 if (*max_iter < *first) {
27 max_iter = first;
28 }
29 ++first;
30 }
31
32 return max_iter;
33}
34
35template <typename Iterator, typename Compare>
36Iterator max_element(Iterator first, Iterator last, Compare comp) {
37 if (first == last) {
38 return last;
39 }
40
41 Iterator max_iter = first;
42 ++first;
43
44 while (first != last) {
45 if (comp(*max_iter, *first)) {
46 max_iter = first;
47 }
48 ++first;
49 }
50
51 return max_iter;
52}
53
54template <typename Iterator>
55Iterator min_element(Iterator first, Iterator last) {
56 if (first == last) {
57 return last;
58 }
59
60 Iterator min_iter = first;
61 ++first;
62
63 while (first != last) {
64 if (*first < *min_iter) {
65 min_iter = first;
66 }
67 ++first;
68 }
69
70 return min_iter;
71}
72
73template <typename Iterator, typename Compare>
74Iterator min_element(Iterator first, Iterator last, Compare comp) {
75 if (first == last) {
76 return last;
77 }
78
79 Iterator min_iter = first;
80 ++first;
81
82 while (first != last) {
83 if (comp(*first, *min_iter)) {
84 min_iter = first;
85 }
86 ++first;
87 }
88
89 return min_iter;
90}
91
92
93
94template <typename Iterator1, typename Iterator2>
95bool equal(Iterator1 first1, Iterator1 last1, Iterator2 first2) {
96 while (first1 != last1) {
97 if (*first1 != *first2) {
98 return false;
99 }
100 ++first1;
101 ++first2;
102 }
103 return true;
104}
105
106template <typename Iterator1, typename Iterator2, typename BinaryPredicate>
107bool equal(Iterator1 first1, Iterator1 last1, Iterator2 first2, BinaryPredicate pred) {
108 while (first1 != last1) {
109 if (!pred(*first1, *first2)) {
110 return false;
111 }
112 ++first1;
113 ++first2;
114 }
115 return true;
116}
117
118template <typename Iterator1, typename Iterator2>
119bool equal(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) {
120 while (first1 != last1 && first2 != last2) {
121 if (*first1 != *first2) {
122 return false;
123 }
124 ++first1;
125 ++first2;
126 }
127 return first1 == last1 && first2 == last2;
128}
129
130template <typename Iterator1, typename Iterator2, typename BinaryPredicate>
131bool equal(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2, BinaryPredicate pred) {
132 while (first1 != last1 && first2 != last2) {
133 if (!pred(*first1, *first2)) {
134 return false;
135 }
136 ++first1;
137 ++first2;
138 }
139 return first1 == last1 && first2 == last2;
140}
141
142template <typename Container1, typename Container2>
143bool equal_container(const Container1& c1, const Container2& c2) {
144 fl::size size1 = c1.size();
145 fl::size size2 = c2.size();
146 if (size1 != size2) {
147 return false;
148 }
149 return equal(c1.begin(), c1.end(), c2.begin(), c2.end());
150}
151
152template <typename Container1, typename Container2, typename BinaryPredicate>
153bool equal_container(const Container1& c1, const Container2& c2, BinaryPredicate pred) {
154 fl::size size1 = c1.size();
155 fl::size size2 = c2.size();
156 if (size1 != size2) {
157 return false;
158 }
159 return equal(c1.begin(), c1.end(), c2.begin(), c2.end(), pred);
160}
161
162
163template <typename Iterator, typename T>
164void fill(Iterator first, Iterator last, const T& value) {
165 while (first != last) {
166 *first = value;
167 ++first;
168 }
169}
170
171template <typename Iterator, typename T>
172Iterator find(Iterator first, Iterator last, const T& value) {
173 while (first != last) {
174 if (*first == value) {
175 return first;
176 }
177 ++first;
178 }
179 return last;
180}
181
182template <typename Iterator, typename UnaryPredicate>
183Iterator find_if(Iterator first, Iterator last, UnaryPredicate pred) {
184 while (first != last) {
185 if (pred(*first)) {
186 return first;
187 }
188 ++first;
189 }
190 return last;
191}
192
193template <typename Iterator, typename UnaryPredicate>
194Iterator find_if_not(Iterator first, Iterator last, UnaryPredicate pred) {
195 while (first != last) {
196 if (!pred(*first)) {
197 return first;
198 }
199 ++first;
200 }
201 return last;
202}
203
204template <typename Iterator, typename T>
205Iterator remove(Iterator first, Iterator last, const T& value) {
206 Iterator result = first;
207 while (first != last) {
208 if (!(*first == value)) {
209 if (result != first) {
210 *result = fl::move(*first);
211 }
212 ++result;
213 }
214 ++first;
215 }
216 return result;
217}
218
219template <typename Iterator, typename UnaryPredicate>
220Iterator remove_if(Iterator first, Iterator last, UnaryPredicate pred) {
221 Iterator result = first;
222 while (first != last) {
223 if (!pred(*first)) {
224 if (result != first) {
225 *result = fl::move(*first);
226 }
227 ++result;
228 }
229 ++first;
230 }
231 return result;
232}
233
234namespace detail {
235
236// Insertion sort implementation for small arrays
237template <typename Iterator, typename Compare>
238void insertion_sort(Iterator first, Iterator last, Compare comp) {
239 if (first == last) return;
240
241 for (Iterator i = first + 1; i != last; ++i) {
242 auto value = fl::move(*i);
243 Iterator j = i;
244
245 while (j != first && comp(value, *(j - 1))) {
246 *j = fl::move(*(j - 1));
247 --j;
248 }
249
250 *j = fl::move(value);
251 }
252}
253
254// Median-of-three pivot selection
255template <typename Iterator, typename Compare>
256Iterator median_of_three(Iterator first, Iterator middle, Iterator last, Compare comp) {
257 if (comp(*middle, *first)) {
258 if (comp(*last, *middle)) {
259 return middle;
260 } else if (comp(*last, *first)) {
261 return last;
262 } else {
263 return first;
264 }
265 } else {
266 if (comp(*last, *first)) {
267 return first;
268 } else if (comp(*last, *middle)) {
269 return last;
270 } else {
271 return middle;
272 }
273 }
274}
275
276// Partition function for quicksort
277template <typename Iterator, typename Compare>
278Iterator partition(Iterator first, Iterator last, Compare comp) {
279 Iterator middle = first + (last - first) / 2;
280 Iterator pivot_iter = median_of_three(first, middle, last - 1, comp);
281
282 // Move pivot to end
283 swap(*pivot_iter, *(last - 1));
284 Iterator pivot = last - 1;
285
286 Iterator i = first;
287 for (Iterator j = first; j != pivot; ++j) {
288 if (comp(*j, *pivot)) {
289 swap(*i, *j);
290 ++i;
291 }
292 }
293
294 swap(*i, *pivot);
295 return i;
296}
297
298// Heapsort implementation (fallback for deep recursion)
299template <typename Iterator, typename Compare>
300void sift_down(Iterator first, Iterator start, Iterator end, Compare comp) {
301 Iterator root = start;
302
303 while (root - first <= (end - first - 2) / 2) {
304 Iterator child = first + 2 * (root - first) + 1;
305 Iterator swap_iter = root;
306
307 if (comp(*swap_iter, *child)) {
308 swap_iter = child;
309 }
310
311 if (child + 1 <= end && comp(*swap_iter, *(child + 1))) {
312 swap_iter = child + 1;
313 }
314
315 if (swap_iter == root) {
316 return;
317 } else {
318 swap(*root, *swap_iter);
319 root = swap_iter;
320 }
321 }
322}
323
324template <typename Iterator, typename Compare>
325void heapify(Iterator first, Iterator last, Compare comp) {
326 Iterator start = first + (last - first - 2) / 2;
327
328 while (true) {
329 sift_down(first, start, last - 1, comp);
330 if (start == first) {
331 break;
332 }
333 --start;
334 }
335}
336
337template <typename Iterator, typename Compare>
338void heap_sort(Iterator first, Iterator last, Compare comp) {
339 heapify(first, last, comp);
340
341 Iterator end = last - 1;
342 while (end > first) {
343 swap(*end, *first);
344 sift_down(first, first, end - 1, comp);
345 --end;
346 }
347}
348
349// Quicksort implementation
350template <typename Iterator, typename Compare>
351void quicksort_impl(Iterator first, Iterator last, Compare comp) {
352 if (last - first <= 16) { // Use insertion sort for small arrays
353 insertion_sort(first, last, comp);
354 return;
355 }
356
357 Iterator pivot = partition(first, last, comp);
358 quicksort_impl(first, pivot, comp);
359 quicksort_impl(pivot + 1, last, comp);
360}
361
362// Rotate elements in range [first, last) so that middle becomes the new first
363template <typename Iterator>
364void rotate_impl(Iterator first, Iterator middle, Iterator last) {
365 if (first == middle || middle == last) {
366 return;
367 }
368
369 Iterator next = middle;
370 while (first != next) {
371 swap(*first++, *next++);
372 if (next == last) {
373 next = middle;
374 } else if (first == middle) {
375 middle = next;
376 }
377 }
378}
379
380// Find the position where value should be inserted in sorted range [first, last)
381template <typename Iterator, typename T, typename Compare>
382Iterator lower_bound_impl(Iterator first, Iterator last, const T& value, Compare comp) {
383 auto count = last - first;
384 while (count > 0) {
385 auto step = count / 2;
386 Iterator it = first + step;
387 if (comp(*it, value)) {
388 first = ++it;
389 count -= step + 1;
390 } else {
391 count = step;
392 }
393 }
394 return first;
395}
396
397// In-place merge operation for merge sort (stable sort)
398template <typename Iterator, typename Compare>
399void merge_inplace(Iterator first, Iterator middle, Iterator last, Compare comp) {
400 // If one of the ranges is empty, nothing to merge
401 if (first == middle || middle == last) {
402 return;
403 }
404
405 // If arrays are small enough, use insertion-based merge
406 auto left_size = middle - first;
407 auto right_size = last - middle;
408 if (left_size + right_size <= 32) {
409 // Simple insertion-based merge for small arrays
410 Iterator left = first;
411 Iterator right = middle;
412
413 while (left < middle && right < last) {
414 if (!comp(*right, *left)) {
415 // left element is in correct position
416 ++left;
417 } else {
418 // right element needs to be inserted into left part
419 auto value = fl::move(*right);
420 Iterator shift_end = right;
421 Iterator shift_start = left;
422
423 // Shift elements to make room
424 while (shift_end > shift_start) {
425 *shift_end = fl::move(*(shift_end - 1));
426 --shift_end;
427 }
428
429 *left = fl::move(value);
430 ++left;
431 ++middle; // middle has shifted right
432 ++right;
433 }
434 }
435 return;
436 }
437
438 // For larger arrays, use rotation-based merge
439 if (left_size == 0 || right_size == 0) {
440 return;
441 }
442
443 if (left_size == 1) {
444 // Find insertion point for the single left element in right array
445 Iterator pos = lower_bound_impl(middle, last, *first, comp);
446 rotate_impl(first, middle, pos);
447 return;
448 }
449
450 if (right_size == 1) {
451 // Find insertion point for the single right element in left array
452 Iterator pos = lower_bound_impl(first, middle, *(last - 1), comp);
453 rotate_impl(pos, middle, last);
454 return;
455 }
456
457 // Divide both arrays and recursively merge
458 Iterator left_mid = first + left_size / 2;
459 Iterator right_mid = lower_bound_impl(middle, last, *left_mid, comp);
460
461 // Rotate to bring the two middle parts together
462 rotate_impl(left_mid, middle, right_mid);
463
464 // Update middle position
465 Iterator new_middle = left_mid + (right_mid - middle);
466
467 // Recursively merge the two parts
468 merge_inplace(first, left_mid, new_middle, comp);
469 merge_inplace(new_middle, right_mid, last, comp);
470}
471
472// Merge sort implementation (stable, in-place)
473template <typename Iterator, typename Compare>
474void mergesort_impl(Iterator first, Iterator last, Compare comp) {
475 auto size = last - first;
476 if (size <= 16) { // Use insertion sort for small arrays (it's stable)
477 insertion_sort(first, last, comp);
478 return;
479 }
480
481 Iterator middle = first + size / 2;
482 mergesort_impl(first, middle, comp);
483 mergesort_impl(middle, last, comp);
484 merge_inplace(first, middle, last, comp);
485}
486
487} // namespace detail
488
489// Sort function with custom comparator (using quicksort)
490template <typename Iterator, typename Compare>
491void sort(Iterator first, Iterator last, Compare comp) {
492 if (first == last || first + 1 == last) {
493 return; // Already sorted or empty
494 }
495
496 detail::quicksort_impl(first, last, comp);
497}
498
499// Sort function with default comparator
500template <typename Iterator>
501void sort(Iterator first, Iterator last) {
502 // Use explicit template parameter to avoid C++14 auto in lambda
503 typedef typename fl::remove_reference<decltype(*first)>::type value_type;
504 sort(first, last, [](const value_type& a, const value_type& b) { return a < b; });
505}
506
507// Stable sort function with custom comparator (using merge sort)
508template <typename Iterator, typename Compare>
509void stable_sort(Iterator first, Iterator last, Compare comp) {
510 if (first == last || first + 1 == last) {
511 return; // Already sorted or empty
512 }
513
514 detail::mergesort_impl(first, last, comp);
515}
516
517// Stable sort function with default comparator
518template <typename Iterator>
519void stable_sort(Iterator first, Iterator last) {
520 // Use explicit template parameter to avoid C++14 auto in lambda
521 typedef typename fl::remove_reference<decltype(*first)>::type value_type;
522 stable_sort(first, last, [](const value_type& a, const value_type& b) { return a < b; });
523}
524
525// Shuffle function with custom random generator (Fisher-Yates shuffle)
526template <typename Iterator, typename RandomGenerator>
527void shuffle(Iterator first, Iterator last, RandomGenerator& g) {
528 if (first == last) {
529 return; // Empty range, nothing to shuffle
530 }
531
532 auto n = last - first;
533 for (auto i = n - 1; i > 0; --i) {
534 // Generate random index from 0 to i (inclusive)
535 auto j = g() % (i + 1);
536
537 // Swap elements at positions i and j
538 swap(*(first + i), *(first + j));
539 }
540}
541
542// Shuffle function with fl::fl_random instance
543template <typename Iterator>
544void shuffle(Iterator first, Iterator last, fl_random& rng) {
545 if (first == last) {
546 return; // Empty range, nothing to shuffle
547 }
548
549 auto n = last - first;
550 for (auto i = n - 1; i > 0; --i) {
551 // Generate random index from 0 to i (inclusive)
552 auto j = rng(static_cast<u32>(i + 1));
553
554 // Swap elements at positions i and j
555 swap(*(first + i), *(first + j));
556 }
557}
558
559// Shuffle function with default random generator
560template <typename Iterator>
561void shuffle(Iterator first, Iterator last) {
562 shuffle(first, last, default_random());
563}
564
565} // namespace fl
uint8_t pos
Definition Blur.ino:11
A random number generator class that wraps FastLED's random functions.
Definition random.h:20
Result type for promise operations.
Iterator median_of_three(Iterator first, Iterator middle, Iterator last, Compare comp)
Definition algorithm.h:256
void merge_inplace(Iterator first, Iterator middle, Iterator last, Compare comp)
Definition algorithm.h:399
void sift_down(Iterator first, Iterator start, Iterator end, Compare comp)
Definition algorithm.h:300
void heap_sort(Iterator first, Iterator last, Compare comp)
Definition algorithm.h:338
Iterator partition(Iterator first, Iterator last, Compare comp)
Definition algorithm.h:278
void heapify(Iterator first, Iterator last, Compare comp)
Definition algorithm.h:325
void rotate_impl(Iterator first, Iterator middle, Iterator last)
Definition algorithm.h:364
void insertion_sort(Iterator first, Iterator last, Compare comp)
Definition algorithm.h:238
void quicksort_impl(Iterator first, Iterator last, Compare comp)
Definition algorithm.h:351
Iterator lower_bound_impl(Iterator first, Iterator last, const T &value, Compare comp)
Definition algorithm.h:382
void mergesort_impl(Iterator first, Iterator last, Compare comp)
Definition algorithm.h:474
constexpr remove_reference< T >::type && move(T &&t) noexcept
Definition move.h:27
Iterator find(Iterator first, Iterator last, const T &value)
Definition algorithm.h:172
void swap(array< T, N > &lhs, array< T, N > &rhs) noexcept(noexcept(lhs.swap(rhs)))
Definition array.h:156
void shuffle(Iterator first, Iterator last, RandomGenerator &g)
Definition algorithm.h:527
Iterator min_element(Iterator first, Iterator last)
Definition algorithm.h:55
constexpr T * end(T(&array)[N]) noexcept
fl_random & default_random()
Global default random number generator instance.
Definition random.cpp:8
Iterator remove(Iterator first, Iterator last, const T &value)
Definition algorithm.h:205
Iterator find_if_not(Iterator first, Iterator last, UnaryPredicate pred)
Definition algorithm.h:194
void reverse(Iterator first, Iterator last)
Definition algorithm.h:10
Iterator find_if(Iterator first, Iterator last, UnaryPredicate pred)
Definition algorithm.h:183
Iterator max_element(Iterator first, Iterator last)
Definition algorithm.h:17
void sort(Iterator first, Iterator last, Compare comp)
Definition algorithm.h:491
void stable_sort(Iterator first, Iterator last, Compare comp)
Definition algorithm.h:509
bool equal(Iterator1 first1, Iterator1 last1, Iterator2 first2)
Definition algorithm.h:95
bool equal_container(const Container1 &c1, const Container2 &c2)
Definition algorithm.h:143
void fill(Iterator first, Iterator last, const T &value)
Definition algorithm.h:164
Iterator remove_if(Iterator first, Iterator last, UnaryPredicate pred)
Definition algorithm.h:220
IMPORTANT!
Definition crgb.h:20