1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /* SPDX-FileCopyrightText: OpenMPT Project Developers and Contributors */
3 
4 /*
5  * Originally based on <http://stackoverflow.com/questions/4226960/type-safer-bitflags-in-c>.
6  * Rewritten to be standard-conforming.
7  */
8 
9 
10 #pragma once
11 
12 #include "openmpt/all/BuildSettings.hpp"
13 
14 #include "mpt/base/macros.hpp"
15 
16 #include <type_traits>
17 
18 #include <cstddef>
19 
20 
21 OPENMPT_NAMESPACE_BEGIN
22 
23 
24 // Type-safe wrapper around an enum, that can represent all enum values and bitwise compositions thereof.
25 // Conversions to and from plain integers as well as conversions to the base enum are always explicit.
26 template <typename enum_t>
27 // cppcheck-suppress copyCtorAndEqOperator
28 class enum_value_type
29 {
30 public:
31 	using enum_type = enum_t;
32 	using value_type = enum_value_type;
33 	using store_type = typename std::make_unsigned<enum_t>::type;
34 
35 private:
36 	store_type bits;
37 
38 public:
enum_value_type()39 	MPT_CONSTEXPRINLINE enum_value_type() noexcept
40 		: bits(0) {}
enum_value_type(const enum_value_type & x)41 	MPT_CONSTEXPRINLINE enum_value_type(const enum_value_type &x) noexcept
42 		: bits(x.bits) {}
enum_value_type(enum_type x)43 	MPT_CONSTEXPRINLINE enum_value_type(enum_type x) noexcept
44 		: bits(static_cast<store_type>(x)) {}
45 
46 private:
enum_value_type(store_type x)47 	explicit MPT_CONSTEXPRINLINE enum_value_type(store_type x) noexcept
48 		: bits(x) {}                                                           // private in order to prevent accidental conversions. use from_bits.
operator store_type() const49 	MPT_CONSTEXPRINLINE operator store_type() const noexcept { return bits; }  // private in order to prevent accidental conversions. use as_bits.
50 public:
from_bits(store_type bits)51 	static MPT_CONSTEXPRINLINE enum_value_type from_bits(store_type bits) noexcept { return value_type(bits); }
as_enum() const52 	MPT_CONSTEXPRINLINE enum_type as_enum() const noexcept { return static_cast<enum_t>(bits); }
as_bits() const53 	MPT_CONSTEXPRINLINE store_type as_bits() const noexcept { return bits; }
54 
55 public:
operator bool() const56 	MPT_CONSTEXPRINLINE operator bool() const noexcept { return bits != store_type(); }
operator !() const57 	MPT_CONSTEXPRINLINE bool operator!() const noexcept { return bits == store_type(); }
58 
operator ~() const59 	MPT_CONSTEXPRINLINE const enum_value_type operator~() const noexcept { return enum_value_type(~bits); }
60 
operator ==(enum_value_type a,enum_value_type b)61 	friend MPT_CONSTEXPRINLINE bool operator==(enum_value_type a, enum_value_type b) noexcept { return a.bits == b.bits; }
operator !=(enum_value_type a,enum_value_type b)62 	friend MPT_CONSTEXPRINLINE bool operator!=(enum_value_type a, enum_value_type b) noexcept { return a.bits != b.bits; }
63 
operator ==(enum_value_type a,enum_t b)64 	friend MPT_CONSTEXPRINLINE bool operator==(enum_value_type a, enum_t b) noexcept { return a == enum_value_type(b); }
operator !=(enum_value_type a,enum_t b)65 	friend MPT_CONSTEXPRINLINE bool operator!=(enum_value_type a, enum_t b) noexcept { return a != enum_value_type(b); }
66 
operator ==(enum_t a,enum_value_type b)67 	friend MPT_CONSTEXPRINLINE bool operator==(enum_t a, enum_value_type b) noexcept { return enum_value_type(a) == b; }
operator !=(enum_t a,enum_value_type b)68 	friend MPT_CONSTEXPRINLINE bool operator!=(enum_t a, enum_value_type b) noexcept { return enum_value_type(a) != b; }
69 
operator |(enum_value_type a,enum_value_type b)70 	friend MPT_CONSTEXPRINLINE const enum_value_type operator|(enum_value_type a, enum_value_type b) noexcept { return enum_value_type(a.bits | b.bits); }
operator &(enum_value_type a,enum_value_type b)71 	friend MPT_CONSTEXPRINLINE const enum_value_type operator&(enum_value_type a, enum_value_type b) noexcept { return enum_value_type(a.bits & b.bits); }
operator ^(enum_value_type a,enum_value_type b)72 	friend MPT_CONSTEXPRINLINE const enum_value_type operator^(enum_value_type a, enum_value_type b) noexcept { return enum_value_type(a.bits ^ b.bits); }
73 
operator |(enum_value_type a,enum_t b)74 	friend MPT_CONSTEXPRINLINE const enum_value_type operator|(enum_value_type a, enum_t b) noexcept { return a | enum_value_type(b); }
operator &(enum_value_type a,enum_t b)75 	friend MPT_CONSTEXPRINLINE const enum_value_type operator&(enum_value_type a, enum_t b) noexcept { return a & enum_value_type(b); }
operator ^(enum_value_type a,enum_t b)76 	friend MPT_CONSTEXPRINLINE const enum_value_type operator^(enum_value_type a, enum_t b) noexcept { return a ^ enum_value_type(b); }
77 
operator |(enum_t a,enum_value_type b)78 	friend MPT_CONSTEXPRINLINE const enum_value_type operator|(enum_t a, enum_value_type b) noexcept { return enum_value_type(a) | b; }
operator &(enum_t a,enum_value_type b)79 	friend MPT_CONSTEXPRINLINE const enum_value_type operator&(enum_t a, enum_value_type b) noexcept { return enum_value_type(a) & b; }
operator ^(enum_t a,enum_value_type b)80 	friend MPT_CONSTEXPRINLINE const enum_value_type operator^(enum_t a, enum_value_type b) noexcept { return enum_value_type(a) ^ b; }
81 
operator |=(enum_value_type b)82 	MPT_CONSTEXPRINLINE enum_value_type &operator|=(enum_value_type b) noexcept
83 	{
84 		*this = *this | b;
85 		return *this;
86 	}
operator &=(enum_value_type b)87 	MPT_CONSTEXPRINLINE enum_value_type &operator&=(enum_value_type b) noexcept
88 	{
89 		*this = *this & b;
90 		return *this;
91 	}
operator ^=(enum_value_type b)92 	MPT_CONSTEXPRINLINE enum_value_type &operator^=(enum_value_type b) noexcept
93 	{
94 		*this = *this ^ b;
95 		return *this;
96 	}
97 
operator |=(enum_t b)98 	MPT_CONSTEXPRINLINE enum_value_type &operator|=(enum_t b) noexcept
99 	{
100 		*this = *this | b;
101 		return *this;
102 	}
operator &=(enum_t b)103 	MPT_CONSTEXPRINLINE enum_value_type &operator&=(enum_t b) noexcept
104 	{
105 		*this = *this & b;
106 		return *this;
107 	}
operator ^=(enum_t b)108 	MPT_CONSTEXPRINLINE enum_value_type &operator^=(enum_t b) noexcept
109 	{
110 		*this = *this ^ b;
111 		return *this;
112 	}
113 };
114 
115 
116 // Type-safe enum wrapper that allows type-safe bitwise testing.
117 template <typename enum_t>
118 class Enum
119 {
120 public:
121 	using self_type = Enum;
122 	using enum_type = enum_t;
123 	using value_type = enum_value_type<enum_t>;
124 	using store_type = typename value_type::store_type;
125 
126 private:
127 	enum_type value;
128 
129 public:
Enum(enum_type val)130 	explicit MPT_CONSTEXPRINLINE Enum(enum_type val) noexcept
131 		: value(val) {}
operator enum_type() const132 	MPT_CONSTEXPRINLINE operator enum_type() const noexcept { return value; }
operator =(enum_type val)133 	MPT_CONSTEXPRINLINE Enum &operator=(enum_type val) noexcept
134 	{
135 		value = val;
136 		return *this;
137 	}
138 
139 public:
operator ~() const140 	MPT_CONSTEXPRINLINE const value_type operator~() const { return ~value_type(value); }
141 
operator ==(self_type a,self_type b)142 	friend MPT_CONSTEXPRINLINE bool operator==(self_type a, self_type b) noexcept { return value_type(a) == value_type(b); }
operator !=(self_type a,self_type b)143 	friend MPT_CONSTEXPRINLINE bool operator!=(self_type a, self_type b) noexcept { return value_type(a) != value_type(b); }
144 
operator ==(self_type a,value_type b)145 	friend MPT_CONSTEXPRINLINE bool operator==(self_type a, value_type b) noexcept { return value_type(a) == value_type(b); }
operator !=(self_type a,value_type b)146 	friend MPT_CONSTEXPRINLINE bool operator!=(self_type a, value_type b) noexcept { return value_type(a) != value_type(b); }
147 
operator ==(value_type a,self_type b)148 	friend MPT_CONSTEXPRINLINE bool operator==(value_type a, self_type b) noexcept { return value_type(a) == value_type(b); }
operator !=(value_type a,self_type b)149 	friend MPT_CONSTEXPRINLINE bool operator!=(value_type a, self_type b) noexcept { return value_type(a) != value_type(b); }
150 
operator ==(self_type a,enum_type b)151 	friend MPT_CONSTEXPRINLINE bool operator==(self_type a, enum_type b) noexcept { return value_type(a) == value_type(b); }
operator !=(self_type a,enum_type b)152 	friend MPT_CONSTEXPRINLINE bool operator!=(self_type a, enum_type b) noexcept { return value_type(a) != value_type(b); }
153 
operator ==(enum_type a,self_type b)154 	friend MPT_CONSTEXPRINLINE bool operator==(enum_type a, self_type b) noexcept { return value_type(a) == value_type(b); }
operator !=(enum_type a,self_type b)155 	friend MPT_CONSTEXPRINLINE bool operator!=(enum_type a, self_type b) noexcept { return value_type(a) != value_type(b); }
156 
operator |(self_type a,self_type b)157 	friend MPT_CONSTEXPRINLINE const value_type operator|(self_type a, self_type b) noexcept { return value_type(a) | value_type(b); }
operator &(self_type a,self_type b)158 	friend MPT_CONSTEXPRINLINE const value_type operator&(self_type a, self_type b) noexcept { return value_type(a) & value_type(b); }
operator ^(self_type a,self_type b)159 	friend MPT_CONSTEXPRINLINE const value_type operator^(self_type a, self_type b) noexcept { return value_type(a) ^ value_type(b); }
160 
operator |(self_type a,value_type b)161 	friend MPT_CONSTEXPRINLINE const value_type operator|(self_type a, value_type b) noexcept { return value_type(a) | value_type(b); }
operator &(self_type a,value_type b)162 	friend MPT_CONSTEXPRINLINE const value_type operator&(self_type a, value_type b) noexcept { return value_type(a) & value_type(b); }
operator ^(self_type a,value_type b)163 	friend MPT_CONSTEXPRINLINE const value_type operator^(self_type a, value_type b) noexcept { return value_type(a) ^ value_type(b); }
164 
operator |(value_type a,self_type b)165 	friend MPT_CONSTEXPRINLINE const value_type operator|(value_type a, self_type b) noexcept { return value_type(a) | value_type(b); }
operator &(value_type a,self_type b)166 	friend MPT_CONSTEXPRINLINE const value_type operator&(value_type a, self_type b) noexcept { return value_type(a) & value_type(b); }
operator ^(value_type a,self_type b)167 	friend MPT_CONSTEXPRINLINE const value_type operator^(value_type a, self_type b) noexcept { return value_type(a) ^ value_type(b); }
168 
operator |(self_type a,enum_type b)169 	friend MPT_CONSTEXPRINLINE const value_type operator|(self_type a, enum_type b) noexcept { return value_type(a) | value_type(b); }
operator &(self_type a,enum_type b)170 	friend MPT_CONSTEXPRINLINE const value_type operator&(self_type a, enum_type b) noexcept { return value_type(a) & value_type(b); }
operator ^(self_type a,enum_type b)171 	friend MPT_CONSTEXPRINLINE const value_type operator^(self_type a, enum_type b) noexcept { return value_type(a) ^ value_type(b); }
172 
operator |(enum_type a,self_type b)173 	friend MPT_CONSTEXPRINLINE const value_type operator|(enum_type a, self_type b) noexcept { return value_type(a) | value_type(b); }
operator &(enum_type a,self_type b)174 	friend MPT_CONSTEXPRINLINE const value_type operator&(enum_type a, self_type b) noexcept { return value_type(a) & value_type(b); }
operator ^(enum_type a,self_type b)175 	friend MPT_CONSTEXPRINLINE const value_type operator^(enum_type a, self_type b) noexcept { return value_type(a) ^ value_type(b); }
176 };
177 
178 
179 template <typename enum_t, typename store_t = typename enum_value_type<enum_t>::store_type>
180 // cppcheck-suppress copyCtorAndEqOperator
181 class FlagSet
182 {
183 public:
184 	using self_type = FlagSet;
185 	using enum_type = enum_t;
186 	using value_type = enum_value_type<enum_t>;
187 	using store_type = store_t;
188 
189 private:
190 	// support truncated store_type ... :
191 	store_type bits_;
store_from_value(value_type bits)192 	static MPT_CONSTEXPRINLINE store_type store_from_value(value_type bits) noexcept { return static_cast<store_type>(bits.as_bits()); }
value_from_store(store_type bits)193 	static MPT_CONSTEXPRINLINE value_type value_from_store(store_type bits) noexcept { return value_type::from_bits(static_cast<typename value_type::store_type>(bits)); }
194 
store(value_type bits)195 	MPT_CONSTEXPRINLINE FlagSet &store(value_type bits) noexcept
196 	{
197 		bits_ = store_from_value(bits);
198 		return *this;
199 	}
load() const200 	MPT_CONSTEXPRINLINE value_type load() const noexcept { return value_from_store(bits_); }
201 
202 public:
203 	// Default constructor (no flags set)
FlagSet()204 	MPT_CONSTEXPRINLINE FlagSet() noexcept
205 		: bits_(store_from_value(value_type()))
206 	{
207 	}
208 
209 	// Copy constructor
FlagSet(const FlagSet & flags)210 	MPT_CONSTEXPRINLINE FlagSet(const FlagSet &flags) noexcept
211 		: bits_(flags.bits_)
212 	{
213 	}
214 
215 	// Value constructor
FlagSet(value_type flags)216 	MPT_CONSTEXPRINLINE FlagSet(value_type flags) noexcept
217 		: bits_(store_from_value(value_type(flags)))
218 	{
219 	}
220 
FlagSet(enum_type flag)221 	MPT_CONSTEXPRINLINE FlagSet(enum_type flag) noexcept
222 		: bits_(store_from_value(value_type(flag)))
223 	{
224 	}
225 
FlagSet(store_type flags)226 	explicit MPT_CONSTEXPRINLINE FlagSet(store_type flags) noexcept
227 		: bits_(store_from_value(value_type::from_bits(flags)))
228 	{
229 	}
230 
operator bool() const231 	MPT_CONSTEXPRINLINE explicit operator bool() const noexcept
232 	{
233 		return load();
234 	}
operator store_type() const235 	MPT_CONSTEXPRINLINE explicit operator store_type() const noexcept
236 	{
237 		return load().as_bits();
238 	}
239 
value() const240 	MPT_CONSTEXPRINLINE value_type value() const noexcept
241 	{
242 		return load();
243 	}
244 
operator value_type() const245 	MPT_CONSTEXPRINLINE operator value_type() const noexcept
246 	{
247 		return load();
248 	}
249 
250 	// Test if one or more flags are set. Returns true if at least one of the given flags is set.
operator [](value_type flags) const251 	MPT_CONSTEXPRINLINE bool operator[](value_type flags) const noexcept
252 	{
253 		return test(flags);
254 	}
255 
256 	// Set one or more flags.
set(value_type flags)257 	MPT_CONSTEXPRINLINE FlagSet &set(value_type flags) noexcept
258 	{
259 		return store(load() | flags);
260 	}
261 
262 	// Set or clear one or more flags.
set(value_type flags,bool val)263 	MPT_CONSTEXPRINLINE FlagSet &set(value_type flags, bool val) noexcept
264 	{
265 		return store((val ? (load() | flags) : (load() & ~flags)));
266 	}
267 
268 	// Clear or flags.
reset()269 	MPT_CONSTEXPRINLINE FlagSet &reset() noexcept
270 	{
271 		return store(value_type());
272 	}
273 
274 	// Clear one or more flags.
reset(value_type flags)275 	MPT_CONSTEXPRINLINE FlagSet &reset(value_type flags) noexcept
276 	{
277 		return store(load() & ~flags);
278 	}
279 
280 	// Toggle all flags.
flip()281 	MPT_CONSTEXPRINLINE FlagSet &flip() noexcept
282 	{
283 		return store(~load());
284 	}
285 
286 	// Toggle one or more flags.
flip(value_type flags)287 	MPT_CONSTEXPRINLINE FlagSet &flip(value_type flags) noexcept
288 	{
289 		return store(load() ^ flags);
290 	}
291 
292 	// Returns the size of the flag set in bytes
size() const293 	MPT_CONSTEXPRINLINE std::size_t size() const noexcept
294 	{
295 		return sizeof(store_type);
296 	}
297 
298 	// Returns the size of the flag set in bits
size_bits() const299 	MPT_CONSTEXPRINLINE std::size_t size_bits() const noexcept
300 	{
301 		return size() * 8;
302 	}
303 
304 	// Test if one or more flags are set. Returns true if at least one of the given flags is set.
test(value_type flags) const305 	MPT_CONSTEXPRINLINE bool test(value_type flags) const noexcept
306 	{
307 		return (load() & flags);
308 	}
309 
310 	// Test if all specified flags are set.
test_all(value_type flags) const311 	MPT_CONSTEXPRINLINE bool test_all(value_type flags) const noexcept
312 	{
313 		return (load() & flags) == flags;
314 	}
315 
316 	// Test if any but the specified flags are set.
test_any_except(value_type flags) const317 	MPT_CONSTEXPRINLINE bool test_any_except(value_type flags) const noexcept
318 	{
319 		return (load() & ~flags);
320 	}
321 
322 	// Test if any flag is set.
any() const323 	MPT_CONSTEXPRINLINE bool any() const noexcept
324 	{
325 		return load();
326 	}
327 
328 	// Test if no flags are set.
none() const329 	MPT_CONSTEXPRINLINE bool none() const noexcept
330 	{
331 		return !load();
332 	}
333 
GetRaw() const334 	MPT_CONSTEXPRINLINE store_type GetRaw() const noexcept
335 	{
336 		return bits_;
337 	}
338 
SetRaw(store_type flags)339 	MPT_CONSTEXPRINLINE FlagSet &SetRaw(store_type flags) noexcept
340 	{
341 		bits_ = flags;
342 		return *this;
343 	}
344 
operator =(value_type flags)345 	MPT_CONSTEXPRINLINE FlagSet &operator=(value_type flags) noexcept
346 	{
347 		return store(flags);
348 	}
349 
operator =(enum_type flag)350 	MPT_CONSTEXPRINLINE FlagSet &operator=(enum_type flag) noexcept
351 	{
352 		return store(flag);
353 	}
354 
operator =(FlagSet flags)355 	MPT_CONSTEXPRINLINE FlagSet &operator=(FlagSet flags) noexcept
356 	{
357 		return store(flags.load());
358 	}
359 
operator &=(value_type flags)360 	MPT_CONSTEXPRINLINE FlagSet &operator&=(value_type flags) noexcept
361 	{
362 		return store(load() & flags);
363 	}
364 
operator |=(value_type flags)365 	MPT_CONSTEXPRINLINE FlagSet &operator|=(value_type flags) noexcept
366 	{
367 		return store(load() | flags);
368 	}
369 
operator ^=(value_type flags)370 	MPT_CONSTEXPRINLINE FlagSet &operator^=(value_type flags) noexcept
371 	{
372 		return store(load() ^ flags);
373 	}
374 
operator ==(self_type a,self_type b)375 	friend MPT_CONSTEXPRINLINE bool operator==(self_type a, self_type b) noexcept { return a.load() == b.load(); }
operator !=(self_type a,self_type b)376 	friend MPT_CONSTEXPRINLINE bool operator!=(self_type a, self_type b) noexcept { return a.load() != b.load(); }
377 
operator ==(self_type a,value_type b)378 	friend MPT_CONSTEXPRINLINE bool operator==(self_type a, value_type b) noexcept { return a.load() == value_type(b); }
operator !=(self_type a,value_type b)379 	friend MPT_CONSTEXPRINLINE bool operator!=(self_type a, value_type b) noexcept { return a.load() != value_type(b); }
380 
operator ==(value_type a,self_type b)381 	friend MPT_CONSTEXPRINLINE bool operator==(value_type a, self_type b) noexcept { return value_type(a) == b.load(); }
operator !=(value_type a,self_type b)382 	friend MPT_CONSTEXPRINLINE bool operator!=(value_type a, self_type b) noexcept { return value_type(a) != b.load(); }
383 
operator ==(self_type a,enum_type b)384 	friend MPT_CONSTEXPRINLINE bool operator==(self_type a, enum_type b) noexcept { return a.load() == value_type(b); }
operator !=(self_type a,enum_type b)385 	friend MPT_CONSTEXPRINLINE bool operator!=(self_type a, enum_type b) noexcept { return a.load() != value_type(b); }
386 
operator ==(enum_type a,self_type b)387 	friend MPT_CONSTEXPRINLINE bool operator==(enum_type a, self_type b) noexcept { return value_type(a) == b.load(); }
operator !=(enum_type a,self_type b)388 	friend MPT_CONSTEXPRINLINE bool operator!=(enum_type a, self_type b) noexcept { return value_type(a) != b.load(); }
389 
operator ==(self_type a,Enum<enum_type> b)390 	friend MPT_CONSTEXPRINLINE bool operator==(self_type a, Enum<enum_type> b) noexcept { return a.load() == value_type(b); }
operator !=(self_type a,Enum<enum_type> b)391 	friend MPT_CONSTEXPRINLINE bool operator!=(self_type a, Enum<enum_type> b) noexcept { return a.load() != value_type(b); }
392 
operator ==(Enum<enum_type> a,self_type b)393 	friend MPT_CONSTEXPRINLINE bool operator==(Enum<enum_type> a, self_type b) noexcept { return value_type(a) == b.load(); }
operator !=(Enum<enum_type> a,self_type b)394 	friend MPT_CONSTEXPRINLINE bool operator!=(Enum<enum_type> a, self_type b) noexcept { return value_type(a) != b.load(); }
395 
operator |(self_type a,self_type b)396 	friend MPT_CONSTEXPRINLINE const value_type operator|(self_type a, self_type b) noexcept { return a.load() | b.load(); }
operator &(self_type a,self_type b)397 	friend MPT_CONSTEXPRINLINE const value_type operator&(self_type a, self_type b) noexcept { return a.load() & b.load(); }
operator ^(self_type a,self_type b)398 	friend MPT_CONSTEXPRINLINE const value_type operator^(self_type a, self_type b) noexcept { return a.load() ^ b.load(); }
399 
operator |(self_type a,value_type b)400 	friend MPT_CONSTEXPRINLINE const value_type operator|(self_type a, value_type b) noexcept { return a.load() | value_type(b); }
operator &(self_type a,value_type b)401 	friend MPT_CONSTEXPRINLINE const value_type operator&(self_type a, value_type b) noexcept { return a.load() & value_type(b); }
operator ^(self_type a,value_type b)402 	friend MPT_CONSTEXPRINLINE const value_type operator^(self_type a, value_type b) noexcept { return a.load() ^ value_type(b); }
403 
operator |(value_type a,self_type b)404 	friend MPT_CONSTEXPRINLINE const value_type operator|(value_type a, self_type b) noexcept { return value_type(a) | b.load(); }
operator &(value_type a,self_type b)405 	friend MPT_CONSTEXPRINLINE const value_type operator&(value_type a, self_type b) noexcept { return value_type(a) & b.load(); }
operator ^(value_type a,self_type b)406 	friend MPT_CONSTEXPRINLINE const value_type operator^(value_type a, self_type b) noexcept { return value_type(a) ^ b.load(); }
407 
operator |(self_type a,enum_type b)408 	friend MPT_CONSTEXPRINLINE const value_type operator|(self_type a, enum_type b) noexcept { return a.load() | value_type(b); }
operator &(self_type a,enum_type b)409 	friend MPT_CONSTEXPRINLINE const value_type operator&(self_type a, enum_type b) noexcept { return a.load() & value_type(b); }
operator ^(self_type a,enum_type b)410 	friend MPT_CONSTEXPRINLINE const value_type operator^(self_type a, enum_type b) noexcept { return a.load() ^ value_type(b); }
411 
operator |(enum_type a,self_type b)412 	friend MPT_CONSTEXPRINLINE const value_type operator|(enum_type a, self_type b) noexcept { return value_type(a) | b.load(); }
operator &(enum_type a,self_type b)413 	friend MPT_CONSTEXPRINLINE const value_type operator&(enum_type a, self_type b) noexcept { return value_type(a) & b.load(); }
operator ^(enum_type a,self_type b)414 	friend MPT_CONSTEXPRINLINE const value_type operator^(enum_type a, self_type b) noexcept { return value_type(a) ^ b.load(); }
415 
operator |(self_type a,Enum<enum_type> b)416 	friend MPT_CONSTEXPRINLINE const value_type operator|(self_type a, Enum<enum_type> b) noexcept { return a.load() | value_type(b); }
operator &(self_type a,Enum<enum_type> b)417 	friend MPT_CONSTEXPRINLINE const value_type operator&(self_type a, Enum<enum_type> b) noexcept { return a.load() & value_type(b); }
operator ^(self_type a,Enum<enum_type> b)418 	friend MPT_CONSTEXPRINLINE const value_type operator^(self_type a, Enum<enum_type> b) noexcept { return a.load() ^ value_type(b); }
419 
operator |(Enum<enum_type> a,self_type b)420 	friend MPT_CONSTEXPRINLINE const value_type operator|(Enum<enum_type> a, self_type b) noexcept { return value_type(a) | b.load(); }
operator &(Enum<enum_type> a,self_type b)421 	friend MPT_CONSTEXPRINLINE const value_type operator&(Enum<enum_type> a, self_type b) noexcept { return value_type(a) & b.load(); }
operator ^(Enum<enum_type> a,self_type b)422 	friend MPT_CONSTEXPRINLINE const value_type operator^(Enum<enum_type> a, self_type b) noexcept { return value_type(a) ^ b.load(); }
423 };
424 
425 
426 // Declare typesafe logical operators for enum_t
427 #define MPT_DECLARE_ENUM(enum_t) \
428 	MPT_CONSTEXPRINLINE enum_value_type<enum_t> operator|(enum_t a, enum_t b) noexcept { return enum_value_type<enum_t>(a) | enum_value_type<enum_t>(b); } \
429 	MPT_CONSTEXPRINLINE enum_value_type<enum_t> operator&(enum_t a, enum_t b) noexcept { return enum_value_type<enum_t>(a) & enum_value_type<enum_t>(b); } \
430 	MPT_CONSTEXPRINLINE enum_value_type<enum_t> operator^(enum_t a, enum_t b) noexcept { return enum_value_type<enum_t>(a) ^ enum_value_type<enum_t>(b); } \
431 	MPT_CONSTEXPRINLINE enum_value_type<enum_t> operator~(enum_t a) noexcept { return ~enum_value_type<enum_t>(a); } \
432 /**/
433 
434 // backwards compatibility
435 #define DECLARE_FLAGSET MPT_DECLARE_ENUM
436 
437 
438 OPENMPT_NAMESPACE_END
439