A simple fixed-size Bitset implementation similar to std::Bitset.
Constructs a bitset_fixed with all bits reset.
Resets all bits to zero.
Sets or clears the bit at position pos.
Clears the bit at position pos.
Flips (toggles) the bit at position pos.
Flips all bits.
Tests whether the bit at position pos is set.
Returns the value of the bit at position pos.
Returns the number of set bits.
Queries.
Size of the bitset_fixed (number of bits).
Finds the first bit that matches the test value. Returns the index of the first matching bit, or -1 if none found.
Finds the first run of consecutive bits that match the test value. Returns the index of the first bit in the run, or -1 if no run found.
Friend operators for convenience.
A Bitset implementation with inline storage that can grow if needed. T is the storage type (u8, u16, u32, u64) N is the initial number of bits to store inline
Constructs a Bitset with all bits reset.
Resets all bits to zero.
Sets or clears the bit at position pos.
Clears the bit at position pos.
Flips (toggles) the bit at position pos.
Flips all bits.
Tests whether the bit at position pos is set.
Returns the value of the bit at position pos.
Returns the number of set bits.
Queries.
Size of the Bitset (number of bits).
Finds the first bit that matches the test value. Returns the index of the first matching bit, or -1 if none found.
20 {
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>;
29
30
31
32template<typename IntType>
34 return static_cast<fl::u8>(__builtin_popcount(value));
35}
36
37template<typename IntType>
39 return static_cast<fl::u8>(__builtin_ctz(value));
40}
41
43template <fl::u32 N> class bitset_fixed {
44 private:
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
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
62 _bitset.set(_pos, value);
63 return *this;
64 }
65
66 operator bool() const
FL_NOEXCEPT {
return _bitset.test(_pos); }
67 };
68
70
73
75 detail::to_string(_blocks, N, dst);
76 }
77
80 for (fl::u32 i = 0; i < block_count; ++i) {
81 _blocks[i] = 0;
82 }
83 }
84
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
100 if (n > N) {
101 n = N;
102 }
103 for (fl::size i = 0; i < n; ++i) {
104 set(i, value);
105 }
106 }
107
110
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
123 for (fl::u32 i = 0; i < block_count; ++i) {
124 _blocks[i] = ~_blocks[i];
125 }
126
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
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
146
149 fl::u32 cnt = 0;
150
151 for (fl::u32 i = 0; i < block_count - 1; ++i) {
152 cnt += fl::popcount(_blocks[i]);
153 }
154
155
156
157 if (block_count > 0) {
158 block_type last_block = _blocks[block_count - 1];
159
160
161 if (N % bits_per_block != 0) {
162 const fl::u32 valid_bits = N % bits_per_block;
163
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; }
179 if (N == 0)
180 return true;
181
182
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
190 if (block_count > 0) {
191 block_type mask;
192 if (N % bits_per_block != 0) {
193
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 }
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
237
239 return -1;
240 }
241
242
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
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
259 if (!test_value) {
260 current_block = ~current_block;
261 }
262
263
264 if (block_idx == start_block && start_bit > 0) {
265 current_block &= ~((block_type(1) << start_bit) - 1);
266 }
267
268
269 if (current_block != 0) {
270
271 fl::u32 bit_pos = fl::countr_zero(current_block);
272 fl::u32 absolute_pos = block_idx * bits_per_block + bit_pos;
273
274
275 if (absolute_pos < N) {
276 return static_cast<fl::i32>(absolute_pos);
277 }
278 }
279 }
280
281 return -1;
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;
310 }
311
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
323 return !(*this == other);
324 }
325
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
340 return *this < other || *this == other;
341 }
342
344 return other < *this;
345 }
346
348 return other <= *this;
349 }
350
352 friend bitset_fixed
operator&(bitset_fixed lhs,
354 return lhs &= rhs;
355 }
356 friend bitset_fixed
operator|(bitset_fixed lhs,
358 return lhs |= rhs;
359 }
360 friend bitset_fixed operator^(bitset_fixed lhs,
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>
371class bitset_inlined {
372 private:
373
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
383 : _bitset(bitset), _pos(
pos) {}
384
386 _bitset.set(_pos, value);
387 return *this;
388 }
389
390 operator bool() const
FL_NOEXCEPT {
return _bitset.test(_pos); }
391 };
392
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) {}
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
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
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
440 if (new_size <= N) {
441
442 if (_storage.template is<bitset_dynamic>()) {
443
444 fixed_bitset fixed;
445 bitset_dynamic *dynamic =
446 _storage.template ptr<bitset_dynamic>();
447
448
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
459 if (_storage.template is<fixed_bitset>()) {
460
461 bitset_dynamic dynamic(new_size);
462 fixed_bitset *fixed = _storage.template ptr<fixed_bitset>();
463
464
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
474 _storage.template ptr<bitset_dynamic>()->resize(new_size);
475 }
476 }
477 }
478
481 if (
pos >= N && _storage.template is<fixed_bitset>()) {
483 }
484
485 if (_storage.template is<fixed_bitset>()) {
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
500
503 if (
pos >= N && _storage.template is<fixed_bitset>()) {
505 }
506
507 if (_storage.template is<fixed_bitset>()) {
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
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
532 fl::u32 new_size = size() + 1;
533 resize(new_size);
534 }
535
537 template<typename... Args>
539 push_back();
540 }
541
544 if (size() > 0) {
545 resize(size() - 1);
546 }
547 }
548
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
561
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
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
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
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
598 if (_storage.template is<fixed_bitset>()) {
599 return N;
600 } else {
601 return _storage.template ptr<bitset_dynamic>()->size();
602 }
603 }
604
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
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;
631 }
632
633 friend bitset_inlined
operator&(
const bitset_inlined &lhs,
635 bitset_inlined
result = lhs;
636
637 if (
result._storage.template is<fixed_bitset>() &&
638 rhs._storage.template is<fixed_bitset>()) {
639
640 *
result._storage.template ptr<fixed_bitset>() &=
641 *rhs._storage.template ptr<fixed_bitset>();
642 } else {
643
644 fl::u32 min_size =
645 result.size() < rhs.size() ?
result.size() : rhs.size();
646 for (fl::u32 i = 0; i < min_size; ++i) {
648 }
649
650 for (fl::u32 i = min_size; i <
result.size(); ++i) {
652 }
653 }
654
656 }
657
658 friend bitset_inlined
operator|(
const bitset_inlined &lhs,
660 bitset_inlined
result = lhs;
661
662 if (
result._storage.template is<fixed_bitset>() &&
663 rhs._storage.template is<fixed_bitset>()) {
664
665 *
result._storage.template ptr<fixed_bitset>() |=
666 *rhs._storage.template ptr<fixed_bitset>();
667 } else {
668
669 fl::u32 max_size =
670 result.size() > rhs.size() ?
result.size() : rhs.size();
671
672
673 if (
result.size() < max_size) {
675 }
676
677
678 for (fl::u32 i = 0; i < rhs.size(); ++i) {
679 if (rhs.test(i)) {
681 }
682 }
683 }
684
686 }
687
688 friend bitset_inlined operator^(const bitset_inlined &lhs,
690 bitset_inlined
result = lhs;
691
692 if (
result._storage.template is<fixed_bitset>() &&
693 rhs._storage.template is<fixed_bitset>()) {
694
695 *
result._storage.template ptr<fixed_bitset>() ^=
696 *rhs._storage.template ptr<fixed_bitset>();
697 } else {
698
699 fl::u32 max_size =
700 result.size() > rhs.size() ?
result.size() : rhs.size();
701
702
703 if (
result.size() < max_size) {
705 }
706
707
708 for (fl::u32 i = 0; i < rhs.size(); ++i) {
710 }
711 }
712
714 }
715
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
730 return !(*this == other);
731 }
732
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;
741 }
742 }
743
744 return size() < other.size();
745 }
746
748 return *this < other || *this == other;
749 }
750
752 return other < *this;
753 }
754
756 return other <= *this;
757 }
758};
759
760}
ClearFlags & operator|=(ClearFlags &a, ClearFlags b)
Enable bitwise OR assignment for ClearFlags.
ClearFlags operator|(ClearFlags a, ClearFlags b)
Enable bitwise OR for ClearFlags.
ClearFlags operator&(ClearFlags a, ClearFlags b)
Enable bitwise AND for ClearFlags.
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)
constexpr remove_reference< T >::type && move(T &&t) 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 the sum of the color channels in one CRGB object is less than another.
FASTLED_FORCE_INLINE bool operator==(const CRGB &lhs, const CRGB &rhs) FL_NOEXCEPT
Check if two CRGB objects have the same color data.
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.
expected< T, E > result
Alias for expected (Rust-style naming)
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.
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.
#define FL_STATIC_ASSERT(...)