#pragma once #include #include #include namespace detail { template struct BitFlags { using UnderlyingType = U; using Type = T; constexpr static const UnderlyingType s_validMask = (UnderlyingType{1u << *Type::Count} - UnderlyingType{1}); struct NoneType {}; struct AllType {}; UnderlyingType m_bits; constexpr static const AllType All{}; constexpr static const NoneType None{}; BitFlags() = default; BitFlags(const BitFlags&) = default; constexpr BitFlags(NoneType) : m_bits(0) {} constexpr BitFlags(AllType) : m_bits(s_validMask) {} constexpr explicit BitFlags(UnderlyingType t) : m_bits(s_validMask & t) {} BitFlags& operator=(const BitFlags&) = default; ~BitFlags() = default; constexpr BitFlags(Type t) : m_bits{UnderlyingType{1} << static_cast>(t)} {} constexpr BitFlags& operator|=(BitFlags rhs) { m_bits |= rhs.m_bits; return *this; } constexpr BitFlags& operator&=(BitFlags rhs) { m_bits &= rhs.m_bits; return *this; } constexpr BitFlags& operator-=(BitFlags rhs) { m_bits &= ~rhs.m_bits; return *this; } explicit operator bool() const { return m_bits != 0; } }; template constexpr BitFlags operator|(BitFlags lhs, BitFlags rhs) { lhs |= rhs; return lhs; } template constexpr BitFlags operator&(BitFlags lhs, BitFlags rhs) { lhs &= rhs; return lhs; } template constexpr BitFlags operator-(BitFlags lhs, BitFlags rhs) { lhs -= rhs; return lhs; } template constexpr BitFlags operator-(BitFlags lhs, T rhs) { lhs -= rhs; return lhs; } template constexpr BitFlags operator-(T lhs, BitFlags rhs) { rhs -= lhs; return rhs; } template constexpr BitFlags operator|(BitFlags lhs, T rhs) { lhs |= rhs; return lhs; } template constexpr BitFlags operator|(T lhs, BitFlags rhs) { rhs |= lhs; return rhs; } template constexpr bool operator&(BitFlags lhs, T rhs) { lhs &= rhs; return lhs.m_bits != 0; } template constexpr bool operator&(T lhs, BitFlags rhs) { rhs &= lhs; return rhs.m_bits != 0; } template struct FlagType; template using FlagTypeT = typename FlagType::Type; template struct EnumArray; } // namespace detail #define DEFINE_FLAGS_UT(TypeName, UnderlyingType) \ using TypeName##s = detail::BitFlags; \ constexpr TypeName##s operator|(TypeName lhs, TypeName rhs) { return TypeName##s{lhs} | TypeName##s{rhs}; } \ namespace detail \ { \ template<> struct FlagType \ { \ using Type = TypeName##s; \ }; \ } #define DEFINE_FLAGS(TypeName) DEFINE_FLAGS_UT(TypeName, uint32_t) #define ENUM_X(type, e, y) e, #define ENUM_QUAL_X(type, e, y) type::e, #define ENUM_NAME_PAIR(type, e, y) {type::e, y}, #define CASE_X(type, e, y) \ case type::e: \ return y; #define DEFINE_ENUM_CLASS_TYPE(Name, Type) \ enum class Name : Type \ { \ ENUM_CLASS_##Name(Name, ENUM_X) Count \ }; \ constexpr auto operator*(Name t) { return static_cast>(t); } \ namespace detail \ { \ template<> struct EnumArray \ { \ constexpr static const std::array, *Name::Count> values{ \ {ENUM_CLASS_##Name(Name, ENUM_NAME_PAIR)}}; \ }; \ } \ constexpr const char* toString(Name t) \ { \ if(t < Name::Count) \ { \ return detail::EnumArray::values[*t].second; \ } \ return "UNKNWON"; \ } \ DEFINE_FLAGS_UT(Name, Type) #define DEFINE_ENUM_CLASS(Name) DEFINE_ENUM_CLASS_TYPE(Name, uint32_t)