1#ifndef MSTL_CORE_CONTAINER_BITSET_HPP__
2#define MSTL_CORE_CONTAINER_BITSET_HPP__
8class bitset :
public icommon<bitset<N>>,
public istringify<bitset<N>> {
11 static constexpr size_t bits_per_block =
sizeof(block_type) * 8;
12 static constexpr size_t block_count = (N + bits_per_block - 1) / bits_per_block;
14 array<block_type, block_count> blocks{};
16 static constexpr block_type last_block_mask() noexcept {
17 const size_t excess = block_count * bits_per_block - N;
18 if (excess == 0)
return static_cast<block_type
>(~0ULL);
19 return (
static_cast<block_type
>(1ULL) << (bits_per_block - excess)) - 1;
22 MSTL_ALWAYS_INLINE
constexpr void check_range(
const size_t pos)
const noexcept {
23 MSTL_DEBUG_VERIFY(pos < N,
"bitset position out of range");
26 MSTL_ALWAYS_INLINE
constexpr size_t block_index(
const size_t pos)
const noexcept {
27 return pos / bits_per_block;
29 MSTL_ALWAYS_INLINE
constexpr size_t bit_index(
const size_t pos)
const noexcept {
30 return pos % bits_per_block;
34 constexpr bitset() noexcept {
38 constexpr explicit bitset(
const block_type val)
noexcept {
40 MSTL_IF_CONSTEXPR (block_count > 0) {
41 blocks[0] = val & last_block_mask();
45 constexpr explicit bitset(
const string_view str,
46 const char zero =
'0',
const char one =
'1') {
48 const size_t str_len = str.length();
49 const size_t M = (str_len < N) ? str_len : N;
51 for (
size_t i = 0; i < M; ++i) {
52 const char c = str[i];
53 size_t pos = N - 1 - i;
56 }
else if (c == zero) {
59 throw_exception(value_exception(
"bitset string ctor: invalid character"));
64 constexpr explicit bitset(
const string& str,
const char zero =
'0',
const char one =
'1')
65 : bitset(str.view(), zero, one) {}
67 constexpr explicit bitset(
const char* str,
const char zero =
'0',
const char one =
'1')
68 : bitset(string_view{str}, zero, one) {}
71 constexpr bitset& set() noexcept {
72 for (
auto& b : blocks) b = ~static_cast<block_type>(0ULL);
73 blocks[block_count - 1] &= last_block_mask();
77 constexpr bitset& set(
const size_t pos,
const bool value =
true) noexcept {
79 const size_t idx = block_index(pos);
80 const size_t bit = bit_index(pos);
82 blocks[idx] |= (
static_cast<block_type
>(1) << bit);
84 blocks[idx] &= ~(
static_cast<block_type
>(1) << bit);
88 constexpr bitset& reset() noexcept {
93 constexpr bitset& reset(
const size_t pos)
noexcept {
95 const size_t idx = block_index(pos);
96 const size_t bit = bit_index(pos);
97 blocks[idx] &= ~(
static_cast<block_type
>(1) << bit);
101 constexpr bitset& flip() noexcept {
102 for (
auto& b : blocks) {
105 blocks[block_count - 1] &= last_block_mask();
109 constexpr bitset& flip(
const size_t pos)
noexcept {
111 const size_t idx = block_index(pos);
112 const size_t bit = bit_index(pos);
113 blocks[idx] ^= (
static_cast<block_type
>(1) << bit);
123 constexpr reference(bitset& b,
const size_t p) noexcept
126 constexpr reference& operator =(
const bool x)
noexcept {
130 constexpr reference& operator =(
const reference& x)
noexcept {
131 return *
this =
static_cast<bool>(x);
133 constexpr operator bool() const noexcept {
136 constexpr reference& flip() noexcept {
140 constexpr void flip() volatile noexcept = delete;
143 MSTL_NODISCARD constexpr
bool operator [](const
size_t pos) const noexcept {
146 MSTL_NODISCARD
constexpr reference operator [](
size_t pos)
noexcept {
148 return reference(*
this, pos);
151 MSTL_NODISCARD
constexpr size_t size() const noexcept {
return N; }
152 MSTL_NODISCARD
constexpr bool empty() const noexcept {
return N == 0; }
154 MSTL_NODISCARD
constexpr bool test(
const size_t pos)
const noexcept {
156 const size_t idx = block_index(pos);
157 const size_t bit = bit_index(pos);
158 return (blocks[idx] & (
static_cast<block_type
>(1) << bit)) != 0;
161 MSTL_NODISCARD
constexpr bitset& operator &=(
const bitset& other)
noexcept {
162 for (
size_t i = 0; i < block_count; ++i)
163 blocks[i] &= other.blocks[i];
167 MSTL_NODISCARD
constexpr bitset& operator |=(
const bitset& other)
noexcept {
168 for (
size_t i = 0; i < block_count; ++i)
169 blocks[i] |= other.blocks[i];
173 MSTL_NODISCARD
constexpr bitset& operator ^=(
const bitset& other)
noexcept {
174 for (
size_t i = 0; i < block_count; ++i)
175 blocks[i] ^= other.blocks[i];
179 MSTL_NODISCARD
constexpr bitset operator ~() const noexcept {
185 MSTL_NODISCARD
constexpr bitset& operator <<=(
const size_t pos)
noexcept {
190 const size_t block_shift = pos / bits_per_block;
191 const size_t bit_shift = pos % bits_per_block;
193 if (block_shift > 0) {
194 for (
size_t i = block_count - 1; i >= block_shift; --i) {
195 blocks[i] = blocks[i - block_shift];
197 for (
size_t i = 0; i < block_shift; ++i) {
202 for (
size_t i = block_count - 1; i > 0; --i) {
203 blocks[i] = (blocks[i] << bit_shift) | (blocks[i - 1] >> (bits_per_block - bit_shift));
205 blocks[0] <<= bit_shift;
207 blocks[block_count - 1] &= last_block_mask();
212 MSTL_NODISCARD
constexpr bitset& operator >>=(
const size_t pos)
noexcept {
217 const size_t block_shift = pos / bits_per_block;
218 const size_t bit_shift = pos % bits_per_block;
220 if (block_shift > 0) {
221 for (
size_t i = 0; i < block_count - block_shift; ++i) {
222 blocks[i] = blocks[i + block_shift];
224 for (
size_t i = block_count - block_shift; i < block_count; ++i) {
229 for (
size_t i = 0; i < block_count - 1; ++i) {
230 blocks[i] = (blocks[i] >> bit_shift) | (blocks[i + 1] << (bits_per_block - bit_shift));
232 blocks[block_count - 1] >>= bit_shift;
233 blocks[block_count - 1] &= last_block_mask();
238 MSTL_NODISCARD
constexpr size_t count() const noexcept {
240 for (
size_t i = 0; i < block_count; ++i) {
246 MSTL_NODISCARD
constexpr bool all() const noexcept {
247 for (
size_t i = 0; i < block_count - 1; ++i) {
248 if (blocks[i] != ~
static_cast<block_type
>(0ULL))
return false;
250 return blocks[block_count - 1] == last_block_mask();
253 MSTL_NODISCARD
constexpr bool any() const noexcept {
254 for (
auto b : blocks)
255 if (b != 0)
return true;
259 MSTL_NODISCARD
constexpr bool none() const noexcept {
263 MSTL_NODISCARD
constexpr unsigned long to_ulong() const noexcept {
264 MSTL_IF_CONSTEXPR (N >
sizeof(
unsigned long) * 8) {
265 constexpr size_t ulong_blocks = (
sizeof(
unsigned long) * 8 + bits_per_block - 1) / bits_per_block;
266 for (
size_t i = ulong_blocks; i < block_count; ++i) {
267 if (blocks[i] != 0) {
268 throw_exception(value_exception(
"bitset to_ulong overflow"));
272 constexpr size_t ulong_bits =
sizeof(
unsigned long) * 8;
273 constexpr size_t remainder_bits = ulong_bits % bits_per_block;
274 MSTL_IF_CONSTEXPR (remainder_bits != 0) {
275 constexpr size_t last_ulong_block = ulong_bits / bits_per_block;
276 block_type mask = (~static_cast<block_type>(0ULL)) << remainder_bits;
277 if ((blocks[last_ulong_block] & mask) != 0) {
278 throw_exception(value_exception(
"bitset to_ulong overflow"));
283 MSTL_IF_CONSTEXPR (
sizeof(
unsigned long) >=
sizeof(block_type)) {
284 return static_cast<unsigned long>(blocks[0]);
286 unsigned long result = 0;
287 constexpr size_t ulong_blocks = (
sizeof(
unsigned long) * 8 + bits_per_block - 1) / bits_per_block;
288 constexpr size_t blocks_to_use = ulong_blocks < block_count ? ulong_blocks : block_count;
289 for (
size_t i = 0; i < blocks_to_use; ++i) {
290 result |=
static_cast<unsigned long>(blocks[i]) << (i * bits_per_block);
297 MSTL_NODISCARD
constexpr unsigned long long to_ullong() const noexcept {
298 MSTL_IF_CONSTEXPR (N >
sizeof(
unsigned long long) * 8) {
299 constexpr size_t ullong_blocks = (
sizeof(
unsigned long long) * 8 + bits_per_block - 1) / bits_per_block;
300 for (
size_t i = ullong_blocks; i < block_count; ++i) {
301 if (blocks[i] != 0) {
302 throw_exception(value_exception(
"bitset to_ullong overflow"));
306 constexpr size_t ullong_bits =
sizeof(
unsigned long long) * 8;
307 constexpr size_t remainder_bits = ullong_bits % bits_per_block;
308 MSTL_IF_CONSTEXPR (remainder_bits != 0) {
309 constexpr size_t last_ullong_block = ullong_bits / bits_per_block;
310 block_type mask = (~static_cast<block_type>(0ULL)) << remainder_bits;
311 if ((blocks[last_ullong_block] & mask) != 0) {
312 throw_exception(value_exception(
"bitset to_ullong overflow"));
317 MSTL_IF_CONSTEXPR (
sizeof(
unsigned long long) >=
sizeof(block_type)) {
318 return static_cast<unsigned long long>(blocks[0]);
320 unsigned long long result = 0;
321 constexpr size_t ullong_blocks = (
sizeof(
unsigned long long) * 8 + bits_per_block - 1) / bits_per_block;
322 constexpr size_t blocks_to_use = ullong_blocks < block_count ? ullong_blocks : block_count;
323 for (
size_t i = 0; i < blocks_to_use; ++i) {
324 result |=
static_cast<unsigned long long>(blocks[i]) << (i * bits_per_block);
330 MSTL_NODISCARD
constexpr bool operator ==(
const bitset& other)
const noexcept {
331 return blocks == other.blocks;
333 MSTL_NODISCARD
constexpr bool operator <(
const bitset& other)
const noexcept {
334 return blocks < other.blocks;
337 MSTL_NODISCARD
constexpr size_t to_hash() const noexcept {
338 return blocks.to_hash();
341 MSTL_NODISCARD MSTL_CONSTEXPR20
string to_string(
const char zero,
const char one)
const {
344 for (
size_t i = N; i > 0; --i) {
345 result.push_back(test(i - 1) ? one : zero);
350 MSTL_NODISCARD MSTL_CONSTEXPR20
string to_string()
const {
351 return this->to_string(
'0',
'1');
354 constexpr void swap(bitset& other)
noexcept {
355 blocks.swap(other.blocks);
358 bitset operator &(
const bitset& rhs) {
364 bitset operator |(
const bitset& rhs) {
370 bitset operator ^(
const bitset& rhs) {
constexpr int popcount(const uintptr_t x) noexcept
计算整数中1的个数
constexpr iter_difference_t< Iterator > count(Iterator first, Iterator last, const T &value)
统计范围内等于指定值的元素数量
#define _MSTL
全局命名空间MSTL前缀
#define MSTL_END_NAMESPACE__
结束全局命名空间MSTL
#define MSTL_BEGIN_NAMESPACE__
开始全局命名空间MSTL
MSTL_INLINE17 constexpr none_t none
默认空表示
void swap()=delete
删除无参数的swap重载
MSTL_NODISCARD MSTL_ALWAYS_INLINE constexpr bool empty(const Container &cont) noexcept(noexcept(cont.empty()))
检查容器是否为空
MSTL_NODISCARD MSTL_ALWAYS_INLINE constexpr decltype(auto) size(const Container &cont) noexcept(noexcept(cont.size()))
获取容器的大小
MSTL_NODISCARD constexpr size_t to_hash() const noexcept(noexcept(derived().to_hash()))