22template <fl::u32 N>
class bitset_inlined;
24template <fl::u32 N>
class bitset_fixed;
27template <fl::u32 N = 16>
28using bitset = bitset_inlined<N>;
32template<
typename IntType>
34 return static_cast<fl::u8>(__builtin_popcount(
value));
37template<
typename IntType>
43template <fl::u32 N>
class bitset_fixed {
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;
52 block_type _blocks[block_count];
56 bitset_fixed &_bitset;
59 Proxy(bitset_fixed &bitset, fl::u32
pos)
FL_NOEXCEPT : _bitset(bitset), _pos(
pos) {}
62 _bitset.set(_pos, value);
66 operator bool()
const FL_NOEXCEPT {
return _bitset.test(_pos); }
80 for (fl::u32 i = 0; i < block_count; ++i) {
88 const fl::u32 idx =
pos / bits_per_block;
89 const fl::u32 off =
pos % bits_per_block;
91 _blocks[idx] |= (block_type(1) << off);
93 _blocks[idx] &= ~(block_type(1) << off);
103 for (fl::size i = 0; i < n; ++i) {
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);
123 for (fl::u32 i = 0; i < block_count; ++i) {
124 _blocks[i] = ~_blocks[i];
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);
137 const fl::u32 idx =
pos / bits_per_block;
138 const fl::u32 off =
pos % bits_per_block;
139 return (_blocks[idx] >> off) & 1;
151 for (fl::u32 i = 0; i < block_count - 1; ++i) {
152 cnt += fl::popcount(_blocks[i]);
157 if (block_count > 0) {
158 block_type last_block = _blocks[block_count - 1];
161 if (N % bits_per_block != 0) {
162 const fl::u32 valid_bits = N % bits_per_block;
164 block_type mask = (valid_bits == bits_per_block)
165 ?
static_cast<block_type
>(~block_type(0))
166 : ((block_type(1) << valid_bits) - 1);
169 cnt += fl::popcount(last_block);
176 bool any()
const FL_NOEXCEPT {
return count() > 0; }
177 bool none()
const FL_NOEXCEPT {
return count() == 0; }
183 for (fl::u32 i = 0; i < block_count - 1; ++i) {
184 if (_blocks[i] != ~block_type(0)) {
190 if (block_count > 0) {
192 if (N % bits_per_block != 0) {
194 mask = (block_type(1) << (N % bits_per_block)) - 1;
196 mask =
static_cast<block_type
>(~block_type(0));
199 if ((_blocks[block_count - 1] & mask) != mask) {
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];
216 for (fl::u32 i = 0; i < block_count; ++i) {
217 _blocks[i] |= other._blocks[i];
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];
230 constexpr fl::u32 size()
const FL_NOEXCEPT {
return N; }
243 fl::u32 start_block =
offset / bits_per_block;
244 fl::u32 start_bit =
offset % bits_per_block;
246 for (fl::u32 block_idx = start_block; block_idx < block_count; ++block_idx) {
247 block_type current_block = _blocks[block_idx];
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;
260 current_block = ~current_block;
264 if (block_idx == start_block && start_bit > 0) {
265 current_block &= ~((block_type(1) << start_bit) - 1);
269 if (current_block != 0) {
271 fl::u32 bit_pos = fl::countr_zero(current_block);
272 fl::u32 absolute_pos = block_idx * bits_per_block + bit_pos;
275 if (absolute_pos < N) {
276 return static_cast<fl::i32
>(absolute_pos);
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;
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) {
305 if (run_length >= min_length) {
306 return static_cast<fl::i32
>(run_start);
314 for (fl::u32 i = 0; i < block_count; ++i) {
315 if (_blocks[i] != other._blocks[i]) {
323 return !(*
this == other);
328 for (fl::i32 i =
static_cast<fl::i32
>(block_count) - 1; i >= 0; --i) {
329 if (_blocks[i] < other._blocks[i]) {
332 if (_blocks[i] > other._blocks[i]) {
340 return *
this < other || *
this == other;
344 return other < *
this;
348 return other <= *
this;
352 friend bitset_fixed
operator&(bitset_fixed lhs,
356 friend bitset_fixed
operator|(bitset_fixed lhs,
360 friend bitset_fixed operator^(bitset_fixed lhs,
364 friend bitset_fixed operator~(bitset_fixed bs)
FL_NOEXCEPT {
return bs.flip(); }
370template <fl::u32 N = 16>
371class bitset_inlined {
374 using fixed_bitset = bitset_fixed<N>;
375 variant<fixed_bitset, bitset_dynamic> _storage;
379 bitset_inlined &_bitset;
383 : _bitset(bitset), _pos(
pos) {}
386 _bitset.set(_pos, value);
390 operator bool()
const FL_NOEXCEPT {
return _bitset.test(_pos); }
396 bitset_inlined()
FL_NOEXCEPT : _storage(fixed_bitset()) {}
397 bitset_inlined(fl::size size)
FL_NOEXCEPT : _storage(fixed_bitset()) {
399 _storage = bitset_dynamic(size);
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;
411 bitset_inlined &operator=(bitset_inlined &&other)
FL_NOEXCEPT {
412 if (
this != &other) {
413 _storage =
fl::move(other._storage);
420 if (_storage.template is<fixed_bitset>()) {
421 _storage.template ptr<fixed_bitset>()->reset();
423 _storage.template ptr<bitset_dynamic>()->reset();
429 if (_storage.template is<fixed_bitset>()) {
430 _storage.template ptr<fixed_bitset>()->assign(n,
value);
432 _storage.template ptr<bitset_dynamic>()->assign(n,
value);
442 if (_storage.template is<bitset_dynamic>()) {
445 bitset_dynamic *dynamic =
446 _storage.template ptr<bitset_dynamic>();
449 for (fl::u32 i = 0; i < N && i < dynamic->size(); ++i) {
450 if (dynamic->test(i)) {
459 if (_storage.template is<fixed_bitset>()) {
461 bitset_dynamic dynamic(new_size);
462 fixed_bitset *fixed = _storage.template ptr<fixed_bitset>();
465 for (fl::u32 i = 0; i < N; ++i) {
466 if (fixed->test(i)) {
474 _storage.template ptr<bitset_dynamic>()->resize(new_size);
481 if (
pos >= N && _storage.template is<fixed_bitset>()) {
485 if (_storage.template is<fixed_bitset>()) {
487 _storage.template ptr<fixed_bitset>()->set(
pos,
value);
490 if (
pos >= _storage.template ptr<bitset_dynamic>()->size()) {
491 _storage.template ptr<bitset_dynamic>()->resize(
pos + 1);
493 _storage.template ptr<bitset_dynamic>()->set(
pos,
value);
503 if (
pos >= N && _storage.template is<fixed_bitset>()) {
507 if (_storage.template is<fixed_bitset>()) {
509 _storage.template ptr<fixed_bitset>()->flip(
pos);
512 if (
pos >= _storage.template ptr<bitset_dynamic>()->size()) {
513 _storage.template ptr<bitset_dynamic>()->resize(
pos + 1);
515 _storage.template ptr<bitset_dynamic>()->flip(
pos);
522 if (_storage.template is<fixed_bitset>()) {
523 _storage.template ptr<fixed_bitset>()->flip();
525 _storage.template ptr<bitset_dynamic>()->flip();
532 fl::u32 new_size = size() + 1;
537 template<
typename... Args>
551 if (_storage.template is<fixed_bitset>()) {
552 return pos < N ? _storage.template ptr<fixed_bitset>()->test(
pos)
555 return _storage.template ptr<bitset_dynamic>()->test(
pos);
564 if (_storage.template is<fixed_bitset>()) {
565 return _storage.template ptr<fixed_bitset>()->count();
567 return _storage.template ptr<bitset_dynamic>()->count();
573 if (_storage.template is<fixed_bitset>()) {
574 return _storage.template ptr<fixed_bitset>()->any();
576 return _storage.template ptr<bitset_dynamic>()->any();
581 if (_storage.template is<fixed_bitset>()) {
582 return _storage.template ptr<fixed_bitset>()->none();
584 return _storage.template ptr<bitset_dynamic>()->none();
589 if (_storage.template is<fixed_bitset>()) {
590 return _storage.template ptr<fixed_bitset>()->all();
592 return _storage.template ptr<bitset_dynamic>()->all();
598 if (_storage.template is<fixed_bitset>()) {
601 return _storage.template ptr<bitset_dynamic>()->size();
607 if (_storage.template is<fixed_bitset>()) {
608 _storage.template ptr<fixed_bitset>()->to_string(dst);
610 _storage.template ptr<bitset_dynamic>()->to_string(dst);
619 if (_storage.template is<fixed_bitset>()) {
620 return _storage.template ptr<fixed_bitset>()->find_first(test_value,
offset);
622 return _storage.template ptr<bitset_dynamic>()->find_first(test_value,
offset);
627 friend bitset_inlined operator~(
const bitset_inlined &bs)
FL_NOEXCEPT {
628 bitset_inlined
result = bs;
633 friend bitset_inlined
operator&(
const bitset_inlined &lhs,
635 bitset_inlined
result = lhs;
637 if (
result._storage.template is<fixed_bitset>() &&
638 rhs._storage.template is<fixed_bitset>()) {
640 *
result._storage.template ptr<fixed_bitset>() &=
641 *rhs._storage.template ptr<fixed_bitset>();
645 result.size() < rhs.size() ?
result.size() : rhs.size();
646 for (fl::u32 i = 0; i < min_size; ++i) {
650 for (fl::u32 i = min_size; i <
result.size(); ++i) {
658 friend bitset_inlined
operator|(
const bitset_inlined &lhs,
660 bitset_inlined
result = lhs;
662 if (
result._storage.template is<fixed_bitset>() &&
663 rhs._storage.template is<fixed_bitset>()) {
665 *
result._storage.template ptr<fixed_bitset>() |=
666 *rhs._storage.template ptr<fixed_bitset>();
670 result.size() > rhs.size() ?
result.size() : rhs.size();
673 if (
result.size() < max_size) {
678 for (fl::u32 i = 0; i < rhs.size(); ++i) {
688 friend bitset_inlined operator^(
const bitset_inlined &lhs,
690 bitset_inlined
result = lhs;
692 if (
result._storage.template is<fixed_bitset>() &&
693 rhs._storage.template is<fixed_bitset>()) {
695 *
result._storage.template ptr<fixed_bitset>() ^=
696 *rhs._storage.template ptr<fixed_bitset>();
700 result.size() > rhs.size() ?
result.size() : rhs.size();
703 if (
result.size() < max_size) {
708 for (fl::u32 i = 0; i < rhs.size(); ++i) {
718 if (size() != other.size()) {
721 for (fl::u32 i = 0; i < size(); ++i) {
722 if (test(i) != other.test(i)) {
730 return !(*
this == other);
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) {
744 return size() < other.size();
748 return *
this < other || *
this == other;
752 return other < *
this;
756 return other <= *
this;