|
| 1 | +#pragma once |
| 2 | +#include "enum19/Enum.h" |
| 3 | +#include "enum19/Enum.max.h" |
| 4 | + |
| 5 | +#include <stdint.h> // int64_t, uint64_t |
| 6 | + |
| 7 | +namespace flags19 { |
| 8 | + |
| 9 | +using enum19::HasMetaEnum; |
| 10 | +using enum19::max_underlying_value_of; |
| 11 | +using enum19::meta_enum_for; |
| 12 | + |
| 13 | +namespace details { |
| 14 | + |
| 15 | +template<size_t maxBit> constexpr auto storageTypeForMaxBit() { |
| 16 | + if constexpr (maxBit <= sizeof(uint8_t)) { |
| 17 | + return uint8_t{}; |
| 18 | + } |
| 19 | + else if constexpr (maxBit <= sizeof(uint16_t)) { |
| 20 | + return uint16_t{}; |
| 21 | + } |
| 22 | + else if constexpr (maxBit <= sizeof(uint32_t)) { |
| 23 | + return uint32_t{}; |
| 24 | + } |
| 25 | + else if constexpr (maxBit <= sizeof(uint64_t)) { |
| 26 | + return uint64_t{}; |
| 27 | + } |
| 28 | + else { |
| 29 | + static_assert(maxBit > sizeof(uint64_t), "not supported right now"); |
| 30 | + } |
| 31 | +} |
| 32 | + |
| 33 | +} // namespace details |
| 34 | + |
| 35 | +template<HasMetaEnum Enum> struct FlagsOf { |
| 36 | + using UnderlyingBit = std::underlying_type_t<Enum>; |
| 37 | + using Value = decltype(details::storageTypeForMaxBit<max_underlying_value_of<Enum>>()); |
| 38 | + |
| 39 | + constexpr FlagsOf() = default; |
| 40 | + explicit constexpr FlagsOf(Value const& value) : m_value{value} {} |
| 41 | + |
| 42 | + template<class... Args> requires((sizeof...(Args) > 0) && ... && std::is_same_v<Args, Enum>) |
| 43 | + explicit constexpr FlagsOf(Args... args) : FlagsOf{((1U << static_cast<UnderlyingBit>(args)) | ...)} {} |
| 44 | + |
| 45 | + auto operator==(FlagsOf const&) const -> bool = default; |
| 46 | + |
| 47 | + explicit operator Value() const { return m_value; } |
| 48 | + |
| 49 | + [[nodiscard]] constexpr auto operator[](Enum bit) const noexcept -> bool { |
| 50 | + return 0U != (m_value & (1U << static_cast<UnderlyingBit>(bit))); |
| 51 | + } |
| 52 | + |
| 53 | + template<class... Args> requires((sizeof...(Args) > 0) && ... && std::is_same_v<Args, Enum>) |
| 54 | + constexpr auto allOf(Args... args) const -> bool { |
| 55 | + auto const mask = ((1U << static_cast<UnderlyingBit>(args)) | ...); |
| 56 | + return mask == (m_value & mask); |
| 57 | + } |
| 58 | + |
| 59 | + template<class... Args> requires((sizeof...(Args) > 0) && ... && std::is_same_v<Args, Enum>) |
| 60 | + constexpr auto someOf(Args... args) const -> bool { |
| 61 | + auto const mask = ((1U << static_cast<UnderlyingBit>(args)) | ...); |
| 62 | + return 0U != (m_value & mask); |
| 63 | + } |
| 64 | + |
| 65 | + template<class... Args> requires((sizeof...(Args) > 0) && ... && std::is_same_v<Args, Enum>) |
| 66 | + constexpr auto noneOf(Args... args) const -> bool { |
| 67 | + auto const mask = ((1U << static_cast<UnderlyingBit>(args)) | ...); |
| 68 | + return 0U == (m_value & mask); |
| 69 | + } |
| 70 | + |
| 71 | + constexpr void resetAll() { m_value = {}; } |
| 72 | + |
| 73 | + template<class... Args> requires((sizeof...(Args) > 0) && ... && std::is_same_v<Args, Enum>) |
| 74 | + constexpr void set(Args... args) { |
| 75 | + m_value |= ((1U << static_cast<UnderlyingBit>(args)) | ...); |
| 76 | + } |
| 77 | + |
| 78 | + template<class... Args> requires((sizeof...(Args) > 0) && ... && std::is_same_v<Args, Enum>) |
| 79 | + constexpr void reset(Args... args) { |
| 80 | + m_value &= ~static_cast<Value>(((1U << static_cast<UnderlyingBit>(args)) | ...)); |
| 81 | + } |
| 82 | + |
| 83 | + template<class... Args> requires((sizeof...(Args) > 0) && ... && std::is_same_v<Args, Enum>) |
| 84 | + constexpr void toggle(Args... args) { |
| 85 | + m_value ^= ((1U << static_cast<UnderlyingBit>(args)) | ...); |
| 86 | + } |
| 87 | + |
| 88 | + constexpr auto operator|(FlagsOf const& other) const -> FlagsOf { return FlagsOf{m_value | other.m_value}; } |
| 89 | + constexpr auto operator&(FlagsOf const& other) const -> FlagsOf { return FlagsOf{m_value & other.m_value}; } |
| 90 | + constexpr auto operator|=(FlagsOf const& other) -> FlagsOf& { return m_value |= other.m_value, *this; } |
| 91 | + constexpr auto operator&=(FlagsOf const& other) -> FlagsOf& { return m_value &= other.m_value, *this; } |
| 92 | + |
| 93 | +private: |
| 94 | + Value m_value{}; |
| 95 | +}; |
| 96 | + |
| 97 | +} // namespace flags19 |
0 commit comments