1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #pragma once |
4 | |
5 | namespace bs |
6 | { |
7 | /** @addtogroup General |
8 | * @{ |
9 | */ |
10 | |
11 | /** Wrapper around an enum that allows simple use of bitwise logic operations. */ |
12 | template<typename Enum, typename Storage = UINT32> |
13 | class Flags |
14 | { |
15 | public: |
16 | using InternalType = Storage; |
17 | |
18 | Flags() = default; |
19 | |
20 | Flags(Enum value) |
21 | { |
22 | mBits = static_cast<Storage>(value); |
23 | } |
24 | |
25 | Flags(const Flags<Enum, Storage>& value) |
26 | { |
27 | mBits = value.mBits; |
28 | } |
29 | |
30 | explicit Flags(Storage bits) |
31 | { |
32 | mBits = bits; |
33 | } |
34 | |
35 | /** Checks whether all of the provided bits are set */ |
36 | bool isSet(Enum value) const |
37 | { |
38 | return (mBits & static_cast<Storage>(value)) == static_cast<Storage>(value); |
39 | } |
40 | |
41 | /** Checks whether any of the provided bits are set */ |
42 | bool isSetAny(Enum value) const |
43 | { |
44 | return (mBits & static_cast<Storage>(value)) != 0; |
45 | } |
46 | |
47 | /** Checks whether any of the provided bits are set */ |
48 | bool isSetAny(const Flags<Enum, Storage>& value) const |
49 | { |
50 | return (mBits & value.mBits) != 0; |
51 | } |
52 | |
53 | /** Activates all of the provided bits. */ |
54 | Flags<Enum, Storage>& set(Enum value) |
55 | { |
56 | mBits |= static_cast<Storage>(value); |
57 | |
58 | return *this; |
59 | } |
60 | |
61 | /** Deactivates all of the provided bits. */ |
62 | void unset(Enum value) |
63 | { |
64 | mBits &= ~static_cast<Storage>(value); |
65 | } |
66 | |
67 | bool operator==(Enum rhs) const |
68 | { |
69 | return mBits == static_cast<Storage>(rhs); |
70 | } |
71 | |
72 | bool operator==(const Flags<Enum, Storage>& rhs) const |
73 | { |
74 | return mBits == rhs.mBits; |
75 | } |
76 | |
77 | bool operator==(bool rhs) const |
78 | { |
79 | return ((bool)*this) == rhs; |
80 | } |
81 | |
82 | bool operator!=(Enum rhs) const |
83 | { |
84 | return mBits != static_cast<Storage>(rhs); |
85 | } |
86 | |
87 | bool operator!=(const Flags<Enum, Storage>& rhs) const |
88 | { |
89 | return mBits != rhs.mBits; |
90 | } |
91 | |
92 | Flags<Enum, Storage>& operator= (Enum rhs) |
93 | { |
94 | mBits = static_cast<Storage>(rhs); |
95 | |
96 | return *this; |
97 | } |
98 | |
99 | Flags<Enum, Storage>& operator= (const Flags<Enum, Storage>& rhs) |
100 | { |
101 | mBits = rhs.mBits; |
102 | |
103 | return *this; |
104 | } |
105 | |
106 | Flags<Enum, Storage>& operator|= (Enum rhs) |
107 | { |
108 | mBits |= static_cast<Storage>(rhs); |
109 | |
110 | return *this; |
111 | } |
112 | |
113 | Flags<Enum, Storage>& operator|= (const Flags<Enum, Storage>& rhs) |
114 | { |
115 | mBits |= rhs.mBits; |
116 | |
117 | return *this; |
118 | } |
119 | |
120 | Flags<Enum, Storage> operator| (Enum rhs) const |
121 | { |
122 | Flags<Enum, Storage> out(*this); |
123 | out |= rhs; |
124 | |
125 | return out; |
126 | } |
127 | |
128 | Flags<Enum, Storage> operator| (const Flags<Enum, Storage>& rhs) const |
129 | { |
130 | Flags<Enum, Storage> out(*this); |
131 | out |= rhs; |
132 | |
133 | return out; |
134 | } |
135 | |
136 | Flags<Enum, Storage>& operator&= (Enum rhs) |
137 | { |
138 | mBits &= static_cast<Storage>(rhs); |
139 | |
140 | return *this; |
141 | } |
142 | |
143 | Flags<Enum, Storage>& operator&= (const Flags<Enum, Storage>& rhs) |
144 | { |
145 | mBits &= rhs.mBits; |
146 | |
147 | return *this; |
148 | } |
149 | |
150 | Flags<Enum, Storage> operator& (Enum rhs) const |
151 | { |
152 | Flags<Enum, Storage> out = *this; |
153 | out.mBits &= static_cast<Storage>(rhs); |
154 | |
155 | return out; |
156 | } |
157 | |
158 | Flags<Enum, Storage> operator& (const Flags<Enum, Storage>& rhs) const |
159 | { |
160 | Flags<Enum, Storage> out = *this; |
161 | out.mBits &= rhs.mBits; |
162 | |
163 | return out; |
164 | } |
165 | |
166 | Flags<Enum, Storage>& operator^= (Enum rhs) |
167 | { |
168 | mBits ^= static_cast<Storage>(rhs); |
169 | |
170 | return *this; |
171 | } |
172 | |
173 | Flags<Enum, Storage>& operator^= (const Flags<Enum, Storage>& rhs) |
174 | { |
175 | mBits ^= rhs.mBits; |
176 | |
177 | return *this; |
178 | } |
179 | |
180 | Flags<Enum, Storage> operator^ (Enum rhs) const |
181 | { |
182 | Flags<Enum, Storage> out = *this; |
183 | out.mBits ^= static_cast<Storage>(rhs); |
184 | |
185 | return out; |
186 | } |
187 | |
188 | Flags<Enum, Storage> operator^ (const Flags<Enum, Storage>& rhs) const |
189 | { |
190 | Flags<Enum, Storage> out = *this; |
191 | out.mBits ^= rhs.mBits; |
192 | |
193 | return out; |
194 | } |
195 | |
196 | Flags<Enum, Storage> operator~ () const |
197 | { |
198 | Flags<Enum, Storage> out; |
199 | out.mBits = (Storage)~mBits; |
200 | |
201 | return out; |
202 | } |
203 | |
204 | operator bool() const |
205 | { |
206 | return mBits ? true : false; |
207 | } |
208 | |
209 | operator UINT8() const |
210 | { |
211 | return static_cast<UINT8>(mBits); |
212 | } |
213 | |
214 | operator UINT16() const |
215 | { |
216 | return static_cast<UINT16>(mBits); |
217 | } |
218 | |
219 | operator UINT32() const |
220 | { |
221 | return static_cast<UINT32>(mBits); |
222 | } |
223 | |
224 | friend Flags<Enum, Storage> operator&(Enum a, Flags<Enum, Storage> &b) |
225 | { |
226 | Flags<Enum, Storage> out; |
227 | out.mBits = a & b.mBits; |
228 | return out; |
229 | } |
230 | |
231 | private: |
232 | InternalType mBits{0}; |
233 | }; |
234 | |
235 | /** Defines global operators for a Flags<Enum, Storage> implementation. */ |
236 | #define BS_FLAGS_OPERATORS(Enum) BS_FLAGS_OPERATORS_EXT(Enum, UINT32) |
237 | |
238 | /** Defines global operators for a Flags<Enum, Storage> implementation. */ |
239 | #define BS_FLAGS_OPERATORS_EXT(Enum, Storage) \ |
240 | inline Flags<Enum, Storage> operator|(Enum a, Enum b) { Flags<Enum, Storage> r(a); r |= b; return r; } \ |
241 | inline Flags<Enum, Storage> operator&(Enum a, Enum b) { Flags<Enum, Storage> r(a); r &= b; return r; } \ |
242 | inline Flags<Enum, Storage> operator~(Enum a) { return ~Flags<Enum, Storage>(a); } |
243 | |
244 | /** @cond SPECIALIZATIONS */ |
245 | |
246 | /** |
247 | * RTTIPlainType for Flags. |
248 | * |
249 | * @see RTTIPlainType |
250 | */ |
251 | template<class Enum, class Storage> struct RTTIPlainType<Flags<Enum, Storage>> |
252 | { |
253 | enum { id = TID_Flags }; enum { hasDynamicSize = 0 }; |
254 | |
255 | /** @copydoc RTTIPlainType::toMemory */ |
256 | static void toMemory(const Flags<Enum, Storage>& data, char* memory) |
257 | { |
258 | Storage storageData = (Storage)data; |
259 | RTTIPlainType<Storage>::toMemory(storageData, memory); |
260 | } |
261 | |
262 | /** @copydoc RTTIPlainType::fromMemory */ |
263 | static UINT32 fromMemory(Flags<Enum, Storage>& data, char* memory) |
264 | { |
265 | Storage storageData; |
266 | RTTIPlainType<Storage>::fromMemory(storageData, memory); |
267 | |
268 | data = Flags<Enum, Storage>(storageData); |
269 | return sizeof(Flags<Enum, Storage>); |
270 | } |
271 | |
272 | /** @copydoc RTTIPlainType::getDynamicSize */ |
273 | static UINT32 getDynamicSize(const Flags<Enum, Storage>& data) |
274 | { |
275 | assert(false); |
276 | return sizeof(Flags<Enum, Storage>); |
277 | } |
278 | }; |
279 | |
280 | /** @endcond */ |
281 | /** @} */ |
282 | } |
283 | |
284 | /** @cond STDLIB */ |
285 | |
286 | namespace std |
287 | { |
288 | /** Hash value generator for Flags<Enum, Storage>. */ |
289 | template<class Enum, class Storage> |
290 | struct hash<bs::Flags<Enum, Storage>> |
291 | { |
292 | size_t operator()(const bs::Flags<Enum, Storage>& key) const |
293 | { |
294 | return (Storage)key; |
295 | } |
296 | }; |
297 | } |
298 | |
299 | /** @endcond */ |
300 | |