NexusForce 1.0.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
bitset.hpp
浏览该文件的文档.
1#ifndef NEFORCE_CORE_CONTAINER_BITSET_HPP__
2#define NEFORCE_CORE_CONTAINER_BITSET_HPP__
3
12
16NEFORCE_BEGIN_NAMESPACE__
17
23
33template <size_t N>
34class bitset : public icommon<bitset<N>>, public ibinary<bitset<N>>, public istringify<bitset<N>> {
35public:
42 class reference {
43 private:
44 bitset& set_;
45 size_t position_;
46
47 public:
53 constexpr reference(bitset& set, const size_t position) noexcept :
54 set_(set),
55 position_(position) {}
56
62 constexpr reference& operator=(const bool value) noexcept {
63 set_.set(position_, value);
64 return *this;
65 }
66
72 constexpr reference& operator=(const reference& value) noexcept { return *this = static_cast<bool>(value); }
73
78 explicit constexpr operator bool() const noexcept { return set_.test(position_); }
79
84 constexpr reference& flip() noexcept {
85 set_.flip(position_);
86 return *this;
87 }
88 };
89
90private:
91 using block_type = size_t;
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;
94
96
97private:
98 static constexpr block_type last_block_mask() noexcept {
99 const size_t excess = block_count * bits_per_block - N;
100 if (excess == 0) {
101 return static_cast<block_type>(~0ULL);
102 }
103 return (static_cast<block_type>(1ULL) << (bits_per_block - excess)) - 1;
104 }
105
106 NEFORCE_ALWAYS_INLINE constexpr void check_range(const size_t pos) const noexcept {
107 NEFORCE_DEBUG_VERIFY(pos < N, "bitset position out of range");
108 }
109
110 NEFORCE_ALWAYS_INLINE constexpr size_t block_index(const size_t pos) const noexcept { return pos / bits_per_block; }
111
112 NEFORCE_ALWAYS_INLINE constexpr size_t bit_index(const size_t pos) const noexcept { return pos % bits_per_block; }
113
114public:
118 constexpr bitset() noexcept { blocks.fill(0); }
119
126 constexpr explicit bitset(const block_type value) noexcept {
127 blocks.fill(0);
128 NEFORCE_IF_CONSTEXPR(block_count > 0) { blocks[0] = value & last_block_mask(); }
129 }
130
141 constexpr explicit bitset(const string_view str, const char zero = '0', const char one = '1') {
142 blocks.fill(0);
143 const size_t str_len = str.length();
144 const size_t M = (str_len < N) ? str_len : N;
145
146 for (size_t i = 0; i < M; ++i) {
147 const char c = str[i];
148 size_t pos = N - 1 - i;
149 if (c == one) {
150 set(pos);
151 } else if (c == zero) {
152 reset(pos);
153 } else {
154 NEFORCE_THROW_EXCEPTION(value_exception("bitset string ctor: invalid character"));
155 }
156 }
157 }
158
165 constexpr explicit bitset(const string& str, const char zero = '0', const char one = '1') :
166 bitset(str.view(), zero, one) {}
167
174 constexpr explicit bitset(const char* str, const char zero = '0', const char one = '1') :
175 bitset(string_view{str}, zero, one) {}
176
181 constexpr bitset& set() noexcept {
182 for (auto& b: blocks) {
183 b = ~static_cast<block_type>(0ULL);
184 }
185 blocks[block_count - 1] &= last_block_mask();
186 return *this;
187 }
188
195 constexpr bitset& set(const size_t pos, const bool value = true) noexcept {
196 check_range(pos);
197 const size_t idx = block_index(pos);
198 const size_t bit = bit_index(pos);
199 if (value) {
200 blocks[idx] |= (static_cast<block_type>(1) << bit);
201 } else {
202 blocks[idx] &= ~(static_cast<block_type>(1) << bit);
203 }
204 return *this;
205 }
206
211 constexpr bitset& reset() noexcept {
212 blocks.fill(0);
213 return *this;
214 }
215
221 constexpr bitset& reset(const size_t pos) noexcept {
222 check_range(pos);
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);
226 return *this;
227 }
228
233 constexpr bitset& flip() noexcept {
234 for (auto& b: blocks) {
235 b = ~b;
236 }
237 blocks[block_count - 1] &= last_block_mask();
238 return *this;
239 }
240
246 constexpr bitset& flip(const size_t pos) noexcept {
247 check_range(pos);
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);
251 return *this;
252 }
253
259 NEFORCE_NODISCARD constexpr bool operator[](const size_t pos) const noexcept { return test(pos); }
260
266 NEFORCE_NODISCARD constexpr reference operator[](size_t pos) noexcept {
267 check_range(pos);
268 return reference(*this, pos);
269 }
270
275 NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE constexpr size_t size() const noexcept { return N; }
276
281 NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE constexpr bool empty() const noexcept { return N == 0; }
282
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;
293 }
294
300 NEFORCE_NODISCARD constexpr bitset& operator&=(const bitset& other) noexcept {
301 for (size_t i = 0; i < block_count; ++i) {
302 blocks[i] &= other.blocks[i];
303 }
304 return *this;
305 }
306
312 NEFORCE_NODISCARD constexpr bitset& operator|=(const bitset& other) noexcept {
313 for (size_t i = 0; i < block_count; ++i) {
314 blocks[i] |= other.blocks[i];
315 }
316 return *this;
317 }
318
324 NEFORCE_NODISCARD constexpr bitset& operator^=(const bitset& other) noexcept {
325 for (size_t i = 0; i < block_count; ++i) {
326 blocks[i] ^= other.blocks[i];
327 }
328 return *this;
329 }
330
335 NEFORCE_NODISCARD constexpr bitset operator~() const noexcept {
336 bitset res = *this;
337 res.flip();
338 return res;
339 }
340
346 NEFORCE_NODISCARD constexpr bitset& operator<<=(const uint32_t pos) noexcept {
347 if (pos >= N) {
348 reset();
349 return *this;
350 }
351 const size_t block_shift = pos / bits_per_block;
352 const size_t bit_shift = pos % bits_per_block;
353
354 if (block_shift > 0) {
355 for (size_t i = block_count - 1; i >= block_shift; --i) {
356 blocks[i] = blocks[i - block_shift];
357 }
358 for (size_t i = 0; i < block_shift; ++i) {
359 blocks[i] = 0;
360 }
361 }
362 if (bit_shift > 0) {
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));
365 }
366 blocks[0] <<= bit_shift;
367 }
368 blocks[block_count - 1] &= last_block_mask();
369
370 return *this;
371 }
372
378 NEFORCE_NODISCARD constexpr bitset& operator>>=(const uint32_t pos) noexcept {
379 if (pos >= N) {
380 reset();
381 return *this;
382 }
383 const size_t block_shift = pos / bits_per_block;
384 const size_t bit_shift = pos % bits_per_block;
385
386 if (block_shift > 0) {
387 for (size_t i = 0; i < block_count - block_shift; ++i) {
388 blocks[i] = blocks[i + block_shift];
389 }
390 for (size_t i = block_count - block_shift; i < block_count; ++i) {
391 blocks[i] = 0;
392 }
393 }
394 if (bit_shift > 0) {
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));
397 }
398 blocks[block_count - 1] >>= bit_shift;
399 blocks[block_count - 1] &= last_block_mask();
400 }
401 return *this;
402 }
403
408 NEFORCE_NODISCARD constexpr size_t count() const noexcept {
409 size_t cnt = 0;
410 for (size_t i = 0; i < block_count; ++i) {
411 cnt += _NEFORCE popcount(blocks[i]);
412 }
413 return cnt;
414 }
415
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)) {
423 return false;
424 }
425 }
426 return blocks[block_count - 1] == last_block_mask();
427 }
428
433 NEFORCE_NODISCARD constexpr bool any() const noexcept {
434 for (auto b: blocks) {
435 if (b != 0) {
436 return true;
437 }
438 }
439 return false;
440 }
441
446 NEFORCE_NODISCARD constexpr bool none() const noexcept { return !any(); }
447
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) {
458 NEFORCE_THROW_EXCEPTION(value_exception("bitset to_ulong overflow"));
459 }
460 }
461
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) {
468 NEFORCE_THROW_EXCEPTION(value_exception("bitset to_ulong overflow"));
469 }
470 }
471 }
472
473 NEFORCE_IF_CONSTEXPR(sizeof(unsigned long) >= sizeof(block_type)) {
474 return static_cast<unsigned long>(blocks[0]);
475 }
476 else {
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);
482 }
483 return result;
484 }
485 }
486
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) {
497 NEFORCE_THROW_EXCEPTION(value_exception("bitset to_ullong overflow"));
498 }
499 }
500
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) {
507 NEFORCE_THROW_EXCEPTION(value_exception("bitset to_ullong overflow"));
508 }
509 }
510 }
511
512 NEFORCE_IF_CONSTEXPR(sizeof(unsigned long long) >= sizeof(block_type)) {
513 return static_cast<unsigned long long>(blocks[0]);
514 }
515 else {
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);
521 }
522 return result;
523 }
524 }
525
531 NEFORCE_NODISCARD constexpr bool operator==(const bitset& other) const noexcept { return blocks == other.blocks; }
532
538 NEFORCE_NODISCARD constexpr bool operator<(const bitset& other) const noexcept { return blocks < other.blocks; }
539
544 NEFORCE_NODISCARD constexpr size_t to_hash() const noexcept { return blocks.to_hash(); }
545
552 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const char zero, const char one) const {
553 string result;
554 result.reserve(N);
555 for (size_t i = N; i > 0; --i) {
556 result.push_back(test(i - 1) ? one : zero);
557 }
558 return result;
559 }
560
565 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string() const { return bitset::to_string('0', '1'); }
566
571 constexpr void swap(bitset& other) noexcept { blocks.swap(other.blocks); }
572};
573 // BitManipulation
575
576NEFORCE_END_NAMESPACE__
577#endif // NEFORCE_CORE_CONTAINER_BITSET_HPP__
固定大小数组容器
位操作函数
固定大小数组容器
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)
调试模式断言
uint64_t size_t
无符号大小类型
basic_string_view< char > string_view
字符字符串视图
可字符串化接口
位运算接口基类
通用接口,同时具备可比较和可哈希功能
可字符串化接口
变量处理异常