21template <fl::u32 N>
class BitsetInlined;
23template <fl::u32 N>
class BitsetFixed;
26template <fl::u32 N = 16>
27using bitset = BitsetInlined<N>;
30using bitset_fixed = BitsetFixed<N>;
34template<
typename IntType>
35inline fl::u8 popcount(IntType value) {
36 return static_cast<fl::u8>(__builtin_popcount(value));
39template<
typename IntType>
40inline fl::u8 countr_zero(IntType value) {
41 return static_cast<fl::u8>(__builtin_ctz(value));
45template <fl::u32 N>
class BitsetFixed {
47 static_assert(
sizeof(fl::u16) == 2,
"u16 should be 2 bytes");
48 static constexpr fl::u32 bits_per_block = 8 *
sizeof(fl::u16);
49 static constexpr fl::u32 block_count =
50 (N + bits_per_block - 1) / bits_per_block;
51 using block_type = fl::u16;
54 block_type _blocks[block_count];
61 Proxy(BitsetFixed &bitset, fl::u32
pos) : _bitset(bitset), _pos(
pos) {}
63 Proxy &operator=(
bool value) {
64 _bitset.set(_pos, value);
68 operator bool()
const {
return _bitset.test(_pos); }
71 Proxy operator[](fl::u32
pos) {
return Proxy(*
this,
pos); }
74 constexpr BitsetFixed() noexcept : _blocks{} {}
81 void reset()
noexcept {
82 for (fl::u32 i = 0; i < block_count; ++i) {
88 BitsetFixed &set(fl::u32
pos,
bool value =
true) {
90 const fl::u32 idx =
pos / bits_per_block;
91 const fl::u32 off =
pos % bits_per_block;
93 _blocks[idx] |= (block_type(1) << off);
95 _blocks[idx] &= ~(block_type(1) << off);
101 void assign(fl::size n,
bool value) {
105 for (fl::size i = 0; i < n; ++i) {
111 BitsetFixed &reset(fl::u32
pos) {
return set(
pos,
false); }
114 BitsetFixed &flip(fl::u32
pos) {
116 const fl::u32 idx =
pos / bits_per_block;
117 const fl::u32 off =
pos % bits_per_block;
118 _blocks[idx] ^= (block_type(1) << off);
124 BitsetFixed &flip()
noexcept {
125 for (fl::u32 i = 0; i < block_count; ++i) {
126 _blocks[i] = ~_blocks[i];
129 if (N % bits_per_block != 0) {
130 const fl::u32 extra = bits_per_block - (N % bits_per_block);
131 _blocks[block_count - 1] &= (~block_type(0) >> extra);
137 bool test(fl::u32
pos)
const noexcept {
139 const fl::u32 idx =
pos / bits_per_block;
140 const fl::u32 off =
pos % bits_per_block;
141 return (_blocks[idx] >> off) & 1;
147 bool operator[](fl::u32
pos)
const noexcept {
return test(
pos); }
150 fl::u32 count()
const noexcept {
153 for (fl::u32 i = 0; i < block_count - 1; ++i) {
154 cnt += fl::popcount(_blocks[i]);
159 if (block_count > 0) {
160 block_type last_block = _blocks[block_count - 1];
163 if (N % bits_per_block != 0) {
164 const fl::u32 valid_bits = N % bits_per_block;
166 block_type mask = (valid_bits == bits_per_block)
167 ?
static_cast<block_type
>(~block_type(0))
168 : ((block_type(1) << valid_bits) - 1);
171 cnt += fl::popcount(last_block);
178 bool any()
const noexcept {
return count() > 0; }
179 bool none()
const noexcept {
return count() == 0; }
180 bool all()
const noexcept {
185 for (fl::u32 i = 0; i < block_count - 1; ++i) {
186 if (_blocks[i] != ~block_type(0)) {
192 if (block_count > 0) {
194 if (N % bits_per_block != 0) {
196 mask = (block_type(1) << (N % bits_per_block)) - 1;
198 mask =
static_cast<block_type
>(~block_type(0));
201 if ((_blocks[block_count - 1] & mask) != mask) {
210 BitsetFixed &operator&=(
const BitsetFixed &other)
noexcept {
211 for (fl::u32 i = 0; i < block_count; ++i) {
212 _blocks[i] &= other._blocks[i];
217 BitsetFixed &operator|=(
const BitsetFixed &other)
noexcept {
218 for (fl::u32 i = 0; i < block_count; ++i) {
219 _blocks[i] |= other._blocks[i];
224 BitsetFixed &operator^=(
const BitsetFixed &other)
noexcept {
225 for (fl::u32 i = 0; i < block_count; ++i) {
226 _blocks[i] ^= other._blocks[i];
232 constexpr fl::u32 size()
const noexcept {
return N; }
238 fl::i32 find_first(
bool test_value, fl::u32
offset = 0)
const noexcept {
245 fl::u32 start_block =
offset / bits_per_block;
246 fl::u32 start_bit =
offset % bits_per_block;
248 for (fl::u32 block_idx = start_block; block_idx < block_count; ++block_idx) {
249 block_type current_block = _blocks[block_idx];
252 if (block_idx == block_count - 1 && N % bits_per_block != 0) {
253 const fl::u32 valid_bits = N % bits_per_block;
254 block_type mask = (valid_bits == bits_per_block)
255 ?
static_cast<block_type
>(~block_type(0))
256 : ((block_type(1) << valid_bits) - 1);
257 current_block &= mask;
262 current_block = ~current_block;
266 if (block_idx == start_block && start_bit > 0) {
267 current_block &= ~((block_type(1) << start_bit) - 1);
271 if (current_block != 0) {
273 fl::u32 bit_pos = fl::countr_zero(current_block);
274 fl::u32 absolute_pos = block_idx * bits_per_block + bit_pos;
277 if (absolute_pos < N) {
278 return static_cast<fl::i32
>(absolute_pos);
291 fl::i32 find_run(
bool test_value, fl::u32 min_length, fl::u32
offset = 0)
const noexcept {
292 fl::u32 run_start =
offset;
293 fl::u32 run_length = 0;
295 for (fl::u32 i =
offset; i < N && run_length < min_length; ++i) {
296 bool current_bit = test(i);
297 if (current_bit != test_value) {
307 if (run_length >= min_length) {
308 return static_cast<fl::i32
>(run_start);
315 friend BitsetFixed
operator&(BitsetFixed lhs,
316 const BitsetFixed &rhs)
noexcept {
319 friend BitsetFixed
operator|(BitsetFixed lhs,
320 const BitsetFixed &rhs)
noexcept {
323 friend BitsetFixed operator^(BitsetFixed lhs,
324 const BitsetFixed &rhs)
noexcept {
327 friend BitsetFixed operator~(BitsetFixed bs)
noexcept {
return bs.flip(); }
333template <fl::u32 N = 16>
337 using fixed_bitset = BitsetFixed<N>;
338 Variant<fixed_bitset, bitset_dynamic> _storage;
342 BitsetInlined &_bitset;
345 Proxy(BitsetInlined &bitset, fl::u32
pos)
346 : _bitset(bitset), _pos(
pos) {}
348 Proxy &operator=(
bool value) {
349 _bitset.set(_pos, value);
353 operator bool()
const {
return _bitset.test(_pos); }
356 Proxy operator[](fl::u32
pos) {
return Proxy(*
this,
pos); }
359 BitsetInlined() : _storage(fixed_bitset()) {}
360 BitsetInlined(fl::size size) : _storage(fixed_bitset()) {
362 _storage = bitset_dynamic(size);
365 BitsetInlined(
const BitsetInlined &other) : _storage(other._storage) {}
366 BitsetInlined(BitsetInlined &&other) noexcept
367 : _storage(
fl::move(other._storage)) {}
368 BitsetInlined &operator=(
const BitsetInlined &other) {
369 if (
this != &other) {
370 _storage = other._storage;
374 BitsetInlined &operator=(BitsetInlined &&other)
noexcept {
375 if (
this != &other) {
376 _storage =
fl::move(other._storage);
382 void reset()
noexcept {
383 if (_storage.template is<fixed_bitset>()) {
384 _storage.template ptr<fixed_bitset>()->reset();
386 _storage.template ptr<bitset_dynamic>()->reset();
390 void assign(fl::size n,
bool value) {
392 if (_storage.template is<fixed_bitset>()) {
393 _storage.template ptr<fixed_bitset>()->assign(n, value);
395 _storage.template ptr<bitset_dynamic>()->assign(n, value);
402 void resize(fl::u32 new_size) {
405 if (_storage.template is<bitset_dynamic>()) {
408 bitset_dynamic *dynamic =
409 _storage.template ptr<bitset_dynamic>();
412 for (fl::u32 i = 0; i < N && i < dynamic->size(); ++i) {
413 if (dynamic->test(i)) {
422 if (_storage.template is<fixed_bitset>()) {
424 bitset_dynamic dynamic(new_size);
425 fixed_bitset *fixed = _storage.template ptr<fixed_bitset>();
428 for (fl::u32 i = 0; i < N; ++i) {
429 if (fixed->test(i)) {
437 _storage.template ptr<bitset_dynamic>()->resize(new_size);
443 BitsetInlined &set(fl::u32
pos,
bool value =
true) {
444 if (
pos >= N && _storage.template is<fixed_bitset>()) {
448 if (_storage.template is<fixed_bitset>()) {
450 _storage.template ptr<fixed_bitset>()->set(
pos, value);
453 if (
pos >= _storage.template ptr<bitset_dynamic>()->size()) {
454 _storage.template ptr<bitset_dynamic>()->resize(
pos + 1);
456 _storage.template ptr<bitset_dynamic>()->set(
pos, value);
462 BitsetInlined &reset(fl::u32
pos) {
return set(
pos,
false); }
465 BitsetInlined &flip(fl::u32
pos) {
466 if (
pos >= N && _storage.template is<fixed_bitset>()) {
470 if (_storage.template is<fixed_bitset>()) {
472 _storage.template ptr<fixed_bitset>()->flip(
pos);
475 if (
pos >= _storage.template ptr<bitset_dynamic>()->size()) {
476 _storage.template ptr<bitset_dynamic>()->resize(
pos + 1);
478 _storage.template ptr<bitset_dynamic>()->flip(
pos);
484 BitsetInlined &flip()
noexcept {
485 if (_storage.template is<fixed_bitset>()) {
486 _storage.template ptr<fixed_bitset>()->flip();
488 _storage.template ptr<bitset_dynamic>()->flip();
494 bool test(fl::u32
pos)
const noexcept {
495 if (_storage.template is<fixed_bitset>()) {
496 return pos < N ? _storage.template ptr<fixed_bitset>()->test(
pos)
499 return _storage.template ptr<bitset_dynamic>()->test(
pos);
504 bool operator[](fl::u32
pos)
const noexcept {
return test(
pos); }
507 fl::u32 count()
const noexcept {
508 if (_storage.template is<fixed_bitset>()) {
509 return _storage.template ptr<fixed_bitset>()->count();
511 return _storage.template ptr<bitset_dynamic>()->count();
516 bool any()
const noexcept {
517 if (_storage.template is<fixed_bitset>()) {
518 return _storage.template ptr<fixed_bitset>()->any();
520 return _storage.template ptr<bitset_dynamic>()->any();
524 bool none()
const noexcept {
525 if (_storage.template is<fixed_bitset>()) {
526 return _storage.template ptr<fixed_bitset>()->none();
528 return _storage.template ptr<bitset_dynamic>()->none();
532 bool all()
const noexcept {
533 if (_storage.template is<fixed_bitset>()) {
534 return _storage.template ptr<fixed_bitset>()->all();
536 return _storage.template ptr<bitset_dynamic>()->all();
541 fl::u32 size()
const noexcept {
542 if (_storage.template is<fixed_bitset>()) {
545 return _storage.template ptr<bitset_dynamic>()->size();
551 if (_storage.template is<fixed_bitset>()) {
552 _storage.template ptr<fixed_bitset>()->to_string(dst);
554 _storage.template ptr<bitset_dynamic>()->to_string(dst);
562 fl::i32 find_first(
bool test_value, fl::u32
offset = 0)
const noexcept {
563 if (_storage.template is<fixed_bitset>()) {
564 return _storage.template ptr<fixed_bitset>()->find_first(test_value,
offset);
566 return _storage.template ptr<bitset_dynamic>()->find_first(test_value,
offset);
571 friend BitsetInlined operator~(
const BitsetInlined &bs)
noexcept {
572 BitsetInlined result = bs;
577 friend BitsetInlined
operator&(
const BitsetInlined &lhs,
578 const BitsetInlined &rhs)
noexcept {
579 BitsetInlined result = lhs;
581 if (result._storage.template is<fixed_bitset>() &&
582 rhs._storage.template is<fixed_bitset>()) {
584 *result._storage.template ptr<fixed_bitset>() &=
585 *rhs._storage.template ptr<fixed_bitset>();
589 result.size() < rhs.size() ? result.size() : rhs.size();
590 for (fl::u32 i = 0; i < min_size; ++i) {
591 result.set(i, result.test(i) && rhs.test(i));
594 for (fl::u32 i = min_size; i < result.size(); ++i) {
602 friend BitsetInlined
operator|(
const BitsetInlined &lhs,
603 const BitsetInlined &rhs)
noexcept {
604 BitsetInlined result = lhs;
606 if (result._storage.template is<fixed_bitset>() &&
607 rhs._storage.template is<fixed_bitset>()) {
609 *result._storage.template ptr<fixed_bitset>() |=
610 *rhs._storage.template ptr<fixed_bitset>();
614 result.size() > rhs.size() ? result.size() : rhs.size();
617 if (result.size() < max_size) {
618 result.resize(max_size);
622 for (fl::u32 i = 0; i < rhs.size(); ++i) {
632 friend BitsetInlined operator^(
const BitsetInlined &lhs,
633 const BitsetInlined &rhs)
noexcept {
634 BitsetInlined result = lhs;
636 if (result._storage.template is<fixed_bitset>() &&
637 rhs._storage.template is<fixed_bitset>()) {
639 *result._storage.template ptr<fixed_bitset>() ^=
640 *rhs._storage.template ptr<fixed_bitset>();
644 result.size() > rhs.size() ? result.size() : rhs.size();
647 if (result.size() < max_size) {
648 result.resize(max_size);
652 for (fl::u32 i = 0; i < rhs.size(); ++i) {
653 result.set(i, result.test(i) != rhs.test(i));