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

@ -10,7 +10,7 @@ Nazara Engine:
- Fix reflection sometimes being enabled by default for Materials
- Fix built-in unserialization of std::string which was corruption memory
- Fix Buffer::Destroy() not really destroying buffer
- ⚠️ Reworked Flags class, replaced EnumAsFlags<E>::value by IsEnumFlag<E>::value, EnumAsFlags<E> no longer need to contains a `value` field. The `max` field can also be of the same type as the enum.
Nazara Development Kit:
- Added ImageWidget (#139)

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

View File

@ -70,21 +70,21 @@ namespace Nz
}
template<typename T>
std::enable_if_t<std::is_enum<T>::value && !EnumAsFlags<T>::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, TypeTag<T>)
std::enable_if_t<std::is_enum<T>::value && !IsEnumFlag<T>::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, TypeTag<T>)
{
using UnderlyingT = std::underlying_type_t<T>;
return LuaImplQueryArg(instance, index, reinterpret_cast<UnderlyingT*>(arg), TypeTag<UnderlyingT>());
}
template<typename T>
std::enable_if_t<std::is_enum<T>::value && !EnumAsFlags<T>::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, T defValue, TypeTag<T>)
std::enable_if_t<std::is_enum<T>::value && !IsEnumFlag<T>::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, T defValue, TypeTag<T>)
{
using UnderlyingT = std::underlying_type_t<T>;
return LuaImplQueryArg(instance, index, reinterpret_cast<UnderlyingT*>(arg), static_cast<UnderlyingT>(defValue), TypeTag<UnderlyingT>());
}
template<typename T>
std::enable_if_t<std::is_enum<T>::value && EnumAsFlags<T>::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, TypeTag<T>)
std::enable_if_t<std::is_enum<T>::value && IsEnumFlag<T>::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, TypeTag<T>)
{
using UnderlyingT = std::underlying_type_t<T>;
@ -96,7 +96,7 @@ namespace Nz
}
template<typename T>
std::enable_if_t<std::is_enum<T>::value && EnumAsFlags<T>::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, T defValue, TypeTag<T>)
std::enable_if_t<std::is_enum<T>::value && IsEnumFlag<T>::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, T defValue, TypeTag<T>)
{
using UnderlyingT = std::underlying_type_t<T>;
@ -186,14 +186,14 @@ namespace Nz
}
template<typename T>
std::enable_if_t<std::is_enum<T>::value && !EnumAsFlags<T>::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag<T>)
std::enable_if_t<std::is_enum<T>::value && !IsEnumFlag<T>::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag<T>)
{
using EnumT = typename std::underlying_type<T>::type;
return LuaImplReplyVal(instance, static_cast<EnumT>(val), TypeTag<EnumT>());
}
template<typename T>
std::enable_if_t<std::is_enum<T>::value && EnumAsFlags<T>::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag<T>)
std::enable_if_t<std::is_enum<T>::value && IsEnumFlag<T>::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag<T>)
{
Flags<T> flags(val);
return LuaImplReplyVal(instance, flags, TypeTag<decltype(flags)>());
@ -202,7 +202,7 @@ namespace Nz
template<typename E>
int LuaImplReplyVal(const LuaState& instance, Flags<E> val, TypeTag<Flags<E>>)
{
instance.PushInteger(UInt32(val));
instance.PushInteger(Flags<E>::BitField(val));
return 1;
}

View File

@ -22,8 +22,7 @@ namespace Nz
template<>
struct EnumAsFlags<ENetPacketFlag>
{
static constexpr bool value = true;
static constexpr int max = ENetPacketFlag_UnreliableFragment;
static constexpr ENetPacketFlag max = ENetPacketFlag_UnreliableFragment;
};
using ENetPacketFlags = Flags<ENetPacketFlag>;

View File

@ -102,8 +102,7 @@ namespace Nz
template<>
struct EnumAsFlags<SocketPollEvent>
{
static constexpr bool value = true;
static constexpr int max = SocketPollEvent_Max;
static constexpr SocketPollEvent max = SocketPollEvent_Max;
};
using SocketPollEventFlags = Flags<SocketPollEvent>;

View File

@ -73,8 +73,7 @@ namespace Nz
template<>
struct EnumAsFlags<WindowStyle>
{
static constexpr bool value = true;
static constexpr int max = WindowStyle_Max;
static constexpr WindowStyle max = WindowStyle_Max;
};
using WindowStyleFlags = Flags<WindowStyle>;

View File

@ -64,8 +64,7 @@ namespace Nz
template<>
struct EnumAsFlags<BufferUsage>
{
static constexpr bool value = true;
static constexpr int max = BufferUsage_Max;
static constexpr BufferUsage max = BufferUsage_Max;
};
using BufferUsageFlags = Flags<BufferUsage>;

View File

@ -69,12 +69,12 @@ namespace Nz
std::vector<Frame> m_frames;
std::vector<Joint> m_joints;
Stream& m_stream;
StreamOptionFlags m_streamFlags;
String m_currentLine;
bool m_keepLastLine;
unsigned int m_frameIndex;
unsigned int m_frameRate;
unsigned int m_lineCount;
unsigned int m_streamFlags;
};
}

View File

@ -75,11 +75,11 @@ namespace Nz
std::vector<Joint> m_joints;
std::vector<Mesh> m_meshes;
Stream& m_stream;
StreamOptionFlags m_streamFlags;
String m_currentLine;
bool m_keepLastLine;
unsigned int m_lineCount;
unsigned int m_meshIndex;
unsigned int m_streamFlags;
};
}

View File

@ -12,11 +12,11 @@ namespace Nz
{
MD5AnimParser::MD5AnimParser(Stream& stream) :
m_stream(stream),
m_streamFlags(stream.GetStreamOptions()), //< Saves stream flags
m_keepLastLine(false),
m_frameIndex(0),
m_frameRate(0),
m_lineCount(0),
m_streamFlags(stream.GetStreamOptions()) //< Saves stream flags
m_lineCount(0)
{
m_stream.EnableTextMode(true);
}

View File

@ -13,10 +13,10 @@ namespace Nz
{
MD5MeshParser::MD5MeshParser(Stream& stream) :
m_stream(stream),
m_streamFlags(stream.GetStreamOptions()), //< Saves stream flags
m_keepLastLine(false),
m_lineCount(0),
m_meshIndex(0),
m_streamFlags(stream.GetStreamOptions()) //< Saves stream flags
m_meshIndex(0)
{
m_stream.EnableTextMode(true);
}