1#ifndef NEFORCE_CORE_CONTAINER_BITSET_HPP__
2#define NEFORCE_CORE_CONTAINER_BITSET_HPP__
16NEFORCE_BEGIN_NAMESPACE__
55 position_(position) {}
63 set_.set(position_, value);
78 explicit constexpr operator bool() const noexcept {
return set_.test(position_); }
92 static constexpr size_t bits_per_block =
sizeof(block_type) * 8;
93 static constexpr size_t block_count = (N + bits_per_block - 1) / bits_per_block;
98 static constexpr block_type last_block_mask() noexcept {
99 const size_t excess = block_count * bits_per_block - N;
101 return static_cast<block_type
>(~0ULL);
103 return (
static_cast<block_type
>(1ULL) << (bits_per_block - excess)) - 1;
106 NEFORCE_ALWAYS_INLINE
constexpr void check_range(
const size_t pos)
const noexcept {
110 NEFORCE_ALWAYS_INLINE
constexpr size_t block_index(
const size_t pos)
const noexcept {
return pos / bits_per_block; }
112 NEFORCE_ALWAYS_INLINE
constexpr size_t bit_index(
const size_t pos)
const noexcept {
return pos % bits_per_block; }
118 constexpr bitset() noexcept { blocks.fill(0); }
126 constexpr explicit bitset(
const block_type value)
noexcept {
128 NEFORCE_IF_CONSTEXPR(block_count > 0) { blocks[0] = value & last_block_mask(); }
143 const size_t str_len = str.
length();
144 const size_t M = (str_len < N) ? str_len : N;
146 for (
size_t i = 0; i < M; ++i) {
147 const char c = str[i];
148 size_t pos = N - 1 - i;
151 }
else if (c == zero) {
154 NEFORCE_THROW_EXCEPTION(
value_exception(
"bitset string ctor: invalid character"));
165 constexpr explicit bitset(
const string& str,
const char zero =
'0',
const char one =
'1') :
166 bitset(str.view(), zero, one) {}
174 constexpr explicit bitset(
const char* str,
const char zero =
'0',
const char one =
'1') :
182 for (
auto& b: blocks) {
183 b = ~static_cast<block_type>(0ULL);
185 blocks[block_count - 1] &= last_block_mask();
195 constexpr bitset&
set(
const size_t pos,
const bool value =
true) noexcept {
197 const size_t idx = block_index(pos);
198 const size_t bit = bit_index(pos);
200 blocks[idx] |= (
static_cast<block_type
>(1) << bit);
202 blocks[idx] &= ~(
static_cast<block_type
>(1) << bit);
223 const size_t idx = block_index(pos);
224 const size_t bit = bit_index(pos);
225 blocks[idx] &= ~(
static_cast<block_type
>(1) << bit);
234 for (
auto& b: blocks) {
237 blocks[block_count - 1] &= last_block_mask();
248 const size_t idx = block_index(pos);
249 const size_t bit = bit_index(pos);
250 blocks[idx] ^= (
static_cast<block_type
>(1) << bit);
259 NEFORCE_NODISCARD
constexpr bool operator[](
const size_t pos)
const noexcept {
return test(pos); }
275 NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE
constexpr size_t size() const noexcept {
return N; }
281 NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE
constexpr bool empty() const noexcept {
return N == 0; }
288 NEFORCE_NODISCARD
constexpr bool test(
const size_t position)
const noexcept {
289 check_range(position);
290 const size_t idx = block_index(position);
291 const size_t bit = bit_index(position);
292 return (blocks[idx] & (
static_cast<block_type
>(1) << bit)) != 0;
301 for (
size_t i = 0; i < block_count; ++i) {
302 blocks[i] &= other.blocks[i];
313 for (
size_t i = 0; i < block_count; ++i) {
314 blocks[i] |= other.blocks[i];
325 for (
size_t i = 0; i < block_count; ++i) {
326 blocks[i] ^= other.blocks[i];
351 const size_t block_shift = pos / bits_per_block;
352 const size_t bit_shift = pos % bits_per_block;
354 if (block_shift > 0) {
355 for (
size_t i = block_count - 1; i >= block_shift; --i) {
356 blocks[i] = blocks[i - block_shift];
358 for (
size_t i = 0; i < block_shift; ++i) {
363 for (
size_t i = block_count - 1; i > 0; --i) {
364 blocks[i] = (blocks[i] << bit_shift) | (blocks[i - 1] >> (bits_per_block - bit_shift));
366 blocks[0] <<= bit_shift;
368 blocks[block_count - 1] &= last_block_mask();
383 const size_t block_shift = pos / bits_per_block;
384 const size_t bit_shift = pos % bits_per_block;
386 if (block_shift > 0) {
387 for (
size_t i = 0; i < block_count - block_shift; ++i) {
388 blocks[i] = blocks[i + block_shift];
390 for (
size_t i = block_count - block_shift; i < block_count; ++i) {
395 for (
size_t i = 0; i < block_count - 1; ++i) {
396 blocks[i] = (blocks[i] >> bit_shift) | (blocks[i + 1] << (bits_per_block - bit_shift));
398 blocks[block_count - 1] >>= bit_shift;
399 blocks[block_count - 1] &= last_block_mask();
408 NEFORCE_NODISCARD
constexpr size_t count() const noexcept {
410 for (
size_t i = 0; i < block_count; ++i) {
411 cnt += _NEFORCE
popcount(blocks[i]);
420 NEFORCE_NODISCARD
constexpr bool all() const noexcept {
421 for (
size_t i = 0; i < block_count - 1; ++i) {
422 if (blocks[i] != ~
static_cast<block_type
>(0ULL)) {
426 return blocks[block_count - 1] == last_block_mask();
433 NEFORCE_NODISCARD
constexpr bool any() const noexcept {
434 for (
auto b: blocks) {
446 NEFORCE_NODISCARD
constexpr bool none() const noexcept {
return !
any(); }
453 NEFORCE_NODISCARD
constexpr unsigned long to_ulong() const noexcept {
454 NEFORCE_IF_CONSTEXPR(N >
sizeof(
unsigned long) * 8) {
455 constexpr size_t ulong_blocks = (
sizeof(
unsigned long) * 8 + bits_per_block - 1) / bits_per_block;
456 for (
size_t i = ulong_blocks; i < block_count; ++i) {
457 if (blocks[i] != 0) {
462 constexpr size_t ulong_bits =
sizeof(
unsigned long) * 8;
463 constexpr size_t remainder_bits = ulong_bits % bits_per_block;
464 NEFORCE_IF_CONSTEXPR(remainder_bits != 0) {
465 constexpr size_t last_ulong_block = ulong_bits / bits_per_block;
466 block_type mask = (~static_cast<block_type>(0ULL)) << remainder_bits;
467 if ((blocks[last_ulong_block] & mask) != 0) {
473 NEFORCE_IF_CONSTEXPR(
sizeof(
unsigned long) >=
sizeof(block_type)) {
474 return static_cast<unsigned long>(blocks[0]);
477 unsigned long result = 0;
478 constexpr size_t ulong_blocks = (
sizeof(
unsigned long) * 8 + bits_per_block - 1) / bits_per_block;
479 constexpr size_t blocks_to_use = ulong_blocks < block_count ? ulong_blocks : block_count;
480 for (
size_t i = 0; i < blocks_to_use; ++i) {
481 result |=
static_cast<unsigned long>(blocks[i]) << (i * bits_per_block);
492 NEFORCE_NODISCARD
constexpr unsigned long long to_ullong() const noexcept {
493 NEFORCE_IF_CONSTEXPR(N >
sizeof(
unsigned long long) * 8) {
494 constexpr size_t ullong_blocks = (
sizeof(
unsigned long long) * 8 + bits_per_block - 1) / bits_per_block;
495 for (
size_t i = ullong_blocks; i < block_count; ++i) {
496 if (blocks[i] != 0) {
501 constexpr size_t ullong_bits =
sizeof(
unsigned long long) * 8;
502 constexpr size_t remainder_bits = ullong_bits % bits_per_block;
503 NEFORCE_IF_CONSTEXPR(remainder_bits != 0) {
504 constexpr size_t last_ullong_block = ullong_bits / bits_per_block;
505 block_type mask = (~static_cast<block_type>(0ULL)) << remainder_bits;
506 if ((blocks[last_ullong_block] & mask) != 0) {
512 NEFORCE_IF_CONSTEXPR(
sizeof(
unsigned long long) >=
sizeof(block_type)) {
513 return static_cast<unsigned long long>(blocks[0]);
516 unsigned long long result = 0;
517 constexpr size_t ullong_blocks = (
sizeof(
unsigned long long) * 8 + bits_per_block - 1) / bits_per_block;
518 constexpr size_t blocks_to_use = ullong_blocks < block_count ? ullong_blocks : block_count;
519 for (
size_t i = 0; i < blocks_to_use; ++i) {
520 result |=
static_cast<unsigned long long>(blocks[i]) << (i * bits_per_block);
531 NEFORCE_NODISCARD
constexpr bool operator==(
const bitset& other)
const noexcept {
return blocks == other.blocks; }
538 NEFORCE_NODISCARD
constexpr bool operator<(
const bitset& other)
const noexcept {
return blocks < other.blocks; }
544 NEFORCE_NODISCARD
constexpr size_t to_hash() const noexcept {
return blocks.to_hash(); }
552 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20
string to_string(
const char zero,
const char one)
const {
555 for (
size_t i = N; i > 0; --i) {
571 constexpr void swap(
bitset& other)
noexcept { blocks.swap(other.blocks); }
576NEFORCE_END_NAMESPACE__
NEFORCE_NODISCARD constexpr size_type length() const noexcept
获取字符串长度
NEFORCE_CONSTEXPR20 void reserve(const size_type n)
预留容量
NEFORCE_CONSTEXPR20 void push_back(value_type value)
在末尾插入字符
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 bitset & set() noexcept
将所有位设置为1
NEFORCE_NODISCARD constexpr bool all() const noexcept
检查所有位是否都为1
constexpr void swap(bitset &other) noexcept
交换两个bitset的内容
constexpr bitset & reset(const size_t pos) noexcept
将指定位置的位重置为0
NEFORCE_NODISCARD constexpr bool none() const noexcept
检查是否所有位都是0
constexpr bitset(const string &str, const char zero='0', const char one='1')
string初始化
constexpr bitset & set(const size_t pos, const bool value=true) noexcept
将指定位置的位设置为指定值
NEFORCE_NODISCARD constexpr bool any() const noexcept
检查是否存在值为1的位
NEFORCE_NODISCARD constexpr size_t to_hash() const noexcept
计算哈希值
NEFORCE_NODISCARD constexpr bitset & operator|=(const bitset &other) noexcept
按位或赋值
NEFORCE_NODISCARD constexpr bitset & operator>>=(const uint32_t pos) noexcept
右移赋值
NEFORCE_NODISCARD constexpr bool operator==(const bitset &other) const noexcept
相等比较操作符
NEFORCE_NODISCARD constexpr bitset & operator<<=(const uint32_t pos) noexcept
左移赋值
NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE constexpr size_t size() const noexcept
获取位数
constexpr bitset & reset() noexcept
将所有位重置为0
NEFORCE_NODISCARD constexpr unsigned long long to_ullong() const noexcept
转换为unsigned long long
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const char zero, const char one) const
转换为字符串
NEFORCE_NODISCARD constexpr bitset operator~() const noexcept
按位取反
NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE constexpr bool empty() const noexcept
检查是否为空
NEFORCE_NODISCARD constexpr bool test(const size_t position) const noexcept
测试指定位置的位
constexpr bitset(const string_view str, const char zero='0', const char one='1')
用字符串初始化bitset
constexpr bitset(const block_type value) noexcept
整数初始化
constexpr bitset() noexcept
默认构造函数,所有位初始化为0
NEFORCE_NODISCARD constexpr bool operator<(const bitset &other) const noexcept
小于比较操作符(按字典序)
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string() const
转换为字符串(默认使用'0'和'1')
NEFORCE_NODISCARD constexpr bitset & operator^=(const bitset &other) noexcept
按位异或赋值
NEFORCE_NODISCARD constexpr size_t count() const noexcept
统计值为1的位的数量
NEFORCE_NODISCARD constexpr unsigned long to_ulong() const noexcept
转换为unsigned long
constexpr bitset & flip(const size_t pos) noexcept
翻转指定位置的位
NEFORCE_NODISCARD constexpr bitset & operator&=(const bitset &other) noexcept
按位与赋值
constexpr bitset & flip() noexcept
翻转所有位
NEFORCE_NODISCARD constexpr reference operator[](size_t pos) noexcept
非常量下标访问
NEFORCE_NODISCARD constexpr bool operator[](const size_t pos) const noexcept
常量下标访问
constexpr int popcount(const uintptr_t x) noexcept
计算整数中1的个数
unsigned int uint32_t
32位无符号整数类型
#define NEFORCE_DEBUG_VERIFY(CON, MESG)
调试模式断言
basic_string_view< char > string_view
字符字符串视图