ECSTASY
All in the name
Loading...
Searching...
No Matches
BitSet.hpp
Go to the documentation of this file.
1
11
12#ifndef UTIL_BITSET_HPP_
13#define UTIL_BITSET_HPP_
14
15#include <bit>
16#include <cstddef>
17#include <cstdint>
18#include <ostream>
19#include <vector>
20#include <string_view>
21
22// As of 2022, C++20 is still considered "experimental" by G++, `constexpr` for std::vector was only added in G++ 12.1.
23// So we need to disable `constexpr` on most BitSet functions in G++ versions below 12.1.
24//
25// For G++ 12.1 and above, em++, and MSVC, constexpr support is enabled.
26#if !defined(__clang__) && defined(__GNUG__) && (__GNUG__ < 12 || __GNUC_MINOR__ < 1)
27 #define BIT_SET_CONSTEXPR inline
28#else
29 #define BIT_SET_CONSTEXPR constexpr
30#endif // !defined(__clang__) && defined(__GNUG__) && (__GNUG__ < 12 || __GNUC_MINOR__ < 1)
31
32namespace util
33{
35 class BitSet {
36 public:
37 class Reference {
38 public:
41 {
42 this->_set.set(this->_pos, value);
43 return *this;
44 }
45
47 BIT_SET_CONSTEXPR operator bool() const noexcept
48 {
49 return const_cast<BitSet const &>(this->_set)[this->_pos];
50 }
51
53 BIT_SET_CONSTEXPR bool operator~() const noexcept
54 {
55 return !bool(*this);
56 }
57
60 {
61 *this = ~(*this);
62 return *this;
63 }
64
65 private:
68
69 constexpr Reference(BitSet &set, std::size_t pos) : _set(set), _pos(pos)
70 {
71 }
72
73 friend BitSet;
74 };
75
77 BitSet(std::size_t initialSize = 0);
78
84 BitSet(std::string_view bitString);
85
87 [[nodiscard]] constexpr std::size_t size() const noexcept
88 {
89 return this->_size;
90 }
91
95 [[nodiscard]] BIT_SET_CONSTEXPR bool test(std::size_t pos) const noexcept
96 {
97 return (this->_store[pos >> 6] & mask(pos)) != 0;
98 }
99
103 [[nodiscard]] BIT_SET_CONSTEXPR bool operator[](std::size_t pos) const noexcept
104 {
105 return this->test(pos);
106 }
107
111 BIT_SET_CONSTEXPR BitSet &set(std::size_t pos, bool value = true) noexcept
112 {
113 if (value)
114 this->_store[pos >> 6] |= mask(pos);
115 else
116 this->_store[pos >> 6] &= ~mask(pos);
117 return *this;
118 }
119
121 BitSet &setAll(bool value = true) noexcept;
122
126 constexpr Reference operator[](std::size_t pos) noexcept
127 {
128 return Reference(*this, pos);
129 }
130
132 [[nodiscard]] bool operator==(BitSet const &other) const noexcept;
133
135 [[nodiscard]] bool operator!=(BitSet const &other) const noexcept;
136
140 BitSet &flip() noexcept;
141
143 BitSet operator~() const;
144
148 BitSet operator&(BitSet const &other) const;
149
153 BitSet operator|(BitSet const &other) const;
154
158 BitSet operator^(BitSet const &other) const;
159
163 BitSet &operator&=(BitSet const &other) noexcept;
164
168 BitSet &operator|=(BitSet const &other) noexcept;
169
173 BitSet &operator^=(BitSet const &other) noexcept;
174
180 BitSet &inplaceAnd(BitSet const &other) noexcept;
181
187 BitSet &inplaceOr(BitSet const &other) noexcept;
188
194 BitSet &inplaceXor(BitSet const &other) noexcept;
195
199 inline void resize(std::size_t size)
200 {
201 this->_resize(size);
202 this->normalize();
203 }
204
210 void resizeSentinel(std::size_t size, bool sentinelValue);
211
213 BitSet &push(bool value);
214
220 bool pop();
221
229 [[nodiscard]] BIT_SET_CONSTEXPR std::size_t firstSet(std::size_t start = 0) const
230 {
231 std::uint64_t mask = (~std::uint64_t(0)) << (start & 0b111111);
232 std::size_t word_pos = start >> 6;
233 std::uint64_t word = this->_store[word_pos] & mask;
234
235 while (word == 0) {
236 ++word_pos;
237 word = this->_store[word_pos];
238 }
239 return (word_pos << 6) + static_cast<std::size_t>(std::countr_zero(word));
240 }
241
248 {
249 std::uint64_t mask = ~((~std::uint64_t(0)) << (_size & 0b111111));
250 std::size_t word_pos = _size >> 6;
251 std::uint64_t word = this->_store[word_pos] & mask;
252
253 while (word == 0) {
254 // Avoid underflow
255 if (word_pos == 0)
256 break;
257 --word_pos;
258 word = this->_store[word_pos];
259 }
260 if (word == 0)
261 return 0;
262 return (word_pos << 6) + static_cast<std::size_t>(0b111111 - std::countl_zero(word));
263 }
264
273 {
274 std::uint64_t mask = (~std::uint64_t(0)) << (start & 0b111111);
275 std::size_t word_pos = start >> 6;
276 std::uint64_t word = this->_store[word_pos] | (~mask);
277
278 while (word == (~std::uint64_t(0))) {
279 ++word_pos;
280 word = this->_store[word_pos];
281 }
282 return (word_pos << 6) + static_cast<std::size_t>(std::countr_one(word));
283 }
284
291 {
292 std::uint64_t mask = ~((~std::uint64_t(0)) << (_size & 0b111111));
293 std::size_t word_pos = _size >> 6;
294 std::uint64_t word = this->_store[word_pos] | (~mask);
295
296 while (word == (~std::uint64_t(0))) {
297 // Avoid underflow
298 if (word_pos == 0)
299 break;
300 --word_pos;
301 word = this->_store[word_pos];
302 }
303 if (word == (~std::uint64_t(0)))
304 return 0;
305 return (word_pos << 6) + static_cast<std::size_t>(0b111111 - std::countl_one(word));
306 }
307
308 private:
311
313 static constexpr std::uint64_t mask(std::size_t pos)
314 {
315 return std::uint64_t(1) << (pos & 0b111111);
316 }
317
319 static constexpr std::size_t getStoreWordCount(std::size_t bitCount)
320 {
321 if ((bitCount & (~static_cast<std::size_t>(0b111111))) == bitCount)
322 return bitCount >> 6; // if bitCount is a multiple of 64, return bitCount / 64
323 else
324 return (bitCount >> 6) + 1; // or else, add one word to contain the extra bits
325 }
326
328 void normalize() noexcept;
329
331 void _resize(std::size_t size);
332
333 friend Reference;
335 friend class BitSetTester;
336 };
337
339 std::ostream &operator<<(std::ostream &output, BitSet const &set);
340} // namespace util
341
342#endif // !defined(UTIL_BITSET_HPP_)
#define BIT_SET_CONSTEXPR
Definition BitSet.hpp:29
BIT_SET_CONSTEXPR Reference & operator=(bool value) noexcept
Assigns a value to the refenced bit.
Definition BitSet.hpp:40
constexpr Reference(BitSet &set, std::size_t pos)
Definition BitSet.hpp:69
BIT_SET_CONSTEXPR Reference & flip() noexcept
Inverts the referenced bit.
Definition BitSet.hpp:59
BIT_SET_CONSTEXPR bool operator~() const noexcept
Definition BitSet.hpp:53
Mimics the API of std::bitset but with the dynamic properties of std::vector<bool>
Definition BitSet.hpp:35
BIT_SET_CONSTEXPR std::size_t firstUnset(std::size_t start=0) const
Finds the first unset bit in the set, starting from (and including) start.
Definition BitSet.hpp:272
static constexpr std::size_t getStoreWordCount(std::size_t bitCount)
Definition BitSet.hpp:319
void resize(std::size_t size)
Changes the number of bits stored in this set.
Definition BitSet.hpp:199
BitSet & push(bool value)
Adds the given bit to the end of the set.
Definition BitSet.cpp:175
BIT_SET_CONSTEXPR std::size_t lastSet() const
Finds the last set bit in the set.
Definition BitSet.hpp:247
bool operator==(BitSet const &other) const noexcept
Definition BitSet.cpp:42
constexpr std::size_t size() const noexcept
Definition BitSet.hpp:87
BitSet & setAll(bool value=true) noexcept
Sets all bits to the given value.
Definition BitSet.cpp:34
static constexpr std::uint64_t mask(std::size_t pos)
Definition BitSet.hpp:313
BitSet & inplaceXor(BitSet const &other) noexcept
Performs a bitwise XOR with this set and other in place without resizing this.
Definition BitSet.cpp:144
friend class BitSetTester
Used by unit tests to access BitSet internals.
Definition BitSet.hpp:335
std::size_t _size
Definition BitSet.hpp:309
void resizeSentinel(std::size_t size, bool sentinelValue)
Changes the number of bits stored in this set, and sets the final bit past size to the value of senti...
Definition BitSet.cpp:167
void normalize() noexcept
Unset the trailing bits.
Definition BitSet.cpp:152
BIT_SET_CONSTEXPR std::size_t firstSet(std::size_t start=0) const
Finds the first set bit in the set, starting from (and including) start.
Definition BitSet.hpp:229
std::vector< std::uint64_t > _store
Definition BitSet.hpp:310
BitSet & inplaceAnd(BitSet const &other) noexcept
Performs a bitwise AND with this set and other in place without resizing this.
Definition BitSet.cpp:125
BitSet & inplaceOr(BitSet const &other) noexcept
Performs a bitwise OR with this set and other in place without resizing this.
Definition BitSet.cpp:136
bool operator!=(BitSet const &other) const noexcept
Definition BitSet.cpp:47
void _resize(std::size_t size)
Resize without normalizing.
Definition BitSet.cpp:161
BIT_SET_CONSTEXPR bool operator[](std::size_t pos) const noexcept
Definition BitSet.hpp:103
BIT_SET_CONSTEXPR std::size_t lastUnset() const
Finds the last unset bit in the set.
Definition BitSet.hpp:290
BIT_SET_CONSTEXPR BitSet & set(std::size_t pos, bool value=true) noexcept
Definition BitSet.hpp:111
bool pop()
Removes one bit from the end of the set.
Definition BitSet.cpp:182
BIT_SET_CONSTEXPR bool test(std::size_t pos) const noexcept
Definition BitSet.hpp:95
BitSet & flip() noexcept
Flips all the bits in the set.
Definition BitSet.cpp:52
T countl_one(T... args)
T countl_zero(T... args)
T countr_one(T... args)
T countr_zero(T... args)
Namespace regrouping helpers used by ecstasy but not specific to ecstasy.
Definition Queryable.hpp:21