1#ifndef NEFORCE_CORE_CONTAINER_BITSET_HPP__
2#define NEFORCE_CORE_CONTAINER_BITSET_HPP__
17NEFORCE_BEGIN_NAMESPACE__
56 position_(position) {}
64 set_.set(position_, value);
79 explicit constexpr operator bool() const noexcept {
return set_.test(position_); }
93 static constexpr size_t bits_per_block =
sizeof(block_type) * 8;
94 static constexpr size_t block_count = (N + bits_per_block - 1) / bits_per_block;
99 static constexpr block_type last_block_mask() noexcept {
100 if constexpr (block_count == 0) {
103 const size_t excess = block_count * bits_per_block - N;
105 return static_cast<block_type
>(~0ULL);
107 return static_cast<block_type
>(~0ULL) >> excess;
110 NEFORCE_ALWAYS_INLINE
constexpr void check_range(
const size_t pos)
const noexcept {
111 NEFORCE_DEBUG_VERIFY(pos < N,
"bitset position out of range");
114 NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE
constexpr size_t block_index(
const size_t pos)
const noexcept {
115 return pos / bits_per_block;
118 NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE
constexpr size_t bit_index(
const size_t pos)
const noexcept {
119 return pos % bits_per_block;
126 constexpr bitset() noexcept { blocks.fill(0); }
134 constexpr explicit bitset(
unsigned long long value)
noexcept {
136 static_assert(
sizeof(
unsigned long long) >=
sizeof(block_type),
137 "unsigned long long should be at least as large as block_type");
139 while (value != 0 && i < block_count) {
140 blocks[i] =
static_cast<block_type
>(value);
141 NEFORCE_IF_CONSTEXPR(bits_per_block <
sizeof(
unsigned long long) * 8) {
142 value >>=
static_cast<uint32_t>(bits_per_block);
149 NEFORCE_IF_CONSTEXPR(block_count > 0) { blocks[block_count - 1] &= last_block_mask(); }
164 const size_t str_len = str.
length();
165 const size_t M = (str_len < N) ? str_len : N;
167 for (
size_t i = 0; i < M; ++i) {
168 const char c = str[i];
169 size_t pos = M - 1 - i;
172 }
else if (c == zero) {
175 NEFORCE_THROW_EXCEPTION(
value_exception(
"bitset string ctor: invalid character"));
186 constexpr explicit bitset(
const string& str,
const char zero =
'0',
const char one =
'1') :
187 bitset(str.view(), zero, one) {}
195 constexpr explicit bitset(
const char* str,
const char zero =
'0',
const char one =
'1') :
203 for (
auto& b: blocks) {
204 b = ~static_cast<block_type>(0ULL);
206 NEFORCE_IF_CONSTEXPR(N > 0) { blocks[block_count - 1] &= last_block_mask(); }
216 constexpr bitset&
set(
const size_t pos,
const bool value =
true) noexcept {
218 const size_t idx = block_index(pos);
219 const size_t bit = bit_index(pos);
221 blocks[idx] |= (
static_cast<block_type
>(1) << bit);
223 blocks[idx] &= ~(
static_cast<block_type
>(1) << bit);
244 const size_t idx = block_index(pos);
245 const size_t bit = bit_index(pos);
246 blocks[idx] &= ~(
static_cast<block_type
>(1) << bit);
255 for (
auto& b: blocks) {
258 blocks[block_count - 1] &= last_block_mask();
269 const size_t idx = block_index(pos);
270 const size_t bit = bit_index(pos);
271 blocks[idx] ^= (
static_cast<block_type
>(1) << bit);
280 NEFORCE_NODISCARD
constexpr bool operator[](
const size_t pos)
const noexcept {
return test(pos); }
296 NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE
constexpr size_t size() const noexcept {
return N; }
302 NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE
constexpr bool empty() const noexcept {
return N == 0; }
309 NEFORCE_NODISCARD
constexpr bool test(
const size_t position)
const noexcept {
310 check_range(position);
311 const size_t idx = block_index(position);
312 const size_t bit = bit_index(position);
313 return (blocks[idx] & (
static_cast<block_type
>(1) << bit)) != 0;
322 for (
size_t i = 0; i < block_count; ++i) {
323 blocks[i] &= other.blocks[i];
334 for (
size_t i = 0; i < block_count; ++i) {
335 blocks[i] |= other.blocks[i];
346 for (
size_t i = 0; i < block_count; ++i) {
347 blocks[i] ^= other.blocks[i];
372 const size_t block_shift = pos / bits_per_block;
373 const size_t bit_shift = pos % bits_per_block;
375 if (block_shift > 0) {
376 for (
size_t i = block_count - 1; i >= block_shift; --i) {
377 blocks[i] = blocks[i - block_shift];
379 for (
size_t i = 0; i < block_shift; ++i) {
384 for (
size_t i = block_count - 1; i > 0; --i) {
385 blocks[i] = (blocks[i] << bit_shift) | (blocks[i - 1] >> (bits_per_block - bit_shift));
387 blocks[0] <<= bit_shift;
389 blocks[block_count - 1] &= last_block_mask();
404 const size_t block_shift = pos / bits_per_block;
405 const size_t bit_shift = pos % bits_per_block;
407 if (block_shift > 0) {
408 for (
size_t i = 0; i < block_count - block_shift; ++i) {
409 blocks[i] = blocks[i + block_shift];
411 for (
size_t i = block_count - block_shift; i < block_count; ++i) {
416 for (
size_t i = 0; i < block_count - 1; ++i) {
417 blocks[i] = (blocks[i] >> bit_shift) | (blocks[i + 1] << (bits_per_block - bit_shift));
419 blocks[block_count - 1] >>= bit_shift;
420 blocks[block_count - 1] &= last_block_mask();
429 NEFORCE_NODISCARD
constexpr size_t count() const noexcept {
431 for (
size_t i = 0; i < block_count; ++i) {
432 cnt += _NEFORCE
popcount(blocks[i]);
441 NEFORCE_NODISCARD
constexpr bool all() const noexcept {
442 NEFORCE_IF_CONSTEXPR(N == 0) {
return true; }
443 for (
size_t i = 0; i < block_count - 1; ++i) {
444 if (blocks[i] != ~
static_cast<block_type
>(0ULL)) {
448 return blocks[block_count - 1] == last_block_mask();
455 NEFORCE_NODISCARD
constexpr bool any() const noexcept {
456 for (
auto b: blocks) {
468 NEFORCE_NODISCARD
constexpr bool none() const noexcept {
return !
any(); }
475 NEFORCE_NODISCARD
constexpr unsigned long to_ulong()
const {
476 NEFORCE_IF_CONSTEXPR(N >
sizeof(
unsigned long) * 8) {
477 constexpr size_t ulong_blocks = (
sizeof(
unsigned long) * 8 + bits_per_block - 1) / bits_per_block;
478 for (
size_t i = ulong_blocks; i < block_count; ++i) {
479 if (blocks[i] != 0) {
484 constexpr size_t ulong_bits =
sizeof(
unsigned long) * 8;
485 constexpr size_t remainder_bits = ulong_bits % bits_per_block;
486 NEFORCE_IF_CONSTEXPR(remainder_bits != 0) {
487 constexpr size_t last_ulong_block = ulong_bits / bits_per_block;
488 block_type mask = (~static_cast<block_type>(0ULL)) << remainder_bits;
489 if ((blocks[last_ulong_block] & mask) != 0) {
495 NEFORCE_IF_CONSTEXPR(
sizeof(
unsigned long) >=
sizeof(block_type)) {
496 return static_cast<unsigned long>(blocks[0]);
499 unsigned long result = 0;
500 constexpr size_t ulong_blocks = (
sizeof(
unsigned long) * 8 + bits_per_block - 1) / bits_per_block;
501 constexpr size_t blocks_to_use = ulong_blocks < block_count ? ulong_blocks : block_count;
502 for (
size_t i = 0; i < blocks_to_use; ++i) {
503 result |=
static_cast<unsigned long>(blocks[i]) << (i * bits_per_block);
514 NEFORCE_NODISCARD
constexpr unsigned long long to_ullong()
const {
515 NEFORCE_IF_CONSTEXPR(N >
sizeof(
unsigned long long) * 8) {
516 constexpr size_t ullong_blocks = (
sizeof(
unsigned long long) * 8 + bits_per_block - 1) / bits_per_block;
517 for (
size_t i = ullong_blocks; i < block_count; ++i) {
518 if (blocks[i] != 0) {
523 constexpr size_t ullong_bits =
sizeof(
unsigned long long) * 8;
524 constexpr size_t remainder_bits = ullong_bits % bits_per_block;
525 NEFORCE_IF_CONSTEXPR(remainder_bits != 0) {
526 constexpr size_t last_ullong_block = ullong_bits / bits_per_block;
527 block_type mask = (~static_cast<block_type>(0ULL)) << remainder_bits;
528 if ((blocks[last_ullong_block] & mask) != 0) {
534 unsigned long long result = 0;
535 constexpr size_t ullong_bits =
sizeof(
unsigned long long) * 8;
536 constexpr size_t blocks_needed = (ullong_bits + bits_per_block - 1) / bits_per_block;
537 constexpr size_t blocks_to_use = (block_count < blocks_needed) ? block_count : blocks_needed;
538 for (
size_t i = 0; i < blocks_to_use; ++i) {
539 result |=
static_cast<unsigned long long>(blocks[i]) << (i * bits_per_block);
549 NEFORCE_NODISCARD
constexpr bool equal_to(
const bitset& other)
const noexcept {
return blocks == other.blocks; }
556 NEFORCE_NODISCARD
constexpr bool less_than(
const bitset& other)
const noexcept {
return blocks < other.blocks; }
564 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20
string to_string(
const char zero,
const char one)
const {
567 for (
size_t i = N; i > 0; --i) {
583 constexpr void swap(
bitset& other)
noexcept { blocks.swap(other.blocks); }
588NEFORCE_END_NAMESPACE__
constexpr size_type length() const noexcept
获取字符串长度
constexpr void push_back(value_type value)
在末尾插入字符
constexpr void reserve(const size_type n)
预留容量
constexpr reference(bitset &set, const size_t position) noexcept
构造函数
constexpr reference & operator=(const reference &value) noexcept
赋值操作符(引用版本)
constexpr reference & flip() noexcept
翻转该位
constexpr reference & operator=(const bool value) noexcept
赋值操作符(bool版本)
constexpr bitset(const char *str, const char zero='0', const char one='1')
C风格字符串初始化
constexpr unsigned long to_ulong() const
转换为unsigned long
constexpr bitset & set() noexcept
将所有位设置为1
constexpr void swap(bitset &other) noexcept
交换两个bitset的内容
constexpr bool all() const noexcept
检查所有位是否都为1
constexpr string to_string(const char zero, const char one) const
转换为字符串
constexpr bool none() const noexcept
检查是否所有位都是0
constexpr bool test(const size_t position) const noexcept
测试指定位置的位
constexpr bitset & reset(const size_t pos) noexcept
将指定位置的位重置为0
constexpr bitset(const string &str, const char zero='0', const char one='1')
string初始化
constexpr bool operator[](const size_t pos) const noexcept
常量下标访问
constexpr bitset & set(const size_t pos, const bool value=true) noexcept
将指定位置的位设置为指定值
constexpr string to_string() const
转换为字符串(默认使用'0'和'1')
constexpr bitset & operator^=(const bitset &other) noexcept
按位异或赋值
constexpr bool less_than(const bitset &other) const noexcept
小于比较操作符(按字典序)
constexpr size_t size() const noexcept
获取位数
constexpr bitset & reset() noexcept
将所有位重置为0
constexpr bitset & operator<<=(const uint32_t pos) noexcept
左移赋值
constexpr bitset & operator&=(const bitset &other) noexcept
按位与赋值
constexpr bool equal_to(const bitset &other) const noexcept
相等比较操作符
constexpr bool empty() const noexcept
检查是否为空
constexpr bitset(const string_view str, const char zero='0', const char one='1')
用字符串初始化bitset
constexpr unsigned long long to_ullong() const
转换为unsigned long long
constexpr bitset() noexcept
默认构造函数,所有位初始化为0
constexpr reference operator[](size_t pos) noexcept
非常量下标访问
constexpr bitset(unsigned long long value) noexcept
整数初始化
constexpr bitset & operator>>=(const uint32_t pos) noexcept
右移赋值
constexpr bitset operator~() const noexcept
按位取反
constexpr bitset & flip(const size_t pos) noexcept
翻转指定位置的位
constexpr bool any() const noexcept
检查是否存在值为1的位
constexpr bitset & flip() noexcept
翻转所有位
constexpr size_t count() const noexcept
统计值为1的位的数量
constexpr bitset & operator|=(const bitset &other) noexcept
按位或赋值
constexpr int popcount(const uintptr_t x) noexcept
计算整数中1的个数
unsigned int uint32_t
32位无符号整数类型
basic_string_view< char > string_view
字符字符串视图