FastLED 3.9.15
Loading...
Searching...
No Matches
bitset.h
Go to the documentation of this file.
1#pragma once
2
3#include "fl/stl/variant.h"
5#include "fl/stl/int.h"
7
9#include "fl/stl/move.h"
10#include "fl/stl/noexcept.h"
11
13FL_DISABLE_WARNING(double-promotion)
14FL_DISABLE_WARNING(float-conversion)
15FL_DISABLE_WARNING(sign-conversion)
18
19
20namespace fl {
21
22template <fl::u32 N> class bitset_inlined;
23
24template <fl::u32 N> class bitset_fixed;
25
26class string;
27template <fl::u32 N = 16>
28using bitset = bitset_inlined<N>; // inlined but can go bigger.
29
30
31// TODO: move this to fl/math.h
32template<typename IntType>
33inline fl::u8 popcount(IntType value) FL_NOEXCEPT {
34 return static_cast<fl::u8>(__builtin_popcount(value));
35}
36
37template<typename IntType>
38inline fl::u8 countr_zero(IntType value) FL_NOEXCEPT {
39 return static_cast<fl::u8>(__builtin_ctz(value));
40}
41
43template <fl::u32 N> class bitset_fixed {
44 private:
45 FL_STATIC_ASSERT(sizeof(fl::u16) == 2, "u16 should be 2 bytes");
46 static constexpr fl::u32 bits_per_block = 8 * sizeof(fl::u16);
47 static constexpr fl::u32 block_count =
48 (N + bits_per_block - 1) / bits_per_block;
49 using block_type = fl::u16;
50
51 // Underlying blocks storing bits
52 block_type _blocks[block_count];
53
54 public:
55 struct Proxy {
56 bitset_fixed &_bitset;
57 fl::u32 _pos;
58
59 Proxy(bitset_fixed &bitset, fl::u32 pos) FL_NOEXCEPT : _bitset(bitset), _pos(pos) {}
60
61 Proxy &operator=(bool value) FL_NOEXCEPT {
62 _bitset.set(_pos, value);
63 return *this;
64 }
65
66 operator bool() const FL_NOEXCEPT { return _bitset.test(_pos); }
67 };
68
69 Proxy operator[](fl::u32 pos) FL_NOEXCEPT { return Proxy(*this, pos); }
70
72 constexpr bitset_fixed() FL_NOEXCEPT : _blocks{} {}
73
74 void to_string(string* dst) const FL_NOEXCEPT {
75 detail::to_string(_blocks, N, dst);
76 }
77
79 void reset() FL_NOEXCEPT {
80 for (fl::u32 i = 0; i < block_count; ++i) {
81 _blocks[i] = 0;
82 }
83 }
84
86 bitset_fixed &set(fl::u32 pos, bool value = true) FL_NOEXCEPT {
87 if (pos < N) {
88 const fl::u32 idx = pos / bits_per_block;
89 const fl::u32 off = pos % bits_per_block;
90 if (value) {
91 _blocks[idx] |= (block_type(1) << off);
92 } else {
93 _blocks[idx] &= ~(block_type(1) << off);
94 }
95 }
96 return *this;
97 }
98
99 void assign(fl::size n, bool value) FL_NOEXCEPT {
100 if (n > N) {
101 n = N;
102 }
103 for (fl::size i = 0; i < n; ++i) {
104 set(i, value);
105 }
106 }
107
109 bitset_fixed &reset(fl::u32 pos) FL_NOEXCEPT { return set(pos, false); }
110
112 bitset_fixed &flip(fl::u32 pos) FL_NOEXCEPT {
113 if (pos < N) {
114 const fl::u32 idx = pos / bits_per_block;
115 const fl::u32 off = pos % bits_per_block;
116 _blocks[idx] ^= (block_type(1) << off);
117 }
118 return *this;
119 }
120
122 bitset_fixed &flip() FL_NOEXCEPT {
123 for (fl::u32 i = 0; i < block_count; ++i) {
124 _blocks[i] = ~_blocks[i];
125 }
126 // Mask out unused high bits in the last block
127 if (N % bits_per_block != 0) {
128 const fl::u32 extra = bits_per_block - (N % bits_per_block);
129 _blocks[block_count - 1] &= (~block_type(0) >> extra);
130 }
131 return *this;
132 }
133
135 bool test(fl::u32 pos) const FL_NOEXCEPT {
136 if (pos < N) {
137 const fl::u32 idx = pos / bits_per_block;
138 const fl::u32 off = pos % bits_per_block;
139 return (_blocks[idx] >> off) & 1;
140 }
141 return false;
142 }
143
145 bool operator[](fl::u32 pos) const FL_NOEXCEPT { return test(pos); }
146
148 fl::u32 count() const FL_NOEXCEPT {
149 fl::u32 cnt = 0;
150 // Count bits in all complete blocks
151 for (fl::u32 i = 0; i < block_count - 1; ++i) {
152 cnt += fl::popcount(_blocks[i]);
153 }
154
155 // For the last block, we need to be careful about counting only valid
156 // bits
157 if (block_count > 0) {
158 block_type last_block = _blocks[block_count - 1];
159 // If N is not a multiple of bits_per_block, mask out the unused
160 // bits
161 if (N % bits_per_block != 0) {
162 const fl::u32 valid_bits = N % bits_per_block;
163 // Create a mask with only the valid bits set to 1
164 block_type mask = (valid_bits == bits_per_block)
165 ? static_cast<block_type>(~block_type(0))
166 : ((block_type(1) << valid_bits) - 1);
167 last_block &= mask;
168 }
169 cnt += fl::popcount(last_block);
170 }
171
172 return cnt;
173 }
174
176 bool any() const FL_NOEXCEPT { return count() > 0; }
177 bool none() const FL_NOEXCEPT { return count() == 0; }
178 bool all() const FL_NOEXCEPT {
179 if (N == 0)
180 return true;
181
182 // Check all complete blocks
183 for (fl::u32 i = 0; i < block_count - 1; ++i) {
184 if (_blocks[i] != ~block_type(0)) {
185 return false;
186 }
187 }
188
189 // Check the last block
190 if (block_count > 0) {
191 block_type mask;
192 if (N % bits_per_block != 0) {
193 // Create a mask for the valid bits in the last block
194 mask = (block_type(1) << (N % bits_per_block)) - 1;
195 } else {
196 mask = static_cast<block_type>(~block_type(0));
197 }
198
199 if ((_blocks[block_count - 1] & mask) != mask) {
200 return false;
201 }
202 }
203
204 return true;
205 }
206
208 bitset_fixed &operator&=(const bitset_fixed &other) FL_NOEXCEPT {
209 for (fl::u32 i = 0; i < block_count; ++i) {
210 _blocks[i] &= other._blocks[i];
211 }
212 return *this;
213 }
215 bitset_fixed &operator|=(const bitset_fixed &other) FL_NOEXCEPT {
216 for (fl::u32 i = 0; i < block_count; ++i) {
217 _blocks[i] |= other._blocks[i];
218 }
219 return *this;
220 }
222 bitset_fixed &operator^=(const bitset_fixed &other) FL_NOEXCEPT {
223 for (fl::u32 i = 0; i < block_count; ++i) {
224 _blocks[i] ^= other._blocks[i];
225 }
226 return *this;
227 }
228
230 constexpr fl::u32 size() const FL_NOEXCEPT { return N; }
231
236 fl::i32 find_first(bool test_value, fl::u32 offset = 0) const FL_NOEXCEPT {
237 // If offset is beyond our size, no match possible
238 if (offset >= N) {
239 return -1;
240 }
241
242 // Calculate which block to start from
243 fl::u32 start_block = offset / bits_per_block;
244 fl::u32 start_bit = offset % bits_per_block;
245
246 for (fl::u32 block_idx = start_block; block_idx < block_count; ++block_idx) {
247 block_type current_block = _blocks[block_idx];
248
249 // For the last block, we need to mask out unused bits
250 if (block_idx == block_count - 1 && N % bits_per_block != 0) {
251 const fl::u32 valid_bits = N % bits_per_block;
252 block_type mask = (valid_bits == bits_per_block)
253 ? static_cast<block_type>(~block_type(0))
254 : ((block_type(1) << valid_bits) - 1);
255 current_block &= mask;
256 }
257
258 // If looking for false bits, invert the block
259 if (!test_value) {
260 current_block = ~current_block;
261 }
262
263 // For the first block, mask out bits before the offset
264 if (block_idx == start_block && start_bit > 0) {
265 current_block &= ~((block_type(1) << start_bit) - 1);
266 }
267
268 // If there are any matching bits in this block
269 if (current_block != 0) {
270 // Find the first set bit
271 fl::u32 bit_pos = fl::countr_zero(current_block);
272 fl::u32 absolute_pos = block_idx * bits_per_block + bit_pos;
273
274 // Make sure we haven't gone past the end of the bitset
275 if (absolute_pos < N) {
276 return static_cast<fl::i32>(absolute_pos);
277 }
278 }
279 }
280
281 return -1; // No matching bit found
282 }
283
289 fl::i32 find_run(bool test_value, fl::u32 min_length, fl::u32 offset = 0) const FL_NOEXCEPT {
290 fl::u32 run_start = offset;
291 fl::u32 run_length = 0;
292
293 for (fl::u32 i = offset; i < N && run_length < min_length; ++i) {
294 bool current_bit = test(i);
295 if (current_bit != test_value) {
296 run_length = 0;
297 if (i + 1 < N) {
298 run_start = i + 1;
299 }
300 } else {
301 ++run_length;
302 }
303 }
304
305 if (run_length >= min_length) {
306 return static_cast<fl::i32>(run_start);
307 }
308
309 return -1; // No run found
310 }
311
313 bool operator==(const bitset_fixed &other) const FL_NOEXCEPT {
314 for (fl::u32 i = 0; i < block_count; ++i) {
315 if (_blocks[i] != other._blocks[i]) {
316 return false;
317 }
318 }
319 return true;
320 }
321
322 bool operator!=(const bitset_fixed &other) const FL_NOEXCEPT {
323 return !(*this == other);
324 }
325
327 bool operator<(const bitset_fixed &other) const FL_NOEXCEPT {
328 for (fl::i32 i = static_cast<fl::i32>(block_count) - 1; i >= 0; --i) {
329 if (_blocks[i] < other._blocks[i]) {
330 return true;
331 }
332 if (_blocks[i] > other._blocks[i]) {
333 return false;
334 }
335 }
336 return false;
337 }
338
339 bool operator<=(const bitset_fixed &other) const FL_NOEXCEPT {
340 return *this < other || *this == other;
341 }
342
343 bool operator>(const bitset_fixed &other) const FL_NOEXCEPT {
344 return other < *this;
345 }
346
347 bool operator>=(const bitset_fixed &other) const FL_NOEXCEPT {
348 return other <= *this;
349 }
350
352 friend bitset_fixed operator&(bitset_fixed lhs,
353 const bitset_fixed &rhs) FL_NOEXCEPT {
354 return lhs &= rhs;
355 }
356 friend bitset_fixed operator|(bitset_fixed lhs,
357 const bitset_fixed &rhs) FL_NOEXCEPT {
358 return lhs |= rhs;
359 }
360 friend bitset_fixed operator^(bitset_fixed lhs,
361 const bitset_fixed &rhs) FL_NOEXCEPT {
362 return lhs ^= rhs;
363 }
364 friend bitset_fixed operator~(bitset_fixed bs) FL_NOEXCEPT { return bs.flip(); }
365};
366
370template <fl::u32 N = 16> // Default size is 16 bits, or 2 bytes
371class bitset_inlined {
372 private:
373 // Either store a fixed Bitset<N> or a dynamic Bitset
374 using fixed_bitset = bitset_fixed<N>;
375 variant<fixed_bitset, bitset_dynamic> _storage;
376
377 public:
378 struct Proxy {
379 bitset_inlined &_bitset;
380 fl::u32 _pos;
381
382 Proxy(bitset_inlined &bitset, fl::u32 pos) FL_NOEXCEPT
383 : _bitset(bitset), _pos(pos) {}
384
385 Proxy &operator=(bool value) FL_NOEXCEPT {
386 _bitset.set(_pos, value);
387 return *this;
388 }
389
390 operator bool() const FL_NOEXCEPT { return _bitset.test(_pos); }
391 };
392
393 Proxy operator[](fl::u32 pos) FL_NOEXCEPT { return Proxy(*this, pos); }
394
396 bitset_inlined() FL_NOEXCEPT : _storage(fixed_bitset()) {}
397 bitset_inlined(fl::size size) FL_NOEXCEPT : _storage(fixed_bitset()) {
398 if (size > N) {
399 _storage = bitset_dynamic(size);
400 }
401 }
402 bitset_inlined(const bitset_inlined &other) FL_NOEXCEPT : _storage(other._storage) {}
403 bitset_inlined(bitset_inlined &&other) FL_NOEXCEPT
404 : _storage(fl::move(other._storage)) {}
405 bitset_inlined &operator=(const bitset_inlined &other) FL_NOEXCEPT {
406 if (this != &other) {
407 _storage = other._storage;
408 }
409 return *this;
410 }
411 bitset_inlined &operator=(bitset_inlined &&other) FL_NOEXCEPT {
412 if (this != &other) {
413 _storage = fl::move(other._storage);
414 }
415 return *this;
416 }
417
419 void reset() FL_NOEXCEPT {
420 if (_storage.template is<fixed_bitset>()) {
421 _storage.template ptr<fixed_bitset>()->reset();
422 } else {
423 _storage.template ptr<bitset_dynamic>()->reset();
424 }
425 }
426
427 void assign(fl::size n, bool value) FL_NOEXCEPT {
428 resize(n);
429 if (_storage.template is<fixed_bitset>()) {
430 _storage.template ptr<fixed_bitset>()->assign(n, value);
431 } else {
432 _storage.template ptr<bitset_dynamic>()->assign(n, value);
433 }
434 }
435
436
437
439 void resize(fl::u32 new_size) FL_NOEXCEPT {
440 if (new_size <= N) {
441 // If we're already using the fixed Bitset, nothing to do
442 if (_storage.template is<bitset_dynamic>()) {
443 // Convert back to fixed Bitset
444 fixed_bitset fixed;
445 bitset_dynamic *dynamic =
446 _storage.template ptr<bitset_dynamic>();
447
448 // Copy bits from dynamic to fixed
449 for (fl::u32 i = 0; i < N && i < dynamic->size(); ++i) {
450 if (dynamic->test(i)) {
451 fixed.set(i);
452 }
453 }
454
455 _storage = fixed;
456 }
457 } else {
458 // Need to use dynamic Bitset
459 if (_storage.template is<fixed_bitset>()) {
460 // Convert from fixed to dynamic
461 bitset_dynamic dynamic(new_size);
462 fixed_bitset *fixed = _storage.template ptr<fixed_bitset>();
463
464 // Copy bits from fixed to dynamic
465 for (fl::u32 i = 0; i < N; ++i) {
466 if (fixed->test(i)) {
467 dynamic.set(i);
468 }
469 }
470
471 _storage = dynamic;
472 } else {
473 // Already using dynamic, just resize
474 _storage.template ptr<bitset_dynamic>()->resize(new_size);
475 }
476 }
477 }
478
480 bitset_inlined &set(fl::u32 pos, bool value = true) FL_NOEXCEPT {
481 if (pos >= N && _storage.template is<fixed_bitset>()) {
482 resize(pos + 1);
483 }
484
485 if (_storage.template is<fixed_bitset>()) {
486 if (pos < N) {
487 _storage.template ptr<fixed_bitset>()->set(pos, value);
488 }
489 } else {
490 if (pos >= _storage.template ptr<bitset_dynamic>()->size()) {
491 _storage.template ptr<bitset_dynamic>()->resize(pos + 1);
492 }
493 _storage.template ptr<bitset_dynamic>()->set(pos, value);
494 }
495 return *this;
496 }
497
499 bitset_inlined &reset(fl::u32 pos) FL_NOEXCEPT { return set(pos, false); }
500
502 bitset_inlined &flip(fl::u32 pos) FL_NOEXCEPT {
503 if (pos >= N && _storage.template is<fixed_bitset>()) {
504 resize(pos + 1);
505 }
506
507 if (_storage.template is<fixed_bitset>()) {
508 if (pos < N) {
509 _storage.template ptr<fixed_bitset>()->flip(pos);
510 }
511 } else {
512 if (pos >= _storage.template ptr<bitset_dynamic>()->size()) {
513 _storage.template ptr<bitset_dynamic>()->resize(pos + 1);
514 }
515 _storage.template ptr<bitset_dynamic>()->flip(pos);
516 }
517 return *this;
518 }
519
521 bitset_inlined &flip() FL_NOEXCEPT {
522 if (_storage.template is<fixed_bitset>()) {
523 _storage.template ptr<fixed_bitset>()->flip();
524 } else {
525 _storage.template ptr<bitset_dynamic>()->flip();
526 }
527 return *this;
528 }
529
531 void push_back() FL_NOEXCEPT {
532 fl::u32 new_size = size() + 1;
533 resize(new_size);
534 }
535
537 template<typename... Args>
538 void emplace_back(Args&&...) FL_NOEXCEPT {
539 push_back(); // bitset bits are bool, just expand
540 }
541
543 void pop_back() FL_NOEXCEPT {
544 if (size() > 0) {
545 resize(size() - 1);
546 }
547 }
548
550 bool test(fl::u32 pos) const FL_NOEXCEPT {
551 if (_storage.template is<fixed_bitset>()) {
552 return pos < N ? _storage.template ptr<fixed_bitset>()->test(pos)
553 : false;
554 } else {
555 return _storage.template ptr<bitset_dynamic>()->test(pos);
556 }
557 }
558
560 bool operator[](fl::u32 pos) const FL_NOEXCEPT { return test(pos); }
561
563 fl::u32 count() const FL_NOEXCEPT {
564 if (_storage.template is<fixed_bitset>()) {
565 return _storage.template ptr<fixed_bitset>()->count();
566 } else {
567 return _storage.template ptr<bitset_dynamic>()->count();
568 }
569 }
570
572 bool any() const FL_NOEXCEPT {
573 if (_storage.template is<fixed_bitset>()) {
574 return _storage.template ptr<fixed_bitset>()->any();
575 } else {
576 return _storage.template ptr<bitset_dynamic>()->any();
577 }
578 }
579
580 bool none() const FL_NOEXCEPT {
581 if (_storage.template is<fixed_bitset>()) {
582 return _storage.template ptr<fixed_bitset>()->none();
583 } else {
584 return _storage.template ptr<bitset_dynamic>()->none();
585 }
586 }
587
588 bool all() const FL_NOEXCEPT {
589 if (_storage.template is<fixed_bitset>()) {
590 return _storage.template ptr<fixed_bitset>()->all();
591 } else {
592 return _storage.template ptr<bitset_dynamic>()->all();
593 }
594 }
595
597 fl::u32 size() const FL_NOEXCEPT {
598 if (_storage.template is<fixed_bitset>()) {
599 return N;
600 } else {
601 return _storage.template ptr<bitset_dynamic>()->size();
602 }
603 }
604
606 void to_string(string* dst) const FL_NOEXCEPT {
607 if (_storage.template is<fixed_bitset>()) {
608 _storage.template ptr<fixed_bitset>()->to_string(dst);
609 } else {
610 _storage.template ptr<bitset_dynamic>()->to_string(dst);
611 }
612 }
613
618 fl::i32 find_first(bool test_value, fl::u32 offset = 0) const FL_NOEXCEPT {
619 if (_storage.template is<fixed_bitset>()) {
620 return _storage.template ptr<fixed_bitset>()->find_first(test_value, offset);
621 } else {
622 return _storage.template ptr<bitset_dynamic>()->find_first(test_value, offset);
623 }
624 }
625
627 friend bitset_inlined operator~(const bitset_inlined &bs) FL_NOEXCEPT {
628 bitset_inlined result = bs;
629 result.flip();
630 return result;
631 }
632
633 friend bitset_inlined operator&(const bitset_inlined &lhs,
634 const bitset_inlined &rhs) FL_NOEXCEPT {
635 bitset_inlined result = lhs;
636
637 if (result._storage.template is<fixed_bitset>() &&
638 rhs._storage.template is<fixed_bitset>()) {
639 // Both are fixed, use the fixed implementation
640 *result._storage.template ptr<fixed_bitset>() &=
641 *rhs._storage.template ptr<fixed_bitset>();
642 } else {
643 // At least one is dynamic, handle bit by bit
644 fl::u32 min_size =
645 result.size() < rhs.size() ? result.size() : rhs.size();
646 for (fl::u32 i = 0; i < min_size; ++i) {
647 result.set(i, result.test(i) && rhs.test(i));
648 }
649 // Clear any bits beyond the size of rhs
650 for (fl::u32 i = min_size; i < result.size(); ++i) {
651 result.reset(i);
652 }
653 }
654
655 return result;
656 }
657
658 friend bitset_inlined operator|(const bitset_inlined &lhs,
659 const bitset_inlined &rhs) FL_NOEXCEPT {
660 bitset_inlined result = lhs;
661
662 if (result._storage.template is<fixed_bitset>() &&
663 rhs._storage.template is<fixed_bitset>()) {
664 // Both are fixed, use the fixed implementation
665 *result._storage.template ptr<fixed_bitset>() |=
666 *rhs._storage.template ptr<fixed_bitset>();
667 } else {
668 // At least one is dynamic, handle bit by bit
669 fl::u32 max_size =
670 result.size() > rhs.size() ? result.size() : rhs.size();
671
672 // Resize if needed
673 if (result.size() < max_size) {
674 result.resize(max_size);
675 }
676
677 // Set bits from rhs
678 for (fl::u32 i = 0; i < rhs.size(); ++i) {
679 if (rhs.test(i)) {
680 result.set(i);
681 }
682 }
683 }
684
685 return result;
686 }
687
688 friend bitset_inlined operator^(const bitset_inlined &lhs,
689 const bitset_inlined &rhs) FL_NOEXCEPT {
690 bitset_inlined result = lhs;
691
692 if (result._storage.template is<fixed_bitset>() &&
693 rhs._storage.template is<fixed_bitset>()) {
694 // Both are fixed, use the fixed implementation
695 *result._storage.template ptr<fixed_bitset>() ^=
696 *rhs._storage.template ptr<fixed_bitset>();
697 } else {
698 // At least one is dynamic, handle bit by bit
699 fl::u32 max_size =
700 result.size() > rhs.size() ? result.size() : rhs.size();
701
702 // Resize if needed
703 if (result.size() < max_size) {
704 result.resize(max_size);
705 }
706
707 // XOR bits from rhs
708 for (fl::u32 i = 0; i < rhs.size(); ++i) {
709 result.set(i, result.test(i) != rhs.test(i));
710 }
711 }
712
713 return result;
714 }
715
717 bool operator==(const bitset_inlined &other) const FL_NOEXCEPT {
718 if (size() != other.size()) {
719 return false;
720 }
721 for (fl::u32 i = 0; i < size(); ++i) {
722 if (test(i) != other.test(i)) {
723 return false;
724 }
725 }
726 return true;
727 }
728
729 bool operator!=(const bitset_inlined &other) const FL_NOEXCEPT {
730 return !(*this == other);
731 }
732
734 bool operator<(const bitset_inlined &other) const FL_NOEXCEPT {
735 fl::u32 min_size = size() < other.size() ? size() : other.size();
736 for (fl::u32 i = min_size; i > 0; --i) {
737 bool this_bit = test(i - 1);
738 bool other_bit = other.test(i - 1);
739 if (this_bit != other_bit) {
740 return !this_bit; // false < true
741 }
742 }
743 // All common bits are equal, shorter is less
744 return size() < other.size();
745 }
746
747 bool operator<=(const bitset_inlined &other) const FL_NOEXCEPT {
748 return *this < other || *this == other;
749 }
750
751 bool operator>(const bitset_inlined &other) const FL_NOEXCEPT {
752 return other < *this;
753 }
754
755 bool operator>=(const bitset_inlined &other) const FL_NOEXCEPT {
756 return other <= *this;
757 }
758};
759
760} // namespace fl
761
uint8_t pos
Definition Blur.ino:11
ClearFlags & operator|=(ClearFlags &a, ClearFlags b)
Enable bitwise OR assignment for ClearFlags.
Definition FastLED.h:599
fl::UISlider offset("Offset", 0.0f, 0.0f, 1.0f, 0.01f)
void to_string(const fl::u16 *bit_data, fl::u32 bit_count, string *dst)
Definition bitset.cpp.hpp:9
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
Definition s16x16x4.h:28
string to_string(T value) FL_NOEXCEPT
Definition string.h:450
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
Definition move.h:28
unsigned char u8
Definition stdint.h:131
constexpr int type_rank< T >::value
FASTLED_FORCE_INLINE CRGB operator&(const CRGB &p1, const CRGB &p2) FL_NOEXCEPT
Combine two CRGB objects, taking the smallest value of each channel.
Definition crgb.h:787
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.
Definition crgb.h:739
FASTLED_FORCE_INLINE bool operator<(const CRGB &lhs, const CRGB &rhs) FL_NOEXCEPT
Check if the sum of the color channels in one CRGB object is less than another.
Definition crgb.h:745
FASTLED_FORCE_INLINE bool operator==(const CRGB &lhs, const CRGB &rhs) FL_NOEXCEPT
Check if two CRGB objects have the same color data.
Definition crgb.h:733
FASTLED_FORCE_INLINE bool operator>(const CRGB &lhs, const CRGB &rhs) FL_NOEXCEPT
Check if the sum of the color channels in one CRGB object is greater than another.
Definition crgb.h:754
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
FASTLED_FORCE_INLINE bool operator<=(const CRGB &lhs, const CRGB &rhs) FL_NOEXCEPT
Check if the sum of the color channels in one CRGB object is less than or equal to another.
Definition crgb.h:772
FASTLED_FORCE_INLINE CRGB operator|(const CRGB &p1, const CRGB &p2) FL_NOEXCEPT
Combine two CRGB objects, taking the largest value of each channel.
Definition crgb.h:795
FASTLED_FORCE_INLINE bool operator>=(const CRGB &lhs, const CRGB &rhs) FL_NOEXCEPT
Check if the sum of the color channels in one CRGB object is greater than or equal to another.
Definition crgb.h:763
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_DISABLE_WARNING(warning)
#define FL_DISABLE_WARNING_IMPLICIT_INT_CONVERSION
#define FL_STATIC_ASSERT(...)
#define FL_DISABLE_WARNING_PUSH
#define FL_DISABLE_WARNING_POP
#define FL_DISABLE_WARNING_FLOAT_CONVERSION
#define FL_NOEXCEPT
Portable compile-time assertion wrapper.