Core/Flags: Reworked Flags class

This commit is contained in:
Jérôme Leclercq
2017-11-21 12:26:22 +01:00
parent f2506ee918
commit 3589a2bc8e
13 changed files with 49 additions and 39 deletions

View File

@@ -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>;

View File

@@ -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;

View File

@@ -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;
}