17 template <
integral_or_enum ENUM, detail::val
id_
integral VALUE_TYPE =
unsigned long long>
20 constexpr inline struct all_flags_t {} all_flags;
21 constexpr inline struct no_flags_t {} no_flags;
58 template <
integral_or_enum ENUM, detail::val
id_
integral VALUE_TYPE =
unsigned long long>
66 using self_type = enum_flags;
70 constexpr enum_flags() noexcept = default;
71 constexpr enum_flags(const enum_flags&) noexcept = default;
72 constexpr enum_flags(enum_flags&&) noexcept = default;
73 constexpr enum_flags& operator=(const enum_flags&) noexcept = default;
74 constexpr enum_flags& operator=(enum_flags&&) noexcept = default;
76 constexpr enum_flags(
enum_type base_value) noexcept : bits(
flag_bits<VALUE_TYPE>(base_value)) {}
77 template<
typename U = VALUE_TYPE>
78 requires (!std::is_same_v<U, enum_type>)
85 template <
typename... ARGS>
88 constexpr enum_flags(std::initializer_list<enum_type> values)
noexcept {
93 template <
integral_or_enum BITS_TYPE>
94 requires std::convertible_to<
decltype(detail::to_underlying_type(BITS_TYPE{})), VALUE_TYPE>
95 [[nodiscard]]
constexpr static self_type
from_bits(BITS_TYPE val)
noexcept {
97 ret.bits =
static_cast<VALUE_TYPE
>(detail::to_underlying_type(val));
105 constexpr enum_flags(all_flags_t) noexcept : bits(~VALUE_TYPE{0}) {}
117 constexpr static self_type
none() noexcept {
return {}; }
119 constexpr enum_flags(no_flags_t) noexcept : bits(VALUE_TYPE{0}) {}
134 template <std::convertible_to<enum_type>... FLAGS>
142 constexpr int count() const noexcept {
return std::popcount(bits); }
149 while (n--) { b ^= (VALUE_TYPE{ 1 } << std::countr_zero(b)); }
150 return static_cast<enum_type>(std::countr_zero(b));
162 template <
typename... ARGS>
166 return this->
is_set(arg) || (this->
is_set(args) || ...);
170 template <
typename... ARGS>
174 return !(this->
is_set(arg) || (this->
is_set(args) || ...));
183 constexpr bool full() const noexcept {
return (~bits) == 0; }
188 constexpr bool contains_any_of(self_type other)
const noexcept {
return other.bits == 0 || (bits & other.bits) != 0; }
191 template <
typename... ARGS>
195 return (this->
is_set(args) && ...);
200 constexpr bool contains_all_of(self_type other)
const noexcept {
return (bits & other.bits) == other.bits; }
202 constexpr explicit operator bool() const noexcept {
return bits != 0; }
209 template <std::convertible_to<enum_type>... ARGS>
212 constexpr self_type&
set(self_type other)
noexcept { bits |= other.bits;
return *
this; }
215 template <std::convertible_to<enum_type>... ARGS>
216 constexpr self_type&
unset(ARGS... args)
noexcept { bits &= ~ flag_bits<VALUE_TYPE>(args...);
return *
this; }
218 constexpr self_type&
unset(self_type other)
noexcept { bits &= ~other.bits;
return *
this; }
221 template <std::convertible_to<enum_type>... ARGS>
224 constexpr self_type&
toggle(self_type other)
noexcept { bits ^= other.bits;
return *
this; }
227 template <std::convertible_to<enum_type>... ARGS>
228 constexpr self_type&
set_to(
bool val, ARGS... args)
noexcept
235 constexpr self_type&
set_to(
bool val, self_type other)
noexcept
237 if (val) bits |= other.bits;
else bits &= ~other.bits;
255 constexpr self_type operator+(self_type flags)
const noexcept {
return self_type::from_bits(bits | flags.bits); }
257 constexpr self_type operator-(self_type flags)
const noexcept {
return self_type::from_bits(bits & ~flags.bits); }
261 constexpr self_type except_for(self_type flags)
const noexcept {
return self_type::from_bits(bits & ~flags.bits); }
263 constexpr self_type without(self_type flags)
const noexcept {
return self_type::from_bits(bits & ~flags.bits); }
265 template <std::convertible_to<enum_type>... ARGS>
267 template <std::convertible_to<enum_type>... ARGS>
271 constexpr self_type& operator-=(
enum_type flag)
noexcept { bits &= ~ flag_bits<VALUE_TYPE>(flag);
return *
this; }
273 constexpr self_type& operator+=(self_type flags)
noexcept { bits |= flags.bits;
return *
this; }
274 constexpr self_type& operator-=(self_type flags)
noexcept { bits &= ~flags.bits;
return *
this; }
276 constexpr auto operator<=>(enum_flags
const& other)
const noexcept =
default;
281 using bitset_type = std::make_unsigned_t<self_type::value_type>;
283 using difference_type = int;
285 using pointer_type = void;
286 using reference = void;
287 using iterator_category = std::forward_iterator_tag;
292 const auto bitset =
static_cast<bitset_type
>(bits);
293#pragma warning(suppress: 4146)
294 return static_cast<enum_type>(std::countr_zero(
static_cast<bitset_type
>(bitset & -bitset)));
299 const auto bitset =
static_cast<bitset_type
>(bits);
300#pragma warning(suppress: 4146)
301 const auto t =
static_cast<bitset_type
>(bitset & -bitset);
306 iterator operator++(
int)
noexcept {
const auto result = *
this; operator++();
return result; }
308 auto operator<=>(iterator
const& other)
const noexcept =
default;
311 iterator begin() const noexcept {
return iterator{ bits }; }
312 iterator end() const noexcept {
return iterator{ {} }; }
313 iterator cbegin() const noexcept {
return iterator{ bits }; }
314 iterator cend() const noexcept {
return iterator{ {} }; }
316 constexpr bool empty() const noexcept {
return bits == 0; }
317 constexpr void clear() noexcept { bits = 0; }
325 template <
typename FUNC>
328 using return_type = std::invoke_result_t<FUNC, enum_type>;
329 using bitset_type = std::make_unsigned_t<value_type>;
330 auto bitset =
static_cast<bitset_type
>(bits);
333#pragma warning(suppress: 4146)
334 const auto t =
static_cast<bitset_type
>(bitset & -bitset);
335 const auto r = std::countr_zero(t);
336 if constexpr (std::is_convertible_v<return_type, bool>)
338 if (
auto ret = callback((
enum_type)r))
return ret;
344 if constexpr (std::is_convertible_v<return_type, bool>)
345 return return_type{};
350 constexpr void apply(flag_changes changes)
noexcept
352 const auto bits_to_xor = changes.bits_to_set.bits & changes.bits_to_unset.bits;
356 changes.bits_to_set.bits &= ~bits_to_xor;
357 changes.bits_to_unset.bits &= ~bits_to_xor;
360 bits &= ~changes.bits_to_unset.bits;
361 bits |= changes.bits_to_set.bits;
364 constexpr self_type operator+(flag_changes changes)
const noexcept
367 result.apply(changes);
373 template <
typename TYPE>
374 struct is_enum_flags : std::false_type {};
376 template <
typename ENUM,
typename VALUE_TYPE>
377 struct is_enum_flags<
enum_flags<ENUM, VALUE_TYPE>> : std::true_type {};
379 template <
typename TYPE>
380 constexpr bool is_enum_flags_v = is_enum_flags<TYPE>::value;
394 template <
integral_or_enum ENUM, detail::val
id_
integral VALUE_TYPE>
395 struct enum_flag_changes
402 using self_type = enum_flag_changes;
406 constexpr enum_flag_changes() noexcept = default;
407 constexpr enum_flag_changes(enum_flag_changes const&) noexcept = default;
408 constexpr enum_flag_changes(enum_flag_changes&&) noexcept = default;
409 constexpr enum_flag_changes& operator=(enum_flag_changes const&) noexcept = default;
410 constexpr enum_flag_changes& operator=(enum_flag_changes&&) noexcept = default;
412 static constexpr self_type no_changes() noexcept {
return self_type{}; }
414 template <std::convertible_to<enum_type>... ARGS>
415 static constexpr self_type to_set(ARGS... args)
noexcept {
return self_type{ flags_type{args...}, flags_type{} }; }
416 static constexpr self_type to_set(flags_type other)
noexcept {
return self_type{ other, flags_type{} }; }
417 static constexpr self_type to_set_all() noexcept {
return self_type{
flags_type::all(), flags_type{}}; }
418 template <std::convertible_to<enum_type>... ARGS>
419 static constexpr self_type to_unset(ARGS... args)
noexcept {
return self_type{ flags_type{}, flags_type{args...} }; }
420 static constexpr self_type to_unset(flags_type other)
noexcept {
return self_type{ flags_type{}, other }; }
421 static constexpr self_type to_unset_all() noexcept {
return self_type{ flags_type{},
flags_type::all() }; }
422 template <std::convertible_to<enum_type>... ARGS>
423 static constexpr self_type to_toggle(ARGS... args)
noexcept {
return self_type{ flags_type{args...}, flags_type{args...} }; }
424 static constexpr self_type to_toggle(flags_type other)
noexcept {
return self_type{ other, other }; }
427 template <std::convertible_to<enum_type>... ARGS>
428 constexpr self_type& set_change_of(
enum_flag_change change, ARGS... args)
noexcept
432 case enum_flag_change::no_change:
return dont_change(args...);
433 case enum_flag_change::set:
return set(args...);
434 case enum_flag_change::unset:
return unset(args...);
435 case enum_flag_change::toggle:
return toggle(args...);
437#if defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L
444 return static_cast<enum_flag_change>(bits_to_set.is_set(flag) * 1 + bits_to_unset.is_set(flag) * 2);
447 constexpr flags_type flags_to_set() const noexcept {
return bits_to_set - bits_to_unset; }
448 constexpr flags_type flags_to_unset() const noexcept {
return bits_to_unset - bits_to_set; }
449 constexpr flags_type flags_to_toggle() const noexcept {
return bits_to_unset.
but_only(bits_to_set); }
450 constexpr flags_type flags_to_not_change() const noexcept {
return -(bits_to_set + bits_to_unset); }
456 case enum_flag_change::set:
return flags_to_set();
457 case enum_flag_change::unset:
return flags_to_unset();
458 case enum_flag_change::toggle:
return flags_to_toggle();
459 case enum_flag_change::no_change:
return flags_to_not_change();
461#if defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L
467 template <std::convertible_to<enum_type>... ARGS>
468 constexpr self_type& set(ARGS... args)
noexcept { bits_to_set.set(args...); bits_to_unset.unset(args...);
return *
this; }
469 constexpr self_type& set(flags_type other)
noexcept { bits_to_set.set(other); bits_to_unset.unset(other);
return *
this; }
471 template <std::convertible_to<enum_type>... ARGS>
472 constexpr self_type& unset(ARGS... args)
noexcept { bits_to_set.unset(args...); bits_to_unset.set(args...);
return *
this; }
473 constexpr self_type& unset(flags_type other)
noexcept { bits_to_set.unset(other); bits_to_unset.set(other);
return *
this; }
475 template <std::convertible_to<enum_type>... ARGS>
476 constexpr self_type& toggle(ARGS... args)
noexcept { bits_to_set.set(args...); bits_to_unset.set(args...);
return *
this; }
477 constexpr self_type& toggle(flags_type other)
noexcept { bits_to_set.set(other); bits_to_unset.set(other);
return *
this; }
479 template <std::convertible_to<enum_type>... ARGS>
480 constexpr self_type& dont_change(ARGS... args)
noexcept { bits_to_set.unset(args...); bits_to_unset.unset(args...);
return *
this; }
481 constexpr self_type& dont_change(flags_type other)
noexcept { bits_to_set.unset(other); bits_to_unset.unset(other);
return *
this; }
483 constexpr self_type& dont_change_any() noexcept { bits_to_set.clear(); bits_to_unset.clear();
return *
this; }
485 constexpr auto operator<=>(self_type
const& other)
const noexcept =
default;
487 flags_type bits_to_set{};
488 flags_type bits_to_unset{};
492 constexpr enum_flag_changes(flags_type to_set, flags_type to_unset) noexcept
493 : bits_to_set(to_set)
494 , bits_to_unset(to_unset)
enum_flag_change
A change to be done to an enum flag in an enum_flags set.
constexpr RESULT_TYPE flag_bits(ARGS... args) noexcept
Takes a list of enum values that represent bit numbers (not actual bit values) and returns a value wi...
auto iterator(T &cont, RANDOM &rng=::ghassanpl::random::default_random_engine)
Returns an iterator to a random element in cont.
Primary namespace for everything in this library.
Holds a set of changes to be made to an enum_flags<ENUM, VALUE_TYPE> - conceptually holds a set of st...
A (constexpr) value struct that represents a set of bits mapped to an enum (implemented as a bitset).
constexpr bool contains_none_of(enum_type arg, ARGS... args) const noexcept
Returns whether or not any of the given flags are set.
static constexpr self_type none() noexcept
Returns a value with none of the bits set.
constexpr enum_flags(enum_type base_value, ARGS... args) noexcept
Constructs the value with all the given flags set.
constexpr self_type & set_to(bool val, self_type other) noexcept
Sets the flags in the other set to val.
constexpr self_type & set(self_type other) noexcept
Sets the flags in the other.
constexpr bool contains(enum_type flag) const noexcept
Same as is_set.
static constexpr self_type all_between(enum_type first, enum_type last) noexcept
Returns a value with bits starting with first, up to and including last, set.
constexpr self_type & unset(ARGS... args) noexcept
Unsets the given flags.
constexpr self_type & toggle(ARGS... args) noexcept
Toggles the given flags.
constexpr bool are_any_set() const noexcept
Returns whether or not any of the given flags are set.
ENUM enum_type
Type of the enum that is the source of the flags.
constexpr enum_type nth_set(size_t n) const noexcept
Returns the value of the nth set bit in the set Preconditions: n must be less than the number of bits...
constexpr self_type & set(ARGS... args) noexcept
Sets the given flags.
constexpr bool contains_all_of(ARGS... args) const noexcept
Returns whether or not all of the given flags are set.
constexpr auto for_each(FUNC &&callback) const
Calls callback for each enum flag in the set.
static constexpr self_type all() noexcept
Returns a value with all bits set (including the ones not in the enum, if any).
static constexpr self_type all(enum_type last) noexcept
Returns a value with all bits set, up to and including the last.
constexpr enum_type to_enum_type() const noexcept
Returns the underlying value representing this set cast to the enum_type.
constexpr enum_type first_set() const noexcept
Returns the lowest numerical value in the set. Returns an unspecified value if no values are in the s...
constexpr self_type & toggle(self_type other) noexcept
Toggles the flags in the other set.
constexpr int count() const noexcept
Returns the number of flags set.
constexpr bool full() const noexcept
Returns whether *this == all().
VALUE_TYPE value_type
The underlying integral value type that holds the bits representing the flags.
constexpr bool contain(enum_type flag) const noexcept
Same as is_set.
constexpr bool is_set(enum_type flag) const noexcept
Returns whether or not flag is set.
constexpr self_type & unset(self_type other) noexcept
Unsets the flags in the other set.
constexpr self_type & set_to(bool val, ARGS... args) noexcept
Sets the given flags to val.
constexpr bool contains_all_of(self_type other) const noexcept
Returns whether or not all of the flags in the other set are set.
constexpr self_type intersected_with(self_type flags) const noexcept
Returns a value with our bits from only the flags that are also set in flags (an intersection).
constexpr self_type but_only(self_type flags) const noexcept
Returns a value with our bits from only the flags that are also set in flags (an intersection).
static constexpr self_type from_bits(BITS_TYPE val) noexcept
Creates the enum_flags set from the given underlying bits.
constexpr enum_type last_set() const noexcept
Returns the highest numerical value in the set, or enum_type(-1) if no values are in the set.
constexpr bool contains_any_of(enum_type arg, ARGS... args) const noexcept
Returns whether or not any of the given flags are set.
constexpr bool contains_any_of(self_type other) const noexcept
Returns whether or not any of the flags in the other set are set.
constexpr auto get(enum_type flag1, enum_type flag2, FLAGS... rest)
Returns an array of bools that are set to the value of contains(param) for each flag parameter Useful...