Sparkle 0.0.1
Loading...
Searching...
No Matches
spk_flags.hpp
1#pragma once
2
3#include <cstdint>
4#include <initializer_list>
5#include <iostream>
6#include <type_traits>
7
8namespace spk
9{
13 template <typename TEnumType>
14 concept bitmask_enum =
15 std::is_enum_v<TEnumType> &&
16 (sizeof(std::underlying_type_t<TEnumType>) <= 4);
17
21 template <typename T>
23 std::is_unsigned_v<T> &&
24 (sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4);
25}
26
33template <spk::bitmask_enum TEnumType>
34constexpr TEnumType operator|(TEnumType p_l, TEnumType p_r) noexcept
35{
36 using U = std::underlying_type_t<TEnumType>;
37 return static_cast<TEnumType>(static_cast<U>(p_l) | static_cast<U>(p_r));
38}
45template <spk::bitmask_enum TEnumType>
46constexpr TEnumType operator&(TEnumType p_l, TEnumType p_r) noexcept
47{
48 using U = std::underlying_type_t<TEnumType>;
49 return static_cast<TEnumType>(static_cast<U>(p_l) & static_cast<U>(p_r));
50}
57template <spk::bitmask_enum TEnumType>
58constexpr TEnumType operator^(TEnumType p_l, TEnumType p_r) noexcept
59{
60 using U = std::underlying_type_t<TEnumType>;
61 return static_cast<TEnumType>(static_cast<U>(p_l) ^ static_cast<U>(p_r));
62}
68template <spk::bitmask_enum TEnumType>
69constexpr TEnumType operator~(TEnumType p_v) noexcept
70{
71 using U = std::underlying_type_t<TEnumType>;
72 return static_cast<TEnumType>(~static_cast<U>(p_v));
73}
75template <spk::bitmask_enum TEnumType>
76constexpr TEnumType &operator|=(TEnumType &p_l, TEnumType p_r) noexcept
77{
78 return p_l = (p_l | p_r);
79}
81template <spk::bitmask_enum TEnumType>
82constexpr TEnumType &operator&=(TEnumType &p_l, TEnumType p_r) noexcept
83{
84 return p_l = (p_l & p_r);
85}
87template <spk::bitmask_enum TEnumType>
88constexpr TEnumType &operator^=(TEnumType &p_l, TEnumType p_r) noexcept
89{
90 return p_l = (p_l ^ p_r);
91}
92
93namespace spk
94{
109 template <bitmask_enum TFlagType, unsigned_storage StorageT = std::uint32_t>
110 struct alignas(StorageT) Flags
111 {
112 static_assert(sizeof(std::underlying_type_t<TFlagType>) <= sizeof(StorageT), "Storage type too small for enum underlying type");
113
115 using MaskType = StorageT;
116
121
125 constexpr Flags() = default;
126
131 constexpr Flags(TFlagType p_v) :
132 bits(static_cast<MaskType>(p_v))
133 {
134 }
135
140 constexpr explicit Flags(MaskType p_raw) :
141 bits(p_raw)
142 {
143 }
144
149 constexpr Flags(std::initializer_list<TFlagType> p_values) :
150 bits(0)
151 {
152 for (auto v : p_values)
153 {
154 bits |= static_cast<MaskType>(v);
155 }
156 }
157
161 constexpr void clear()
162 {
163 bits = 0;
164 }
165
169 constexpr void reset(TFlagType p_v)
170 {
171 bits &= ~static_cast<MaskType>(p_v);
172 }
173
179 constexpr Flags &operator|=(TFlagType p_v)
180 {
181 bits |= static_cast<MaskType>(p_v);
182 return *this;
183 }
184
189 constexpr Flags &operator&=(TFlagType p_v)
190 {
191 bits &= static_cast<MaskType>(p_v);
192 return *this;
193 }
194
199 constexpr Flags &operator^=(TFlagType p_v)
200 {
201 bits ^= static_cast<MaskType>(p_v);
202 return *this;
203 }
204
210 constexpr bool has(TFlagType p_v) const
211 {
212 return (bits & static_cast<MaskType>(p_v)) == static_cast<MaskType>(p_v);
213 }
214
219 constexpr bool testAny(TFlagType p_v) const
220 {
221 return (bits & static_cast<MaskType>(p_v)) != 0;
222 }
223
227 constexpr bool any() const
228 {
229 return bits != 0;
230 }
231
235 constexpr bool none() const
236 {
237 return bits == 0;
238 }
239
243 explicit constexpr operator bool() const
244 {
245 return any();
246 }
247
252 constexpr MaskType raw() const
253 {
254 return bits;
255 }
256 };
257
264 template <bitmask_enum T, unsigned_storage S>
265 constexpr Flags<T, S> operator|(Flags<T, S> p_l, Flags<T, S> p_r) noexcept
266 {
267 p_l.bits |= p_r.bits;
268 return p_l;
269 }
276 template <bitmask_enum T, unsigned_storage S>
277 constexpr Flags<T, S> operator&(Flags<T, S> p_l, Flags<T, S> p_r) noexcept
278 {
279 p_l.bits &= p_r.bits;
280 return p_l;
281 }
288 template <bitmask_enum T, unsigned_storage S>
289 constexpr Flags<T, S> operator^(Flags<T, S> p_l, Flags<T, S> p_r) noexcept
290 {
291 p_l.bits ^= p_r.bits;
292 return p_l;
293 }
299 template <bitmask_enum T, unsigned_storage S>
300 constexpr Flags<T, S> operator~(Flags<T, S> p_v) noexcept
301 {
302 p_v.bits = static_cast<typename Flags<T, S>::MaskType>(~p_v.bits);
303 return p_v;
304 }
305
312 template <bitmask_enum T, unsigned_storage S>
313 constexpr Flags<T, S> operator|(Flags<T, S> p_l, T p_r) noexcept
314 {
315 p_l |= p_r;
316 return p_l;
317 }
324 template <bitmask_enum T, unsigned_storage S>
325 constexpr Flags<T, S> operator|(T p_l, Flags<T, S> p_r) noexcept
326 {
327 p_r |= p_l;
328 return p_r;
329 }
336 template <bitmask_enum T, unsigned_storage S>
337 constexpr Flags<T, S> operator&(Flags<T, S> p_l, T p_r) noexcept
338 {
339 p_l.bits &= static_cast<typename Flags<T, S>::MaskType>(p_r);
340 return p_l;
341 }
348 template <bitmask_enum T, unsigned_storage S>
349 constexpr Flags<T, S> operator&(T p_l, Flags<T, S> p_r) noexcept
350 {
351 return p_r & p_l;
352 }
353
360 template <bitmask_enum T, unsigned_storage S>
361 constexpr bool operator==(Flags<T, S> p_l, Flags<T, S> p_r) noexcept
362 {
363 return p_l.bits == p_r.bits;
364 }
371 template <bitmask_enum T, unsigned_storage S>
372 constexpr bool operator!=(Flags<T, S> p_l, Flags<T, S> p_r) noexcept
373 {
374 return !(p_l == p_r);
375 }
376 template <bitmask_enum T, unsigned_storage S>
377 constexpr bool operator==(Flags<T, S> p_l, T p_r) noexcept
378 {
379 return p_l.bits == static_cast<typename Flags<T, S>::MaskType>(p_r);
380 }
381 template <bitmask_enum T, unsigned_storage S>
382 constexpr bool operator==(T p_l, Flags<T, S> p_r) noexcept
383 {
384 return p_r == p_l;
385 }
386 template <bitmask_enum T, unsigned_storage S>
387 constexpr bool operator!=(Flags<T, S> p_l, T p_r) noexcept
388 {
389 return !(p_l == p_r);
390 }
391 template <bitmask_enum T, unsigned_storage S>
392 constexpr bool operator!=(T p_l, Flags<T, S> p_r) noexcept
393 {
394 return !(p_r == p_l);
395 }
396
397 template <bitmask_enum T>
398 using Flags8 = Flags<T, std::uint8_t>;
399 template <bitmask_enum T>
400 using Flags16 = Flags<T, std::uint16_t>;
401 template <bitmask_enum T>
402 using Flags32 = Flags<T, std::uint32_t>;
403}
404
405template <spk::bitmask_enum E, spk::unsigned_storage S>
406std::ostream &operator<<(std::ostream &p_os, spk::Flags<E, S> p_f)
407{
408 return p_os << "0x" << std::hex << static_cast<typename spk::Flags<E, S>::MaskType>(p_f.bits);
409}
410template <spk::bitmask_enum E, spk::unsigned_storage S>
411std::wostream &operator<<(std::wostream &p_os, spk::Flags<E, S> p_f)
412{
413 return p_os << L"0x" << std::hex << static_cast<typename spk::Flags<E, S>::MaskType>(p_f.bits);
414}
Concept ensuring an enum can be used as a bitmask (size up to 32 bits).
Definition spk_flags.hpp:14
Concept restricting storage to unsigned 8/16/32-bit.
Definition spk_flags.hpp:22
constexpr MaskType raw() const
Returns the underlying bits.
Definition spk_flags.hpp:252
constexpr Flags(std::initializer_list< TFlagType > p_values)
Initializes with multiple flags.
Definition spk_flags.hpp:149
constexpr Flags & operator^=(TFlagType p_v)
In-place XOR with a flag.
Definition spk_flags.hpp:199
constexpr Flags()=default
Builds an empty flag set.
constexpr Flags(MaskType p_raw)
Initializes with raw bits.
Definition spk_flags.hpp:140
constexpr Flags & operator&=(TFlagType p_v)
In-place AND with a mask.
Definition spk_flags.hpp:189
constexpr Flags & operator|=(TFlagType p_v)
In-place OR with a flag.
Definition spk_flags.hpp:179
constexpr bool testAny(TFlagType p_v) const
Tests whether any bit in a mask is set.
Definition spk_flags.hpp:219
constexpr void clear()
Clears all flags.
Definition spk_flags.hpp:161
constexpr Flags(TFlagType p_v)
Initializes with a single flag.
Definition spk_flags.hpp:131
constexpr void reset(TFlagType p_v)
Removes specific flags.
Definition spk_flags.hpp:169
StorageT MaskType
Unsigned storage type used to hold flag bits.
Definition spk_flags.hpp:115
MaskType bits
Definition spk_flags.hpp:120
constexpr bool any() const
Checks if any flag is set.
Definition spk_flags.hpp:227
constexpr bool has(TFlagType p_v) const
Tests whether all bits in a mask are set.
Definition spk_flags.hpp:210
constexpr bool none() const
Checks if no flags are set.
Definition spk_flags.hpp:235