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
5namespace 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
286namespace 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