Core/Flags: Reworked Flags class
This commit is contained in:
@@ -94,8 +94,7 @@ namespace Nz
|
||||
template<>
|
||||
struct EnumAsFlags<OpenMode>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
static constexpr int max = OpenMode_Max;
|
||||
static constexpr OpenMode max = OpenMode_Max;
|
||||
};
|
||||
|
||||
using OpenModeFlags = Flags<OpenMode>;
|
||||
@@ -198,8 +197,7 @@ namespace Nz
|
||||
template<>
|
||||
struct EnumAsFlags<StreamOption>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
static constexpr int max = StreamOption_Max;
|
||||
static constexpr StreamOption max = StreamOption_Max;
|
||||
};
|
||||
|
||||
using StreamOptionFlags = Flags<StreamOption>;
|
||||
|
||||
@@ -16,18 +16,34 @@ namespace Nz
|
||||
template<typename E>
|
||||
struct EnumAsFlags
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
static constexpr int max = 0;
|
||||
};
|
||||
|
||||
// From: https://stackoverflow.com/questions/11927032/sfinae-check-for-static-member-using-decltype
|
||||
template <typename T>
|
||||
class IsEnumFlag
|
||||
{
|
||||
template<typename U, typename = typename std::enable_if<!std::is_member_pointer<decltype(&EnumAsFlags<U>::max)>::value>::type>
|
||||
static std::true_type check(int);
|
||||
|
||||
template <typename> static std::false_type check(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(check<T>(0))::value;
|
||||
};
|
||||
|
||||
template<typename E>
|
||||
class Flags
|
||||
{
|
||||
static_assert(std::is_enum<E>::value, "Type must be an enumeration");
|
||||
static_assert(EnumAsFlags<E>::value, "Enum has not been enabled as flags by an EnumAsFlags specialization");
|
||||
static_assert(IsEnumFlag<E>::value, "Enum has not been enabled as flags by an EnumAsFlags specialization");
|
||||
|
||||
static constexpr std::size_t MaxValue = static_cast<std::size_t>(EnumAsFlags<E>::max);
|
||||
|
||||
using BitField16 = typename std::conditional<(MaxValue > 8), UInt16, UInt8>::type;
|
||||
using BitField32 = typename std::conditional<(MaxValue > 16), UInt32, BitField16>::type;
|
||||
|
||||
public:
|
||||
using BitField = typename std::conditional<(EnumAsFlags<E>::max > 32), UInt64, UInt32>::type;
|
||||
using BitField = typename std::conditional<(MaxValue > 32), UInt64, BitField32>::type;
|
||||
|
||||
constexpr Flags(BitField value = 0);
|
||||
constexpr Flags(E enumVal);
|
||||
@@ -49,7 +65,7 @@ namespace Nz
|
||||
|
||||
static constexpr BitField GetFlagValue(E enumValue);
|
||||
|
||||
static constexpr BitField ValueMask = ((BitField(1) << (EnumAsFlags<E>::max + 1)) - 1);
|
||||
static constexpr BitField ValueMask = ((BitField(1) << (MaxValue + 1)) - 1);
|
||||
|
||||
private:
|
||||
BitField m_value;
|
||||
@@ -58,10 +74,10 @@ namespace Nz
|
||||
// Little hack to have them in both Nz and global scope
|
||||
namespace FlagsOperators
|
||||
{
|
||||
template<typename E> constexpr std::enable_if_t<EnumAsFlags<E>::value, Flags<E>> operator~(E lhs);
|
||||
template<typename E> constexpr std::enable_if_t<EnumAsFlags<E>::value, Flags<E>> operator|(E lhs, E rhs);
|
||||
template<typename E> constexpr std::enable_if_t<EnumAsFlags<E>::value, Flags<E>> operator&(E lhs, E rhs);
|
||||
template<typename E> constexpr std::enable_if_t<EnumAsFlags<E>::value, Flags<E>> operator^(E lhs, E rhs);
|
||||
template<typename E> constexpr std::enable_if_t<IsEnumFlag<E>::value, Flags<E>> operator~(E lhs);
|
||||
template<typename E> constexpr std::enable_if_t<IsEnumFlag<E>::value, Flags<E>> operator|(E lhs, E rhs);
|
||||
template<typename E> constexpr std::enable_if_t<IsEnumFlag<E>::value, Flags<E>> operator&(E lhs, E rhs);
|
||||
template<typename E> constexpr std::enable_if_t<IsEnumFlag<E>::value, Flags<E>> operator^(E lhs, E rhs);
|
||||
}
|
||||
|
||||
using namespace FlagsOperators;
|
||||
|
||||
@@ -222,7 +222,7 @@ namespace Nz
|
||||
* Returns a Flags object with all state enabled except for the enum one.
|
||||
*/
|
||||
template<typename E>
|
||||
constexpr std::enable_if_t<EnumAsFlags<E>::value, Flags<E>> operator~(E lhs)
|
||||
constexpr std::enable_if_t<IsEnumFlag<E>::value, Flags<E>> operator~(E lhs)
|
||||
{
|
||||
return ~Flags<E>(lhs);
|
||||
}
|
||||
@@ -237,7 +237,7 @@ namespace Nz
|
||||
* Returns a Flags object with combined states from the two enumeration values.
|
||||
*/
|
||||
template<typename E>
|
||||
constexpr std::enable_if_t<EnumAsFlags<E>::value, Flags<E>> operator|(E lhs, E rhs)
|
||||
constexpr std::enable_if_t<IsEnumFlag<E>::value, Flags<E>> operator|(E lhs, E rhs)
|
||||
{
|
||||
return Flags<E>(lhs) | rhs;
|
||||
}
|
||||
@@ -253,7 +253,7 @@ namespace Nz
|
||||
* In this case, only one flag will be enabled if both enumeration values are the same.
|
||||
*/
|
||||
template<typename E>
|
||||
constexpr std::enable_if_t<EnumAsFlags<E>::value, Flags<E>> operator&(E lhs, E rhs)
|
||||
constexpr std::enable_if_t<IsEnumFlag<E>::value, Flags<E>> operator&(E lhs, E rhs)
|
||||
{
|
||||
return Flags<E>(lhs) & rhs;
|
||||
}
|
||||
@@ -269,7 +269,7 @@ namespace Nz
|
||||
* In this case, two flags will be enabled if both the enumeration values are different.
|
||||
*/
|
||||
template<typename E>
|
||||
constexpr std::enable_if_t<EnumAsFlags<E>::value, Flags<E>> operator^(E lhs, E rhs)
|
||||
constexpr std::enable_if_t<IsEnumFlag<E>::value, Flags<E>> operator^(E lhs, E rhs)
|
||||
{
|
||||
return Flags<E>(lhs) ^ rhs;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user