Grindstone Game Engine v0.2.0
An open source game engine and toolkit.
Loading...
Searching...
No Matches
Bitset.hpp
1#pragma once
2
3#include <limits.h>
4
5#include "../EnumTraits.hpp"
6#include "../Assert.hpp"
7
8namespace Grindstone::Containers {
9 static uint32_t Popcount(uint32_t n) {
10 // https://nimrod.blog/posts/algorithms-behind-popcount/
11 n = (n & 0x55555555) + ((n >> 1) & 0x55555555);
12 n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
13 n = (n & 0x0F0F0F0F) + ((n >> 4) & 0x0F0F0F0F);
14 n = (n & 0x00FF00FF) + ((n >> 8) & 0x00FF00FF);
15 n = (n & 0x0000FFFF) + ((n >> 16) & 0x0000FFFF);
16 return n;
17 }
18
19 template<uint32_t bitCount, typename WordType = uint32_t>
20 class Bitset {
21 public:
22 static constexpr uint32_t bitsPerWord = (CHAR_BIT * sizeof(WordType));
23 static constexpr uint32_t wordCount = ((bitCount + bitsPerWord - 1) / bitsPerWord);
24 static constexpr uint32_t totalBitCount = wordCount * bitsPerWord;
25 static constexpr uint32_t lastWordbitCount = bitCount % bitsPerWord;
26 static constexpr uint32_t lastWordMask = (lastWordbitCount == 0)
27 ? ~0
28 : ((1 << lastWordbitCount) - 1);
29
30 Bitset() {
31 for (size_t i = 0; i < wordCount; ++i) {
32 contents[i] = 0;
33 }
34 }
35
36 Bitset(const Bitset& other) {
37 for (size_t i = 0; i < wordCount; ++i) {
38 contents[i] = other.contents[i];
39 }
40 }
41
42 Bitset(Bitset&& other) noexcept {
43 for (size_t i = 0; i < wordCount; ++i) {
44 contents[i] = other.contents[i];
45 }
46 }
47
48 Bitset& operator=(const Bitset& other) {
49 for (size_t i = 0; i < wordCount; ++i) {
50 contents[i] = other.contents[i];
51 }
52 return *this;
53 }
54
55 Bitset& operator=(Bitset&& other) {
56 for (size_t i = 0; i < wordCount; ++i) {
57 contents[i] = other.contents[i];
58 }
59 return *this;
60 }
61
62 void Set() {
63 for (WordType& w : contents) {
64 w = WordType(~0);
65 }
66
67 // Clear unused bits of last mask, which will now be 1.
68 contents[wordCount - 1] &= lastWordMask;
69 }
70
71 void Set(uint32_t bitIndex, bool value = true) {
72 size_t wordIndex = bitIndex / bitsPerWord;
73 size_t bitInWord = bitIndex % bitsPerWord;
74
75 if (value) {
76 contents[wordIndex] |= (1 << bitInWord);
77 }
78 else {
79 contents[wordIndex] &= ~(1 << bitInWord);
80 }
81 }
82
83 void Unset() {
84 for (WordType& w : contents) {
85 w = 0;
86 }
87 }
88
89 void Unset(uint32_t index) {
90 contents[index / bitsPerWord] &= ~(1 << (index % bitsPerWord));
91 }
92
93 void Flip() {
94 for (WordType& w : contents) {
95 w = ~w;
96 }
97
98 // Clear unused bits of last mask, which will now be 1.
99 contents[wordCount - 1] &= lastWordMask;
100 }
101
102 void Flip(uint32_t index) {
103 contents[index / bitsPerWord] ^= (1 << (index % bitsPerWord));
104 }
105
106 bool Test(uint32_t index) const {
107 return (contents[index / bitsPerWord] >> (index % bitsPerWord)) & 1;
108 }
109
110 WordType GetWord(uint32_t index) const {
111 return contents[index];
112 }
113
114 bool All() const {
115 for (size_t i = 0; i < wordCount - 1; ++i) {
116 if (contents[i] != WordType(~0)) {
117 return true;
118 }
119 }
120
121 return false;
122 }
123
124 bool Any() const {
125 for (WordType w : contents) {
126 if (w != 0) {
127 return true;
128 }
129 }
130
131 return false;
132 }
133
134 bool None() const {
135 for (WordType w : contents) {
136 if (w != 0) {
137 return false;
138 }
139 }
140
141 return true;
142 }
143
144 constexpr uint32_t GetTrueBitCount() const {
145 uint32_t total = 0;
146 for (uint32_t w : contents) {
147 total += Popcount(w);
148 }
149
150 return total;
151 }
152
153 constexpr uint32_t GetFalseBitCount() const {
154 return bitCount - GetTrueBitCount();
155 }
156
157 static constexpr uint32_t GetBitCount() {
158 return bitCount;
159 }
160
161 static constexpr uint32_t GetBitCapacity() {
162 return totalBitCount;
163 }
164
165 static constexpr uint32_t GetWordCount() {
166 return wordCount;
167 }
168
169 Bitset operator&=(const Bitset& other) const {
170 for (size_t i = 0; i < wordCount; ++i) {
171 contents[i] &= other.contents[i];
172 }
173
174 return *this;
175 }
176
177 Bitset operator|=(const Bitset& other) const {
178 for (size_t i = 0; i < wordCount; ++i) {
179 contents[i] |= other.contents[i];
180 }
181
182 return *this;
183 }
184
185 Bitset operator^=(const Bitset& other) const {
186 for (size_t i = 0; i < wordCount; ++i) {
187 contents[i] ^= other.contents[i];
188 }
189
190 return *this;
191 }
192
193 Bitset operator&(const Bitset& other) const {
194 Bitset result;
195 for (size_t i = 0; i < wordCount; ++i) {
196 result.contents[i] = contents[i] & other.contents[i];
197 }
198
199 return result;
200 }
201
202 Bitset operator|(const Bitset& other) const {
203 Bitset result;
204 for (size_t i = 0; i < wordCount; ++i) {
205 result.contents[i] = contents[i] | other.contents[i];
206 }
207
208 return result;
209 }
210
211 Bitset operator^(const Bitset& other) const {
212 Bitset result;
213 for (size_t i = 0; i < wordCount; ++i) {
214 result.contents[i] = contents[i] ^ other.contents[i];
215 }
216
217 return result;
218 }
219
220 friend Bitset operator~(const Bitset& obj) {
221 Bitset result = obj;
222 result.Flip();
223 return result;
224 }
225
226 bool operator[](uint32_t index) const {
227 return (contents[index / bitsPerWord] >> index % bitsPerWord) & 1;
228 }
229
230 bool operator==(const Bitset& other) const {
231 for (size_t i = 0; i < wordCount; ++i) {
232 if (contents[i] != other.contents[i]) {
233 return false;
234 }
235 }
236
237 return true;
238 }
239
240 bool operator!=(const Bitset& other) const {
241 return *this != other;
242 }
243
244 protected:
245 WordType contents[wordCount];
246 };
247
248 // NOTE: Requires Enum to have an entry called Count with the total number of options.
249 template <typename Enum>
250 class BitsetEnum : public Bitset<static_cast<std::underlying_type_t<Enum>>(Enum::Count), std::underlying_type_t<Enum>> {
251 public:
252 using UnderlyingType = std::underlying_type_t<Enum>;
253 using Traits = EnumTraits<Enum>;
254 static_assert(std::is_enum_v<Enum>, "BitsetFlags requires an enum type");
255
256 static constexpr uint32_t enumBitCount = Traits::size;
257 using Base = Bitset<static_cast<UnderlyingType>(Enum::Count), UnderlyingType>;
258 using Base::Base;
259
260 using Base::wordCount;
261 using Base::bitsPerWord;
262 using Base::totalBitCount;
263 using Base::lastWordbitCount;
264 using Base::lastWordMask;
265 using Base::Set;
266 using Base::Unset;
267 using Base::Flip;
268 using Base::Test;
269 using Base::GetWord;
270 using Base::All;
271 using Base::Any;
272 using Base::None;
273 using Base::GetTrueBitCount;
274 using Base::GetFalseBitCount;
275 using Base::GetBitCount;
276 using Base::GetBitCapacity;
277 using Base::GetWordCount;
278 using Base::operator&=;
279 using Base::operator|=;
280 using Base::operator^=;
281 using Base::operator&;
282 using Base::operator|;
283 using Base::operator^;
284 using Base::operator[];
285 using Base::operator==;
286 using Base::operator!=;
287
288 void Set(Enum e, bool value = true) {
289 Base::Set(static_cast<UnderlyingType>(e), value);
290 }
291
292 void Unset(Enum e) {
293 Base::Unset(static_cast<UnderlyingType>(e));
294 }
295
296 void Flip(Enum e) {
297 Base::Flip(static_cast<UnderlyingType>(e));
298 }
299
300 bool Test(Enum e) const {
301 return Base::Test(static_cast<UnderlyingType>(e));
302 }
303
304 bool operator[](Enum e) const {
305 return Test(static_cast<UnderlyingType>(e));
306 }
307
308 static constexpr const char* GetEntryName(uint32_t index) {
309 return Traits::names[index];
310 }
311
312 static constexpr const char* GetEntryName(Enum e) {
313 uint32_t index = static_cast<uint32_t>(e);
314 return Traits::names[index];
315 }
316
317 struct Iterator {
318 UnderlyingType i = 0;
319 const BitsetEnum* bitset;
320
321 bool operator!=(const Iterator& other) const { return i != other.i; }
322 void operator++() { ++i; }
323 Enum operator*() const { return static_cast<Enum>(i); }
324 };
325
326 Iterator begin() const { return { 0, this }; }
327 Iterator end() const { return { Traits::size, this }; }
328 };
329
330 template<typename Enum>
331 class BitsetFlags {
332 public:
333 using UnderlyingType = std::underlying_type_t<Enum>;
334 using Traits = EnumFlagsTraits<Enum>;
335 static constexpr uint32_t bitsPerWord = (CHAR_BIT * sizeof(UnderlyingType));
336 static constexpr uint32_t enumBitCount = Traits::size;
337 static_assert(std::is_enum_v<Enum>, "BitsetFlags requires an enum type");
338
339 BitsetFlags() = default;
340 BitsetFlags(const BitsetFlags&) = default;
341 BitsetFlags(BitsetFlags&&) = default;
342 BitsetFlags(Enum enumValue) : value(static_cast<UnderlingType>(enumValue)) {}
343
344 BitsetFlags& operator=(const BitsetFlags& other) {
345 value = other.value;
346 return *this;
347 }
348
349 BitsetFlags& operator=(BitsetFlags&& other) {
350 value = other.value;
351 return *this;
352 }
353
354 BitsetFlags& operator=(Enum enumValue) {
355 value = static_cast<UnderlyingType>(enumValue);
356 return *this;
357 }
358
359 void Set() {
360 value = ~UnderlyingType(0);
361 }
362
363 void Set(uint32_t bitIndex) {
364 value |= (1 << bitIndex);
365 }
366
367 void Set(Enum e) {
368 value |= static_cast<UnderlyingType>(e);
369 }
370
371 void Set(uint32_t bitIndex, bool shouldSet) {
372 if (shouldSet) {
373 value |= (1 << bitIndex);
374 }
375 else {
376 value &= ~(1 << bitIndex);
377 }
378 }
379
380 void Set(Enum e, bool shouldSet) {
381 if (shouldSet) {
382 value |= static_cast<UnderlyingType>(e);
383 }
384 else {
385 value &= ~static_cast<UnderlyingType>(e);
386 }
387 }
388
389 void Unset() {
390 value = 0;
391 }
392
393 void Unset(uint32_t index) {
394 value &= ~(1 << index);
395 }
396
397 void Unset(Enum e) {
398 value &= ~static_cast<UnderlyingType>(e);
399 }
400
401 void Flip() {
402 value = ~value;
403 }
404
405 void Flip(uint32_t index) {
406 value ^= (1 << index);
407 }
408
409 void Flip(Enum e) {
410 value ^= static_cast<UnderlyingType>(e);
411 }
412
413 bool Test(uint32_t index) const {
414 return (value >> index) & 1;
415 }
416
417 bool Test(Enum e) const {
418 return value & static_cast<UnderlyingType>(e);
419 }
420
421 static constexpr uint32_t GetBitCount() {
422 return Traits::size;
423 }
424
425 static constexpr const char* GetFlagNameByIndex(uint32_t index) {
426 return Traits::names[index];
427 }
428
429 static constexpr const char* GetFlagName(Enum e) {
430 uint32_t index = static_cast<uint32_t>(std::log2(static_cast<uint32_t>(e)));
431 return Traits::names[index];
432 }
433
434 Enum GetValueEnum() const {
435 return static_cast<Enum>(value);
436 }
437
438 UnderlyingType GetValueUnderlying() const {
439 return value;
440 }
441
442 bool Any() const {
443 return value;
444 }
445
446 bool None() const {
447 return value == 0;
448 }
449
450 BitsetFlags& operator&=(const BitsetFlags& other) const {
451 value &= other.value;
452 return *this;
453 }
454
455 BitsetFlags& operator|=(const BitsetFlags& other) const {
456 value |= other.value;
457 return *this;
458 }
459
460 BitsetFlags& operator^=(const BitsetFlags& other) const {
461 value ^= other.value;
462 return *this;
463 }
464
465 BitsetFlags operator&(const BitsetFlags& other) const {
466 return value & other.value;
467 }
468
469 BitsetFlags operator|(const BitsetFlags& other) const {
470 return value | other.value;
471 }
472
473 BitsetFlags operator^(const BitsetFlags& other) const {
474 return value ^ other.value;
475 }
476
477 BitsetFlags operator~() const {
478 return ~value;
479 }
480
481 bool operator[](uint32_t index) const {
482 return (value >> index) & 1;
483 }
484
485 bool operator[](Enum e) const {
486 return value & static_cast<UnderlyingType>(e);
487 }
488
489 bool operator==(const BitsetFlags& other) const {
490 return value == other.value;
491 }
492
493 bool operator!=(const BitsetFlags& other) const {
494 return value != other.value;
495 }
496
497 struct Iterator {
498 size_t i = 0;
499 const BitsetFlags* bitset;
500
501 bool operator!=(const Iterator& other) const { return i != other.i; }
502 void operator++() { ++i; }
503 Enum operator*() const { return static_cast<Enum>(i); }
504 };
505
506 Iterator begin() const { return { 0, this }; }
507 Iterator end() const { return { EnumTraits<Enum>::size, this }; }
508
509 protected:
510 UnderlyingType value = 0;
511 };
512}
513
514template<uint32_t bitCount, typename WordType = uint32_t>
515std::ostream& operator<< (std::ostream& stream, const Grindstone::Containers::Bitset<bitCount, WordType>& x) {
516 for (uint32_t i = bitCount; i > 0; --i) {
517 stream << (x.Test(i - 1) ? '1' : '0');
518 }
519
520 return stream;
521}
522
523template<uint32_t bitCount, typename WordType = uint32_t>
524std::istream& operator>>(std::istream& stream, Grindstone::Containers::Bitset<bitCount, WordType>& x) {
525 std::string str;
526 stream >> str;
527
528 if (str.size() > bitCount) {
529 stream.setstate(std::ios::failbit);
530 return stream;
531 }
532
533 x.Unset();
534
535 uint32_t offset = bitCount - static_cast<uint32_t>(str.size());
536 for (uint32_t i = 0; i < str.size(); ++i) {
537 char c = str[i];
538 if (c == '1') {
539 x.Set(offset + i);
540 }
541 else if (c != '0') {
542 stream.setstate(std::ios::failbit);
543 return stream;
544 }
545 }
546
547 return stream;
548}
549
550template<typename Enum>
551std::ostream& operator<< (std::ostream& stream, const Grindstone::Containers::BitsetEnum<Enum>& x) {
552 for (uint32_t i = x.GetBitCount(); i > 0; --i) {
553 stream << (x.Test(i - 1) ? '1' : '0');
554 }
555
556 return stream;
557}
558
559template<typename Enum>
560std::istream& operator>>(std::istream& stream, Grindstone::Containers::BitsetEnum<Enum>& x) {
561 std::string str;
562 stream >> str;
563
564 if (str.size() > x.GetBitCount()) {
565 stream.setstate(std::ios::failbit);
566 return stream;
567 }
568
569 x.Unset();
570
571 uint32_t offset = x.GetBitCount() - static_cast<uint32_t>(str.size());
572 for (uint32_t i = 0; i < str.size(); ++i) {
573 char c = str[i];
574 if (c == '1') {
575 x.Set(offset + i);
576 }
577 else if (c != '0') {
578 stream.setstate(std::ios::failbit);
579 return stream;
580 }
581 }
582
583 return stream;
584}
585
586template<typename Enum>
587std::ostream& operator<< (std::ostream& stream, const Grindstone::Containers::BitsetFlags<Enum>& x) {
588 for (uint32_t i = x.GetBitCount(); i > 0; --i) {
589 stream << (x.Test(i - 1) ? '1' : '0');
590 }
591
592 return stream;
593}
594
595template<typename Enum>
596std::istream& operator>>(std::istream& stream, Grindstone::Containers::BitsetFlags<Enum>& x) {
597 std::string str;
598 stream >> str;
599
600 if (str.size() > x.GetBitCount()) {
601 stream.setstate(std::ios::failbit);
602 return stream;
603 }
604
605 x.Unset();
606
607 uint32_t offset = x.GetBitCount() - static_cast<uint32_t>(str.size());
608 for (uint32_t i = 0; i < str.size(); ++i) {
609 char c = str[i];
610 if (c == '1') {
611 x.Set(offset + i);
612 }
613 else if (c != '0') {
614 stream.setstate(std::ios::failbit);
615 return stream;
616 }
617 }
618
619 return stream;
620}
Definition Bitset.hpp:250
Definition Bitset.hpp:331
Definition Bitset.hpp:20
Definition EnumTraits.hpp:10
Definition EnumTraits.hpp:4