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