summaryrefslogtreecommitdiff
path: root/src/common/bit_set.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/bit_set.h')
-rw-r--r--src/common/bit_set.h203
1 files changed, 129 insertions, 74 deletions
diff --git a/src/common/bit_set.h b/src/common/bit_set.h
index 7f5de8df2..b83cbbb36 100644
--- a/src/common/bit_set.h
+++ b/src/common/bit_set.h
@@ -18,49 +18,60 @@ namespace Common {
18 18
19#ifdef _WIN32 19#ifdef _WIN32
20template <typename T> 20template <typename T>
21static inline int CountSetBits(T v) 21static inline int CountSetBits(T v) {
22{
23 // from https://graphics.stanford.edu/~seander/bithacks.html 22 // from https://graphics.stanford.edu/~seander/bithacks.html
24 // GCC has this built in, but MSVC's intrinsic will only emit the actual 23 // GCC has this built in, but MSVC's intrinsic will only emit the actual
25 // POPCNT instruction, which we're not depending on 24 // POPCNT instruction, which we're not depending on
26 v = v - ((v >> 1) & (T)~(T)0/3); 25 v = v - ((v >> 1) & (T) ~(T)0 / 3);
27 v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3); 26 v = (v & (T) ~(T)0 / 15 * 3) + ((v >> 2) & (T) ~(T)0 / 15 * 3);
28 v = (v + (v >> 4)) & (T)~(T)0/255*15; 27 v = (v + (v >> 4)) & (T) ~(T)0 / 255 * 15;
29 return (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * 8; 28 return (T)(v * ((T) ~(T)0 / 255)) >> (sizeof(T) - 1) * 8;
30} 29}
31static inline int LeastSignificantSetBit(u8 val) 30static inline int LeastSignificantSetBit(u8 val) {
32{
33 unsigned long index; 31 unsigned long index;
34 _BitScanForward(&index, val); 32 _BitScanForward(&index, val);
35 return (int)index; 33 return (int)index;
36} 34}
37static inline int LeastSignificantSetBit(u16 val) 35static inline int LeastSignificantSetBit(u16 val) {
38{
39 unsigned long index; 36 unsigned long index;
40 _BitScanForward(&index, val); 37 _BitScanForward(&index, val);
41 return (int)index; 38 return (int)index;
42} 39}
43static inline int LeastSignificantSetBit(u32 val) 40static inline int LeastSignificantSetBit(u32 val) {
44{
45 unsigned long index; 41 unsigned long index;
46 _BitScanForward(&index, val); 42 _BitScanForward(&index, val);
47 return (int)index; 43 return (int)index;
48} 44}
49static inline int LeastSignificantSetBit(u64 val) 45static inline int LeastSignificantSetBit(u64 val) {
50{
51 unsigned long index; 46 unsigned long index;
52 _BitScanForward64(&index, val); 47 _BitScanForward64(&index, val);
53 return (int)index; 48 return (int)index;
54} 49}
55#else 50#else
56static inline int CountSetBits(u8 val) { return __builtin_popcount(val); } 51static inline int CountSetBits(u8 val) {
57static inline int CountSetBits(u16 val) { return __builtin_popcount(val); } 52 return __builtin_popcount(val);
58static inline int CountSetBits(u32 val) { return __builtin_popcount(val); } 53}
59static inline int CountSetBits(u64 val) { return __builtin_popcountll(val); } 54static inline int CountSetBits(u16 val) {
60static inline int LeastSignificantSetBit(u8 val) { return __builtin_ctz(val); } 55 return __builtin_popcount(val);
61static inline int LeastSignificantSetBit(u16 val) { return __builtin_ctz(val); } 56}
62static inline int LeastSignificantSetBit(u32 val) { return __builtin_ctz(val); } 57static inline int CountSetBits(u32 val) {
63static inline int LeastSignificantSetBit(u64 val) { return __builtin_ctzll(val); } 58 return __builtin_popcount(val);
59}
60static inline int CountSetBits(u64 val) {
61 return __builtin_popcountll(val);
62}
63static inline int LeastSignificantSetBit(u8 val) {
64 return __builtin_ctz(val);
65}
66static inline int LeastSignificantSetBit(u16 val) {
67 return __builtin_ctz(val);
68}
69static inline int LeastSignificantSetBit(u32 val) {
70 return __builtin_ctz(val);
71}
72static inline int LeastSignificantSetBit(u64 val) {
73 return __builtin_ctzll(val);
74}
64#endif 75#endif
65 76
66// Similar to std::bitset, this is a class which encapsulates a bitset, i.e. 77// Similar to std::bitset, this is a class which encapsulates a bitset, i.e.
@@ -84,100 +95,144 @@ static inline int LeastSignificantSetBit(u64 val) { return __builtin_ctzll(val);
84// TODO: use constexpr when MSVC gets out of the Dark Ages 95// TODO: use constexpr when MSVC gets out of the Dark Ages
85 96
86template <typename IntTy> 97template <typename IntTy>
87class BitSet 98class BitSet {
88{
89 static_assert(!std::is_signed<IntTy>::value, "BitSet should not be used with signed types"); 99 static_assert(!std::is_signed<IntTy>::value, "BitSet should not be used with signed types");
100
90public: 101public:
91 // A reference to a particular bit, returned from operator[]. 102 // A reference to a particular bit, returned from operator[].
92 class Ref 103 class Ref {
93 {
94 public: 104 public:
95 Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {} 105 Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {
96 Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {} 106 }
97 operator bool() const { return (m_bs->m_val & m_mask) != 0; } 107 Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {
98 bool operator=(bool set) 108 }
99 { 109 operator bool() const {
110 return (m_bs->m_val & m_mask) != 0;
111 }
112 bool operator=(bool set) {
100 m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0); 113 m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0);
101 return set; 114 return set;
102 } 115 }
116
103 private: 117 private:
104 BitSet* m_bs; 118 BitSet* m_bs;
105 IntTy m_mask; 119 IntTy m_mask;
106 }; 120 };
107 121
108 // A STL-like iterator is required to be able to use range-based for loops. 122 // A STL-like iterator is required to be able to use range-based for loops.
109 class Iterator 123 class Iterator {
110 {
111 public: 124 public:
112 Iterator(const Iterator& other) : m_val(other.m_val), m_bit(other.m_bit) {} 125 Iterator(const Iterator& other) : m_val(other.m_val), m_bit(other.m_bit) {
113 Iterator(IntTy val, int bit) : m_val(val), m_bit(bit) {} 126 }
114 Iterator& operator=(Iterator other) { new (this) Iterator(other); return *this; } 127 Iterator(IntTy val, int bit) : m_val(val), m_bit(bit) {
115 int operator*() { return m_bit; } 128 }
116 Iterator& operator++() 129 Iterator& operator=(Iterator other) {
117 { 130 new (this) Iterator(other);
118 if (m_val == 0) 131 return *this;
119 { 132 }
133 int operator*() {
134 return m_bit;
135 }
136 Iterator& operator++() {
137 if (m_val == 0) {
120 m_bit = -1; 138 m_bit = -1;
121 } 139 } else {
122 else
123 {
124 int bit = LeastSignificantSetBit(m_val); 140 int bit = LeastSignificantSetBit(m_val);
125 m_val &= ~(1 << bit); 141 m_val &= ~(1 << bit);
126 m_bit = bit; 142 m_bit = bit;
127 } 143 }
128 return *this; 144 return *this;
129 } 145 }
130 Iterator operator++(int _) 146 Iterator operator++(int _) {
131 {
132 Iterator other(*this); 147 Iterator other(*this);
133 ++*this; 148 ++*this;
134 return other; 149 return other;
135 } 150 }
136 bool operator==(Iterator other) const { return m_bit == other.m_bit; } 151 bool operator==(Iterator other) const {
137 bool operator!=(Iterator other) const { return m_bit != other.m_bit; } 152 return m_bit == other.m_bit;
153 }
154 bool operator!=(Iterator other) const {
155 return m_bit != other.m_bit;
156 }
157
138 private: 158 private:
139 IntTy m_val; 159 IntTy m_val;
140 int m_bit; 160 int m_bit;
141 }; 161 };
142 162
143 BitSet() : m_val(0) {} 163 BitSet() : m_val(0) {
144 explicit BitSet(IntTy val) : m_val(val) {} 164 }
145 BitSet(std::initializer_list<int> init) 165 explicit BitSet(IntTy val) : m_val(val) {
146 { 166 }
167 BitSet(std::initializer_list<int> init) {
147 m_val = 0; 168 m_val = 0;
148 for (int bit : init) 169 for (int bit : init)
149 m_val |= (IntTy)1 << bit; 170 m_val |= (IntTy)1 << bit;
150 } 171 }
151 172
152 static BitSet AllTrue(size_t count) 173 static BitSet AllTrue(size_t count) {
153 { 174 return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1));
154 return BitSet(count == sizeof(IntTy)*8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1)); 175 }
155 } 176
156 177 Ref operator[](size_t bit) {
157 Ref operator[](size_t bit) { return Ref(this, (IntTy)1 << bit); } 178 return Ref(this, (IntTy)1 << bit);
158 const Ref operator[](size_t bit) const { return (*const_cast<BitSet*>(this))[bit]; } 179 }
159 bool operator==(BitSet other) const { return m_val == other.m_val; } 180 const Ref operator[](size_t bit) const {
160 bool operator!=(BitSet other) const { return m_val != other.m_val; } 181 return (*const_cast<BitSet*>(this))[bit];
161 bool operator<(BitSet other) const { return m_val < other.m_val; } 182 }
162 bool operator>(BitSet other) const { return m_val > other.m_val; } 183 bool operator==(BitSet other) const {
163 BitSet operator|(BitSet other) const { return BitSet(m_val | other.m_val); } 184 return m_val == other.m_val;
164 BitSet operator&(BitSet other) const { return BitSet(m_val & other.m_val); } 185 }
165 BitSet operator^(BitSet other) const { return BitSet(m_val ^ other.m_val); } 186 bool operator!=(BitSet other) const {
166 BitSet operator~() const { return BitSet(~m_val); } 187 return m_val != other.m_val;
167 BitSet& operator|=(BitSet other) { return *this = *this | other; } 188 }
168 BitSet& operator&=(BitSet other) { return *this = *this & other; } 189 bool operator<(BitSet other) const {
169 BitSet& operator^=(BitSet other) { return *this = *this ^ other; } 190 return m_val < other.m_val;
191 }
192 bool operator>(BitSet other) const {
193 return m_val > other.m_val;
194 }
195 BitSet operator|(BitSet other) const {
196 return BitSet(m_val | other.m_val);
197 }
198 BitSet operator&(BitSet other) const {
199 return BitSet(m_val & other.m_val);
200 }
201 BitSet operator^(BitSet other) const {
202 return BitSet(m_val ^ other.m_val);
203 }
204 BitSet operator~() const {
205 return BitSet(~m_val);
206 }
207 BitSet& operator|=(BitSet other) {
208 return *this = *this | other;
209 }
210 BitSet& operator&=(BitSet other) {
211 return *this = *this & other;
212 }
213 BitSet& operator^=(BitSet other) {
214 return *this = *this ^ other;
215 }
170 operator u32() = delete; 216 operator u32() = delete;
171 operator bool() { return m_val != 0; } 217 operator bool() {
218 return m_val != 0;
219 }
172 220
173 // Warning: Even though on modern CPUs this is a single fast instruction, 221 // Warning: Even though on modern CPUs this is a single fast instruction,
174 // Dolphin's official builds do not currently assume POPCNT support on x86, 222 // Dolphin's official builds do not currently assume POPCNT support on x86,
175 // so slower explicit bit twiddling is generated. Still should generally 223 // so slower explicit bit twiddling is generated. Still should generally
176 // be faster than a loop. 224 // be faster than a loop.
177 unsigned int Count() const { return CountSetBits(m_val); } 225 unsigned int Count() const {
226 return CountSetBits(m_val);
227 }
178 228
179 Iterator begin() const { Iterator it(m_val, 0); return ++it; } 229 Iterator begin() const {
180 Iterator end() const { return Iterator(m_val, -1); } 230 Iterator it(m_val, 0);
231 return ++it;
232 }
233 Iterator end() const {
234 return Iterator(m_val, -1);
235 }
181 236
182 IntTy m_val; 237 IntTy m_val;
183}; 238};