/** * @file enum_traits.h * * Base template for 'enum_traits' which allow us to access static information about an enum. */ #pragma once #include #include namespace devilution { template struct enum_size { constexpr static const std::size_t value = static_cast(T::LAST) + 1; }; template class enum_values { public: class Iterator { typename std::underlying_type::type m_value; public: Iterator(typename std::underlying_type::type value) : m_value(value) { } const T operator*() const { return static_cast(m_value); } void operator++() { m_value++; } bool operator!=(Iterator rhs) const { return m_value != rhs.m_value; } }; }; template typename enum_values::Iterator begin(enum_values) { return typename enum_values::Iterator(static_cast::type>(T::FIRST)); } template typename enum_values::Iterator end(enum_values) { return typename enum_values::Iterator(static_cast::type>(T::LAST) + 1); } template struct is_flags_enum : std::false_type { }; #define use_enum_as_flags(Type) \ template <> \ struct is_flags_enum : std::true_type { \ }; template ::value && is_flags_enum::value, bool> = true> constexpr EnumType operator|(EnumType lhs, EnumType rhs) { using T = std::underlying_type_t; return static_cast(static_cast(lhs) | static_cast(rhs)); } template ::value && is_flags_enum::value, bool> = true> constexpr EnumType operator|=(EnumType &lhs, EnumType rhs) { lhs = lhs | rhs; return lhs; } template ::value && is_flags_enum::value, bool> = true> constexpr EnumType operator&(EnumType lhs, EnumType rhs) { using T = std::underlying_type_t; return static_cast(static_cast(lhs) & static_cast(rhs)); } template ::value && is_flags_enum::value, bool> = true> constexpr EnumType operator&=(EnumType &lhs, EnumType rhs) { lhs = lhs & rhs; return lhs; } template ::value && is_flags_enum::value, bool> = true> constexpr EnumType operator~(EnumType value) { using T = std::underlying_type_t; return static_cast(~static_cast(value)); } template ::value && is_flags_enum::value, bool> = true> constexpr bool HasAnyOf(EnumType lhs, EnumType test) { return (lhs & test) != static_cast(0); // Some flags enums may not use a None value outside this check so we don't require an EnumType::None definition here. } template ::value && is_flags_enum::value, bool> = true> constexpr bool HasNoneOf(EnumType lhs, EnumType test) { return !HasAnyOf(lhs, test); } } // namespace devilution