Gaia-ECS v0.9.3
A simple and powerful entity component system
Loading...
Searching...
No Matches
bitset.h
1#pragma once
2#include "gaia/config/config.h"
3
4#include <cstdint>
5#include <type_traits>
6
7#include "gaia/cnt/bitset_iterator.h"
8
9namespace gaia {
10 namespace cnt {
11 template <uint32_t NBits>
12 class bitset {
13 public:
14 static constexpr uint32_t BitCount = NBits;
15 static_assert(NBits > 0);
16
17 private:
18 template <bool Use32Bit>
19 struct size_type_selector {
20 using type = std::conditional_t<Use32Bit, uint32_t, uint64_t>;
21 };
22
23 public:
24 static constexpr uint32_t BitsPerItem = (NBits / 64) > 0 ? 64 : 32;
25 static constexpr uint32_t Items = (NBits + BitsPerItem - 1) / BitsPerItem;
26
27 using size_type = typename size_type_selector<BitsPerItem == 32>::type;
28
29 private:
30 static constexpr bool HasTrailingBits = (NBits % BitsPerItem) != 0;
31 static constexpr size_type LastItemMask = ((size_type)1 << (NBits % BitsPerItem)) - 1;
32
33 size_type m_data[Items]{};
34
36 size_type data(uint32_t wordIdx) const {
37 return m_data[wordIdx];
38 }
39
40 public:
45 friend iter;
46 friend iter_inv;
47 friend iter_rev;
48 friend iter_rev_inv;
49
50 constexpr size_type* data() {
51 return &m_data[0];
52 }
53
54 constexpr const size_type* data() const {
55 return &m_data[0];
56 }
57
59 GAIA_NODISCARD constexpr uint32_t items() const {
60 return Items;
61 }
62
63 constexpr iter begin() const {
64 return iter(*this, 0, true);
65 }
66
67 constexpr iter end() const {
68 return iter(*this, NBits, false);
69 }
70
71 constexpr iter_rev rbegin() const {
72 return iter_rev(*this, NBits, false);
73 }
74
75 constexpr iter_rev rend() const {
76 return iter_rev(*this, 0, true);
77 }
78
79 constexpr iter_inv ibegin() const {
80 return iter_inv(*this, 0, true);
81 }
82
83 constexpr iter_inv iend() const {
84 return iter_inv(*this, NBits, false);
85 }
86
87 constexpr iter_rev_inv ribegin() const {
88 return iter_rev_inv(*this, NBits, false);
89 }
90
91 constexpr iter_rev_inv riend() const {
92 return iter_rev_inv(*this, 0, true);
93 }
94
95 GAIA_NODISCARD constexpr bool operator[](uint32_t pos) const {
96 return test(pos);
97 }
98
99 GAIA_NODISCARD constexpr bool operator==(const bitset& other) const {
100 GAIA_FOR(Items) {
101 if (m_data[i] != other.m_data[i])
102 return false;
103 }
104 return true;
105 }
106
107 GAIA_NODISCARD constexpr bool operator!=(const bitset& other) const {
108 GAIA_FOR(Items) {
109 if (m_data[i] == other.m_data[i])
110 return false;
111 }
112 return true;
113 }
114
116 constexpr void set() {
117 if constexpr (HasTrailingBits) {
118 GAIA_FOR(Items - 1) m_data[i] = (size_type)-1;
119 m_data[Items - 1] = LastItemMask;
120 } else {
121 GAIA_FOR(Items) m_data[i] = (size_type)-1;
122 }
123 }
124
128 constexpr void set(uint32_t pos, bool value = true) {
129 GAIA_ASSERT(pos < NBits);
130 if (value)
131 m_data[pos / BitsPerItem] |= ((size_type)1 << (pos % BitsPerItem));
132 else
133 m_data[pos / BitsPerItem] &= ~((size_type)1 << (pos % BitsPerItem));
134 }
135
137 constexpr bitset& flip() {
138 if constexpr (HasTrailingBits) {
139 GAIA_FOR(Items - 1) m_data[i] = ~m_data[i];
140 m_data[Items - 1] = (~m_data[Items - 1]) & LastItemMask;
141 } else {
142 GAIA_FOR(Items) m_data[i] = ~m_data[i];
143 }
144 return *this;
145 }
146
148 constexpr void flip(uint32_t pos) {
149 GAIA_ASSERT(pos < NBits);
150 const auto wordIdx = pos / BitsPerItem;
151 const auto bitIdx = pos % BitsPerItem;
152 m_data[wordIdx] ^= ((size_type)1 << bitIdx);
153 }
154
156 constexpr bitset& flip(uint32_t bitFrom, uint32_t bitTo) {
157 GAIA_ASSERT(bitFrom <= bitTo);
158 GAIA_ASSERT(bitTo < size());
159
160 // The following can't happen because we always have at least 1 bit
161 // if GAIA_UNLIKELY (size() == 0)
162 // return *this;
163
164 const uint32_t wordIdxFrom = bitFrom / BitsPerItem;
165 const uint32_t wordIdxTo = bitTo / BitsPerItem;
166
167 auto getMask = [](uint32_t from, uint32_t to) -> size_type {
168 const auto diff = to - from;
169 // Set all bits when asking for the full range
170 if (diff == BitsPerItem - 1)
171 return (size_type)-1;
172
173 return ((size_type(1) << (diff + 1)) - 1) << from;
174 };
175
176 if (wordIdxFrom == wordIdxTo) {
177 m_data[wordIdxTo] ^= getMask(bitFrom % BitsPerItem, bitTo % BitsPerItem);
178 } else {
179 // First word
180 m_data[wordIdxFrom] ^= getMask(bitFrom % BitsPerItem, BitsPerItem - 1);
181 // Middle
182 GAIA_FOR2(wordIdxFrom + 1, wordIdxTo) m_data[i] = ~m_data[i];
183 // Last word
184 m_data[wordIdxTo] ^= getMask(0, bitTo % BitsPerItem);
185 }
186
187 return *this;
188 }
189
191 constexpr void reset() {
192 GAIA_FOR(Items) m_data[i] = 0;
193 }
194
196 constexpr void reset(uint32_t pos) {
197 GAIA_ASSERT(pos < NBits);
198 m_data[pos / BitsPerItem] &= ~((size_type)1 << (pos % BitsPerItem));
199 }
200
202 GAIA_NODISCARD constexpr bool test(uint32_t pos) const {
203 GAIA_ASSERT(pos < NBits);
204 return (m_data[pos / BitsPerItem] & ((size_type)1 << (pos % BitsPerItem))) != 0;
205 }
206
208 GAIA_NODISCARD constexpr bool all() const {
209 if constexpr (HasTrailingBits) {
210 GAIA_FOR(Items - 1) {
211 if (m_data[i] != (size_type)-1)
212 return false;
213 }
214 return (m_data[Items - 1] & LastItemMask) == LastItemMask;
215 } else {
216 GAIA_FOR(Items) {
217 if (m_data[i] != (size_type)-1)
218 return false;
219 }
220 return true;
221 }
222 }
223
225 GAIA_NODISCARD constexpr bool any() const {
226 GAIA_FOR(Items) {
227 if (m_data[i] != 0)
228 return true;
229 }
230 return false;
231 }
232
234 GAIA_NODISCARD constexpr bool none() const {
235 GAIA_FOR(Items) {
236 if (m_data[i] != 0)
237 return false;
238 }
239 return true;
240 }
241
243 GAIA_NODISCARD uint32_t count() const {
244 uint32_t total = 0;
245
246 GAIA_MSVC_WARNING_PUSH()
247 GAIA_MSVC_WARNING_DISABLE(4244)
248 if constexpr (sizeof(size_type) == 4) {
249 GAIA_FOR(Items) total += GAIA_POPCNT(m_data[i]);
250 } else {
251 GAIA_FOR(Items) total += GAIA_POPCNT64(m_data[i]);
252 }
253 GAIA_MSVC_WARNING_POP()
254
255 return total;
256 }
257
259 GAIA_NODISCARD constexpr uint32_t size() const {
260 return NBits;
261 }
262 };
263 } // namespace cnt
264} // namespace gaia
Bitset iterator.
Definition bitset_iterator.h:14
Definition bitset.h:12
GAIA_NODISCARD constexpr bool all() const
Checks if all bits are set.
Definition bitset.h:208
constexpr void reset()
Unsets all bits.
Definition bitset.h:191
GAIA_NODISCARD constexpr bool none() const
Checks if all bits are reset.
Definition bitset.h:234
GAIA_NODISCARD constexpr bool test(uint32_t pos) const
Returns the value of the bit at the position.
Definition bitset.h:202
GAIA_NODISCARD uint32_t count() const
Returns the number of set bits.
Definition bitset.h:243
constexpr void reset(uint32_t pos)
Unsets the bit at the postion.
Definition bitset.h:196
constexpr void set(uint32_t pos, bool value=true)
Sets the bit at the given position.
Definition bitset.h:128
constexpr bitset & flip(uint32_t bitFrom, uint32_t bitTo)
Flips all bits from.
Definition bitset.h:156
GAIA_NODISCARD constexpr uint32_t size() const
Returns the number of bits the bitset can hold.
Definition bitset.h:259
GAIA_NODISCARD constexpr bool any() const
Checks if any bit is set.
Definition bitset.h:225
constexpr void set()
Sets all bits.
Definition bitset.h:116
GAIA_NODISCARD constexpr uint32_t items() const
Returns the number of words used by the bitset internally.
Definition bitset.h:59
constexpr bitset & flip()
Flips all bits.
Definition bitset.h:137
constexpr void flip(uint32_t pos)
Flips the bit at the postion.
Definition bitset.h:148
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9