MSTL 1.4.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
bitset.hpp
1#ifndef MSTL_CORE_CONTAINER_BITSET_HPP__
2#define MSTL_CORE_CONTAINER_BITSET_HPP__
3#include "../memory/bit.hpp"
4#include "array.hpp"
6
7template <size_t N>
8class bitset : public icommon<bitset<N>>, public istringify<bitset<N>> {
9private:
10 using block_type = size_t;
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;
13
14 array<block_type, block_count> blocks{};
15
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;
20 }
21
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");
24 }
25
26 MSTL_ALWAYS_INLINE constexpr size_t block_index(const size_t pos) const noexcept {
27 return pos / bits_per_block;
28 }
29 MSTL_ALWAYS_INLINE constexpr size_t bit_index(const size_t pos) const noexcept {
30 return pos % bits_per_block;
31 }
32
33public:
34 constexpr bitset() noexcept {
35 blocks.fill(0);
36 }
37
38 constexpr explicit bitset(const block_type val) noexcept {
39 blocks.fill(0);
40 MSTL_IF_CONSTEXPR (block_count > 0) {
41 blocks[0] = val & last_block_mask();
42 }
43 }
44
45 constexpr explicit bitset(const string_view str,
46 const char zero = '0', const char one = '1') {
47 blocks.fill(0);
48 const size_t str_len = str.length();
49 const size_t M = (str_len < N) ? str_len : N;
50
51 for (size_t i = 0; i < M; ++i) {
52 const char c = str[i];
53 size_t pos = N - 1 - i;
54 if (c == one) {
55 set(pos);
56 } else if (c == zero) {
57 reset(pos);
58 } else {
59 throw_exception(value_exception("bitset string ctor: invalid character"));
60 }
61 }
62 }
63
64 constexpr explicit bitset(const string& str, const char zero = '0', const char one = '1')
65 : bitset(str.view(), zero, one) {}
66
67 constexpr explicit bitset(const char* str, const char zero = '0', const char one = '1')
68 : bitset(string_view{str}, zero, one) {}
69
70
71 constexpr bitset& set() noexcept {
72 for (auto& b : blocks) b = ~static_cast<block_type>(0ULL);
73 blocks[block_count - 1] &= last_block_mask();
74 return *this;
75 }
76
77 constexpr bitset& set(const size_t pos, const bool value = true) noexcept {
78 check_range(pos);
79 const size_t idx = block_index(pos);
80 const size_t bit = bit_index(pos);
81 if (value)
82 blocks[idx] |= (static_cast<block_type>(1) << bit);
83 else
84 blocks[idx] &= ~(static_cast<block_type>(1) << bit);
85 return *this;
86 }
87
88 constexpr bitset& reset() noexcept {
89 blocks.fill(0);
90 return *this;
91 }
92
93 constexpr bitset& reset(const size_t pos) noexcept {
94 check_range(pos);
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);
98 return *this;
99 }
100
101 constexpr bitset& flip() noexcept {
102 for (auto& b : blocks) {
103 b = ~b;
104 }
105 blocks[block_count - 1] &= last_block_mask();
106 return *this;
107 }
108
109 constexpr bitset& flip(const size_t pos) noexcept {
110 check_range(pos);
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);
114 return *this;
115 }
116
117
118 class reference {
119 private:
120 bitset& bs;
121 size_t pos;
122 public:
123 constexpr reference(bitset& b, const size_t p) noexcept
124 : bs(b), pos(p) {}
125
126 constexpr reference& operator =(const bool x) noexcept {
127 bs.set(pos, x);
128 return *this;
129 }
130 constexpr reference& operator =(const reference& x) noexcept {
131 return *this = static_cast<bool>(x);
132 }
133 constexpr operator bool() const noexcept {
134 return bs.test(pos);
135 }
136 constexpr reference& flip() noexcept {
137 bs.flip(pos);
138 return *this;
139 }
140 constexpr void flip() volatile noexcept = delete;
141 };
142
143 MSTL_NODISCARD constexpr bool operator [](const size_t pos) const noexcept {
144 return test(pos);
145 }
146 MSTL_NODISCARD constexpr reference operator [](size_t pos) noexcept {
147 check_range(pos);
148 return reference(*this, pos);
149 }
150
151 MSTL_NODISCARD constexpr size_t size() const noexcept { return N; }
152 MSTL_NODISCARD constexpr bool empty() const noexcept { return N == 0; }
153
154 MSTL_NODISCARD constexpr bool test(const size_t pos) const noexcept {
155 check_range(pos);
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;
159 }
160
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];
164 return *this;
165 }
166
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];
170 return *this;
171 }
172
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];
176 return *this;
177 }
178
179 MSTL_NODISCARD constexpr bitset operator ~() const noexcept {
180 bitset res = *this;
181 res.flip();
182 return res;
183 }
184
185 MSTL_NODISCARD constexpr bitset& operator <<=(const size_t pos) noexcept {
186 if (pos >= N) {
187 reset();
188 return *this;
189 }
190 const size_t block_shift = pos / bits_per_block;
191 const size_t bit_shift = pos % bits_per_block;
192
193 if (block_shift > 0) {
194 for (size_t i = block_count - 1; i >= block_shift; --i) {
195 blocks[i] = blocks[i - block_shift];
196 }
197 for (size_t i = 0; i < block_shift; ++i) {
198 blocks[i] = 0;
199 }
200 }
201 if (bit_shift > 0) {
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));
204 }
205 blocks[0] <<= bit_shift;
206 }
207 blocks[block_count - 1] &= last_block_mask();
208
209 return *this;
210 }
211
212 MSTL_NODISCARD constexpr bitset& operator >>=(const size_t pos) noexcept {
213 if (pos >= N) {
214 reset();
215 return *this;
216 }
217 const size_t block_shift = pos / bits_per_block;
218 const size_t bit_shift = pos % bits_per_block;
219
220 if (block_shift > 0) {
221 for (size_t i = 0; i < block_count - block_shift; ++i) {
222 blocks[i] = blocks[i + block_shift];
223 }
224 for (size_t i = block_count - block_shift; i < block_count; ++i) {
225 blocks[i] = 0;
226 }
227 }
228 if (bit_shift > 0) {
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));
231 }
232 blocks[block_count - 1] >>= bit_shift;
233 blocks[block_count - 1] &= last_block_mask();
234 }
235 return *this;
236 }
237
238 MSTL_NODISCARD constexpr size_t count() const noexcept {
239 size_t cnt = 0;
240 for (size_t i = 0; i < block_count; ++i) {
241 cnt += _MSTL popcount(blocks[i]);
242 }
243 return cnt;
244 }
245
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;
249 }
250 return blocks[block_count - 1] == last_block_mask();
251 }
252
253 MSTL_NODISCARD constexpr bool any() const noexcept {
254 for (auto b : blocks)
255 if (b != 0) return true;
256 return false;
257 }
258
259 MSTL_NODISCARD constexpr bool none() const noexcept {
260 return !any();
261 }
262
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"));
269 }
270 }
271
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"));
279 }
280 }
281 }
282
283 MSTL_IF_CONSTEXPR (sizeof(unsigned long) >= sizeof(block_type)) {
284 return static_cast<unsigned long>(blocks[0]);
285 } else {
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);
291 }
292 return result;
293 }
294 }
295
296
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"));
303 }
304 }
305
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"));
313 }
314 }
315 }
316
317 MSTL_IF_CONSTEXPR (sizeof(unsigned long long) >= sizeof(block_type)) {
318 return static_cast<unsigned long long>(blocks[0]);
319 } else {
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);
325 }
326 return result;
327 }
328 }
329
330 MSTL_NODISCARD constexpr bool operator ==(const bitset& other) const noexcept {
331 return blocks == other.blocks;
332 }
333 MSTL_NODISCARD constexpr bool operator <(const bitset& other) const noexcept {
334 return blocks < other.blocks;
335 }
336
337 MSTL_NODISCARD constexpr size_t to_hash() const noexcept {
338 return blocks.to_hash();
339 }
340
341 MSTL_NODISCARD MSTL_CONSTEXPR20 string to_string(const char zero, const char one) const {
342 string result;
343 result.reserve(N);
344 for (size_t i = N; i > 0; --i) {
345 result.push_back(test(i - 1) ? one : zero);
346 }
347 return result;
348 }
349
350 MSTL_NODISCARD MSTL_CONSTEXPR20 string to_string() const {
351 return this->to_string('0', '1');
352 }
353
354 constexpr void swap(bitset& other) noexcept {
355 blocks.swap(other.blocks);
356 }
357
358 bitset operator &(const bitset& rhs) {
359 bitset res = *this;
360 res &= rhs;
361 return res;
362 }
363
364 bitset operator |(const bitset& rhs) {
365 bitset res = *this;
366 res |= rhs;
367 return res;
368 }
369
370 bitset operator ^(const bitset& rhs) {
371 bitset res = *this;
372 res ^= rhs;
373 return res;
374 }
375};
376
378#endif // MSTL_CORE_CONTAINER_BITSET_HPP__
MSTL位操作函数
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
默认空表示
uint64_t size_t
无符号大小类型
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()))