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
17NEFORCE_BEGIN_NAMESPACE__
18
24
34template <size_t N>
35class bitset : public icomparable<bitset<N>>, public ibinary<bitset<N>>, public istringify<bitset<N>> {
36public:
43 class reference {
44 private:
45 bitset& set_;
46 size_t position_;
47
48 public:
54 constexpr reference(bitset& set, const size_t position) noexcept :
55 set_(set),
56 position_(position) {}
57
63 constexpr reference& operator=(const bool value) noexcept {
64 set_.set(position_, value);
65 return *this;
66 }
67
73 constexpr reference& operator=(const reference& value) noexcept { return *this = static_cast<bool>(value); }
74
79 explicit constexpr operator bool() const noexcept { return set_.test(position_); }
80
85 constexpr reference& flip() noexcept {
86 set_.flip(position_);
87 return *this;
88 }
89 };
90
91private:
92 using block_type = size_t;
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;
95
97
98private:
99 static constexpr block_type last_block_mask() noexcept {
100 if constexpr (block_count == 0) {
101 return 0;
102 }
103 const size_t excess = block_count * bits_per_block - N;
104 if (excess == 0) {
105 return static_cast<block_type>(~0ULL);
106 }
107 return static_cast<block_type>(~0ULL) >> excess;
108 }
109
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");
112 }
113
114 NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE constexpr size_t block_index(const size_t pos) const noexcept {
115 return pos / bits_per_block;
116 }
117
118 NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE constexpr size_t bit_index(const size_t pos) const noexcept {
119 return pos % bits_per_block;
120 }
121
122public:
126 constexpr bitset() noexcept { blocks.fill(0); }
127
134 constexpr explicit bitset(unsigned long long value) noexcept {
135 blocks.fill(0);
136 static_assert(sizeof(unsigned long long) >= sizeof(block_type),
137 "unsigned long long should be at least as large as block_type");
138 size_t i = 0;
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);
143 }
144 else {
145 value = 0;
146 }
147 ++i;
148 }
149 NEFORCE_IF_CONSTEXPR(block_count > 0) { blocks[block_count - 1] &= last_block_mask(); }
150 }
151
162 constexpr explicit bitset(const string_view str, const char zero = '0', const char one = '1') {
163 blocks.fill(0);
164 const size_t str_len = str.length();
165 const size_t M = (str_len < N) ? str_len : N;
166
167 for (size_t i = 0; i < M; ++i) {
168 const char c = str[i];
169 size_t pos = M - 1 - i;
170 if (c == one) {
171 set(pos);
172 } else if (c == zero) {
173 reset(pos);
174 } else {
175 NEFORCE_THROW_EXCEPTION(value_exception("bitset string ctor: invalid character"));
176 }
177 }
178 }
179
186 constexpr explicit bitset(const string& str, const char zero = '0', const char one = '1') :
187 bitset(str.view(), zero, one) {}
188
195 constexpr explicit bitset(const char* str, const char zero = '0', const char one = '1') :
196 bitset(string_view{str}, zero, one) {}
197
202 constexpr bitset& set() noexcept {
203 for (auto& b: blocks) {
204 b = ~static_cast<block_type>(0ULL);
205 }
206 NEFORCE_IF_CONSTEXPR(N > 0) { blocks[block_count - 1] &= last_block_mask(); }
207 return *this;
208 }
209
216 constexpr bitset& set(const size_t pos, const bool value = true) noexcept {
217 check_range(pos);
218 const size_t idx = block_index(pos);
219 const size_t bit = bit_index(pos);
220 if (value) {
221 blocks[idx] |= (static_cast<block_type>(1) << bit);
222 } else {
223 blocks[idx] &= ~(static_cast<block_type>(1) << bit);
224 }
225 return *this;
226 }
227
232 constexpr bitset& reset() noexcept {
233 blocks.fill(0);
234 return *this;
235 }
236
242 constexpr bitset& reset(const size_t pos) noexcept {
243 check_range(pos);
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);
247 return *this;
248 }
249
254 constexpr bitset& flip() noexcept {
255 for (auto& b: blocks) {
256 b = ~b;
257 }
258 blocks[block_count - 1] &= last_block_mask();
259 return *this;
260 }
261
267 constexpr bitset& flip(const size_t pos) noexcept {
268 check_range(pos);
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);
272 return *this;
273 }
274
280 NEFORCE_NODISCARD constexpr bool operator[](const size_t pos) const noexcept { return test(pos); }
281
287 NEFORCE_NODISCARD constexpr reference operator[](size_t pos) noexcept {
288 check_range(pos);
289 return reference(*this, pos);
290 }
291
296 NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE constexpr size_t size() const noexcept { return N; }
297
302 NEFORCE_NODISCARD NEFORCE_ALWAYS_INLINE constexpr bool empty() const noexcept { return N == 0; }
303
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;
314 }
315
321 constexpr bitset& operator&=(const bitset& other) noexcept {
322 for (size_t i = 0; i < block_count; ++i) {
323 blocks[i] &= other.blocks[i];
324 }
325 return *this;
326 }
327
333 constexpr bitset& operator|=(const bitset& other) noexcept {
334 for (size_t i = 0; i < block_count; ++i) {
335 blocks[i] |= other.blocks[i];
336 }
337 return *this;
338 }
339
345 constexpr bitset& operator^=(const bitset& other) noexcept {
346 for (size_t i = 0; i < block_count; ++i) {
347 blocks[i] ^= other.blocks[i];
348 }
349 return *this;
350 }
351
356 NEFORCE_NODISCARD constexpr bitset operator~() const noexcept {
357 bitset res = *this;
358 res.flip();
359 return res;
360 }
361
367 constexpr bitset& operator<<=(const uint32_t pos) noexcept {
368 if (pos >= N) {
369 reset();
370 return *this;
371 }
372 const size_t block_shift = pos / bits_per_block;
373 const size_t bit_shift = pos % bits_per_block;
374
375 if (block_shift > 0) {
376 for (size_t i = block_count - 1; i >= block_shift; --i) {
377 blocks[i] = blocks[i - block_shift];
378 }
379 for (size_t i = 0; i < block_shift; ++i) {
380 blocks[i] = 0;
381 }
382 }
383 if (bit_shift > 0) {
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));
386 }
387 blocks[0] <<= bit_shift;
388 }
389 blocks[block_count - 1] &= last_block_mask();
390
391 return *this;
392 }
393
399 constexpr bitset& operator>>=(const uint32_t pos) noexcept {
400 if (pos >= N) {
401 reset();
402 return *this;
403 }
404 const size_t block_shift = pos / bits_per_block;
405 const size_t bit_shift = pos % bits_per_block;
406
407 if (block_shift > 0) {
408 for (size_t i = 0; i < block_count - block_shift; ++i) {
409 blocks[i] = blocks[i + block_shift];
410 }
411 for (size_t i = block_count - block_shift; i < block_count; ++i) {
412 blocks[i] = 0;
413 }
414 }
415 if (bit_shift > 0) {
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));
418 }
419 blocks[block_count - 1] >>= bit_shift;
420 blocks[block_count - 1] &= last_block_mask();
421 }
422 return *this;
423 }
424
429 NEFORCE_NODISCARD constexpr size_t count() const noexcept {
430 size_t cnt = 0;
431 for (size_t i = 0; i < block_count; ++i) {
432 cnt += _NEFORCE popcount(blocks[i]);
433 }
434 return cnt;
435 }
436
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)) {
445 return false;
446 }
447 }
448 return blocks[block_count - 1] == last_block_mask();
449 }
450
455 NEFORCE_NODISCARD constexpr bool any() const noexcept {
456 for (auto b: blocks) {
457 if (b != 0) {
458 return true;
459 }
460 }
461 return false;
462 }
463
468 NEFORCE_NODISCARD constexpr bool none() const noexcept { return !any(); }
469
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) {
480 NEFORCE_THROW_EXCEPTION(value_exception("bitset to_ulong overflow"));
481 }
482 }
483
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) {
490 NEFORCE_THROW_EXCEPTION(value_exception("bitset to_ulong overflow"));
491 }
492 }
493 }
494
495 NEFORCE_IF_CONSTEXPR(sizeof(unsigned long) >= sizeof(block_type)) {
496 return static_cast<unsigned long>(blocks[0]);
497 }
498 else {
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);
504 }
505 return result;
506 }
507 }
508
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) {
519 NEFORCE_THROW_EXCEPTION(value_exception("bitset to_ullong overflow"));
520 }
521 }
522
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) {
529 NEFORCE_THROW_EXCEPTION(value_exception("bitset to_ullong overflow"));
530 }
531 }
532 }
533
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);
540 }
541 return result;
542 }
543
549 NEFORCE_NODISCARD constexpr bool equal_to(const bitset& other) const noexcept { return blocks == other.blocks; }
550
556 NEFORCE_NODISCARD constexpr bool less_than(const bitset& other) const noexcept { return blocks < other.blocks; }
557
564 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string(const char zero, const char one) const {
565 string result;
566 result.reserve(N);
567 for (size_t i = N; i > 0; --i) {
568 result.push_back(test(i - 1) ? one : zero);
569 }
570 return result;
571 }
572
577 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string() const { return bitset::to_string('0', '1'); }
578
583 constexpr void swap(bitset& other) noexcept { blocks.swap(other.blocks); }
584};
585 // BitManipulation
587
588NEFORCE_END_NAMESPACE__
589#endif // NEFORCE_CORE_CONTAINER_BITSET_HPP__
固定大小数组容器
位操作函数
固定大小数组容器
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位无符号整数类型
uint64_t size_t
无符号大小类型
basic_string_view< char > string_view
字符字符串视图
数值操作接口
可字符串化接口
位运算接口基类
可比较对象接口模板
可字符串化接口
变量处理异常