mirror of
https://github.com/aantron/better-enums.git
synced 2025-12-06 08:46:42 +08:00
Used explicit inline functions to simplify type hierarchy, also simplified iterables names.
This commit is contained in:
parent
d0e4d9ffaa
commit
156b9d9b04
383
enum.h
383
enum.h
@ -153,7 +153,7 @@
|
||||
|
||||
|
||||
#define _ENUM_EAT_ASSIGN_SINGLE(EnumType, index, expression) \
|
||||
((_enum::_eat_assign<EnumType>)Base::expression),
|
||||
((_enum::_eat_assign<EnumType>)EnumType::expression),
|
||||
|
||||
#define _ENUM_EAT_ASSIGN(EnumType, ...) \
|
||||
_ENUM_PP_MAP(_ENUM_EAT_ASSIGN_SINGLE, EnumType, __VA_ARGS__)
|
||||
@ -393,206 +393,222 @@ inline void _trim_names(const char * const *raw_names,
|
||||
|
||||
|
||||
#define _ENUM_TYPE(SetUnderlyingType, DisableDefault, SwitchType, \
|
||||
GenerateSwitchType, ShortIterableDeclarations, \
|
||||
ShortIterableAliases, GenerateStrings, DefineInitialize, \
|
||||
CallInitialize, \
|
||||
GenerateSwitchType, GenerateStrings, DeclareInitialize, \
|
||||
DefineInitialize, CallInitialize, \
|
||||
Enum, Integral, ...) \
|
||||
\
|
||||
namespace _enum { \
|
||||
namespace _data_ ## Enum { \
|
||||
\
|
||||
struct Base { \
|
||||
enum _enumerated SetUnderlyingType(Integral) { __VA_ARGS__ }; \
|
||||
\
|
||||
_ENUM_CONSTEXPR Base(_enumerated value) : _value(value) { } \
|
||||
\
|
||||
Integral _value; \
|
||||
}; \
|
||||
\
|
||||
enum PutNamesInThisScopeAlso { __VA_ARGS__ }; \
|
||||
\
|
||||
_ENUM_CONSTEXPR const Base value_array[] = \
|
||||
{ _ENUM_EAT_ASSIGN(Base, __VA_ARGS__) }; \
|
||||
\
|
||||
_ENUM_CONSTEXPR const size_t size = sizeof(value_array) / sizeof(Base); \
|
||||
\
|
||||
GenerateSwitchType(Integral, __VA_ARGS__); \
|
||||
\
|
||||
GenerateStrings(__VA_ARGS__) \
|
||||
\
|
||||
ShortIterableDeclarations \
|
||||
\
|
||||
} \
|
||||
} \
|
||||
\
|
||||
class Enum : public _ENUM_NS(Enum)::Base { \
|
||||
class Enum { \
|
||||
protected: \
|
||||
typedef better_enums::optional<Enum> _optional; \
|
||||
typedef better_enums::optional<size_t> _optional_index; \
|
||||
\
|
||||
public: \
|
||||
enum _enumerated SetUnderlyingType(Integral) { __VA_ARGS__ }; \
|
||||
typedef Integral _integral; \
|
||||
\
|
||||
_ENUM_CONSTEXPR Enum(_enumerated value) : Base(value) { } \
|
||||
_ENUM_CONSTEXPR Enum(_ENUM_NS(Enum)::Base value) : Base(value) { } \
|
||||
\
|
||||
_ENUM_CONSTEXPR _integral _to_integral() const \
|
||||
{ \
|
||||
return _value; \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR static const _optional \
|
||||
_from_integral_nothrow(_integral value) \
|
||||
{ \
|
||||
return \
|
||||
_enum::_map_index<Enum>(_ENUM_NS(Enum)::value_array, \
|
||||
_from_int_loop(value)); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR static const Enum _from_integral(_integral value) \
|
||||
{ \
|
||||
return \
|
||||
_enum::_or_throw(_from_integral_nothrow(value), \
|
||||
"Enum::_from_integral: invalid argument"); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR static const Enum _from_integral_unchecked(_integral value)\
|
||||
{ \
|
||||
return (_enumerated)value; \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR const char* _to_string() const \
|
||||
{ \
|
||||
return \
|
||||
_enum::_or_throw( \
|
||||
_enum::_map_index<const char*>( \
|
||||
_ENUM_NS(Enum)::name_array(), \
|
||||
_from_int_loop(CallInitialize(_value))), \
|
||||
"Enum::to_string: invalid enum value"); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR static const _optional \
|
||||
_from_string_nothrow(const char *name) \
|
||||
{ \
|
||||
return \
|
||||
_enum::_map_index<Enum>( \
|
||||
_ENUM_NS(Enum)::value_array, _from_string_loop(name)); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR static const Enum _from_string(const char *name) \
|
||||
{ \
|
||||
return \
|
||||
_enum::_or_throw(_from_string_nothrow(name), \
|
||||
"Enum::_from_string: invalid argument"); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR static const _optional \
|
||||
_from_string_nocase_nothrow(const char *name) \
|
||||
{ \
|
||||
return \
|
||||
_enum::_map_index<Enum>(_ENUM_NS(Enum)::value_array, \
|
||||
_from_string_nocase_loop(name)); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR static const Enum _from_string_nocase(const char *name) \
|
||||
{ \
|
||||
return \
|
||||
_enum::_or_throw(_from_string_nocase_nothrow(name), \
|
||||
"Enum::_from_string_nocase: invalid argument"); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR static bool _is_valid(_integral value) \
|
||||
{ \
|
||||
return _from_int_loop(value); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR static bool _is_valid(const char *name) \
|
||||
{ \
|
||||
return _from_string_loop(name); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR static bool _is_valid_nocase(const char *name) \
|
||||
{ \
|
||||
return _from_string_nocase_loop(name); \
|
||||
} \
|
||||
_ENUM_CONSTEXPR Enum(_enumerated value) : _value(value) { } \
|
||||
\
|
||||
_ENUM_CONSTEXPR operator SwitchType(Enum)() const \
|
||||
{ \
|
||||
return (SwitchType(Enum))_value; \
|
||||
} \
|
||||
\
|
||||
typedef _enum::_Iterable<_ENUM_NS(Enum)::Base> _value_iterable; \
|
||||
typedef _enum::_Iterable<const char*> _name_iterable; \
|
||||
_ENUM_CONSTEXPR _integral _to_integral() const; \
|
||||
_ENUM_CONSTEXPR static Enum _from_integral(_integral value); \
|
||||
_ENUM_CONSTEXPR static Enum _from_integral_unchecked(_integral value); \
|
||||
_ENUM_CONSTEXPR static _optional _from_integral_nothrow(_integral value); \
|
||||
\
|
||||
typedef _value_iterable::iterator _value_iterator; \
|
||||
typedef _name_iterable::iterator _name_iterator; \
|
||||
_ENUM_CONSTEXPR const char* _to_string() const; \
|
||||
_ENUM_CONSTEXPR static Enum _from_string(const char *name); \
|
||||
_ENUM_CONSTEXPR static _optional _from_string_nothrow(const char *name); \
|
||||
\
|
||||
_ENUM_CONSTEXPR static const size_t _size = _ENUM_NS(Enum)::size; \
|
||||
_ENUM_CONSTEXPR static Enum _from_string_nocase(const char *name); \
|
||||
_ENUM_CONSTEXPR static _optional \
|
||||
_from_string_nocase_nothrow(const char *name); \
|
||||
\
|
||||
_ENUM_CONSTEXPR static const char* _name_() \
|
||||
{ \
|
||||
return #Enum; \
|
||||
} \
|
||||
_ENUM_CONSTEXPR static bool _is_valid(_integral value); \
|
||||
_ENUM_CONSTEXPR static bool _is_valid(const char *name); \
|
||||
_ENUM_CONSTEXPR static bool _is_valid_nocase(const char *name); \
|
||||
\
|
||||
_ENUM_CONSTEXPR static _value_iterable _values_() \
|
||||
{ \
|
||||
return _value_iterable(_ENUM_NS(Enum)::value_array, _size); \
|
||||
} \
|
||||
typedef _enum::_Iterable<Enum> _value_iterable; \
|
||||
typedef _enum::_Iterable<const char*> _name_iterable; \
|
||||
\
|
||||
_ENUM_CONSTEXPR static _name_iterable _names_() \
|
||||
{ \
|
||||
return \
|
||||
_name_iterable(_ENUM_NS(Enum)::name_array(), \
|
||||
CallInitialize(_size)); \
|
||||
} \
|
||||
typedef _value_iterable::iterator _value_iterator; \
|
||||
typedef _name_iterable::iterator _name_iterator; \
|
||||
\
|
||||
ShortIterableAliases(Enum) \
|
||||
_ENUM_CONSTEXPR static const size_t _size = _ENUM_PP_COUNT(__VA_ARGS__); \
|
||||
\
|
||||
_ENUM_CONSTEXPR static const char* _name(); \
|
||||
_ENUM_CONSTEXPR static _value_iterable _values(); \
|
||||
_ENUM_CONSTEXPR static _name_iterable _names(); \
|
||||
\
|
||||
_integral _value; \
|
||||
\
|
||||
DisableDefault(Enum) \
|
||||
\
|
||||
protected: \
|
||||
DefineInitialize(Enum) \
|
||||
DeclareInitialize \
|
||||
\
|
||||
_ENUM_CONSTEXPR static _optional_index \
|
||||
_from_int_loop(_integral value, size_t index = 0) \
|
||||
{ \
|
||||
return \
|
||||
index == _size ? _optional_index() : \
|
||||
_ENUM_NS(Enum)::value_array[index]._value == value ? \
|
||||
_optional_index(index) : \
|
||||
_from_int_loop(value, index + 1); \
|
||||
} \
|
||||
\
|
||||
_from_int_loop(_integral value, size_t index = 0); \
|
||||
_ENUM_CONSTEXPR static _optional_index \
|
||||
_from_string_loop(const char *name, size_t index = 0) \
|
||||
{ \
|
||||
return \
|
||||
index == _size ? _optional_index() : \
|
||||
_enum::_namesMatch(_ENUM_NS(Enum)::name_array()[index], name) ? \
|
||||
_optional_index(index) : \
|
||||
_from_string_loop(name, index + 1); \
|
||||
} \
|
||||
\
|
||||
_from_string_loop(const char *name, size_t index = 0); \
|
||||
_ENUM_CONSTEXPR static _optional_index \
|
||||
_from_string_nocase_loop(const char *name, size_t index = 0) \
|
||||
{ \
|
||||
return \
|
||||
index == _size ? _optional_index() : \
|
||||
_enum::_namesMatchNocase( \
|
||||
_ENUM_NS(Enum)::name_array()[index], name) ? \
|
||||
_optional_index(index) : \
|
||||
_from_string_nocase_loop(name, index + 1); \
|
||||
} \
|
||||
_from_string_nocase_loop(const char *name, size_t index = 0); \
|
||||
}; \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline const Enum operator +(Enum::_enumerated enumerated) \
|
||||
{ return (Enum)enumerated; } \
|
||||
\
|
||||
namespace _enum { \
|
||||
namespace _data_ ## Enum { \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline const Enum operator +(_ENUM_NS(Enum)::Base base) \
|
||||
{ return (Enum)base; } \
|
||||
enum PutNamesInThisScopeAlso { __VA_ARGS__ }; \
|
||||
\
|
||||
_ENUM_CONSTEXPR const Enum value_array[] = \
|
||||
{ _ENUM_EAT_ASSIGN(Enum, __VA_ARGS__) }; \
|
||||
\
|
||||
GenerateStrings(Enum, __VA_ARGS__) \
|
||||
\
|
||||
} \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline const Enum operator +(Enum::_enumerated enumerated) \
|
||||
{ return (Enum)enumerated; } \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline Enum::_integral Enum::_to_integral() const \
|
||||
{ \
|
||||
return _value; \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline Enum \
|
||||
Enum::_from_integral_unchecked(Enum::_integral value) \
|
||||
{ \
|
||||
return (_enumerated)value; \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline Enum Enum::_from_integral(Enum::_integral value) \
|
||||
{ \
|
||||
return \
|
||||
_enum::_or_throw(_from_integral_nothrow(value), \
|
||||
"Enum::_from_integral: invalid argument"); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline Enum::_optional \
|
||||
Enum::_from_integral_nothrow(Enum::_integral value) \
|
||||
{ \
|
||||
return \
|
||||
_enum::_map_index<Enum>(_ENUM_NS(Enum)::value_array, \
|
||||
_from_int_loop(value)); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline const char* Enum::_to_string() const \
|
||||
{ \
|
||||
return \
|
||||
_enum::_or_throw( \
|
||||
_enum::_map_index<const char*>( \
|
||||
_ENUM_NS(Enum)::name_array(), \
|
||||
_from_int_loop(CallInitialize(_value))), \
|
||||
"Enum::to_string: invalid enum value"); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline Enum Enum::_from_string(const char *name) \
|
||||
{ \
|
||||
return \
|
||||
_enum::_or_throw(_from_string_nothrow(name), \
|
||||
"Enum::_from_string: invalid argument"); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline Enum::_optional \
|
||||
Enum::_from_string_nothrow(const char *name) \
|
||||
{ \
|
||||
return \
|
||||
_enum::_map_index<Enum>( \
|
||||
_ENUM_NS(Enum)::value_array, _from_string_loop(name)); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline Enum Enum::_from_string_nocase(const char *name) \
|
||||
{ \
|
||||
return \
|
||||
_enum::_or_throw(_from_string_nocase_nothrow(name), \
|
||||
"Enum::_from_string_nocase: invalid argument"); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline Enum::_optional \
|
||||
Enum::_from_string_nocase_nothrow(const char *name) \
|
||||
{ \
|
||||
return \
|
||||
_enum::_map_index<Enum>(_ENUM_NS(Enum)::value_array, \
|
||||
_from_string_nocase_loop(name)); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline bool Enum::_is_valid(Enum::_integral value) \
|
||||
{ \
|
||||
return _from_int_loop(value); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline bool Enum::_is_valid(const char *name) \
|
||||
{ \
|
||||
return _from_string_loop(name); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline bool Enum::_is_valid_nocase(const char *name) \
|
||||
{ \
|
||||
return _from_string_nocase_loop(name); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline const char* Enum::_name() \
|
||||
{ \
|
||||
return #Enum; \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline Enum::_value_iterable Enum::_values() \
|
||||
{ \
|
||||
return _value_iterable(_ENUM_NS(Enum)::value_array, _size); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline Enum::_name_iterable Enum::_names() \
|
||||
{ \
|
||||
return _name_iterable(_ENUM_NS(Enum)::name_array(), CallInitialize(_size));\
|
||||
} \
|
||||
\
|
||||
DefineInitialize(Enum) \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline Enum::_optional_index \
|
||||
Enum::_from_int_loop(Enum::_integral value, size_t index) \
|
||||
{ \
|
||||
return \
|
||||
index == _size ? _optional_index() : \
|
||||
_ENUM_NS(Enum)::value_array[index]._value == value ? \
|
||||
_optional_index(index) : \
|
||||
_from_int_loop(value, index + 1); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline Enum::_optional_index \
|
||||
Enum::_from_string_loop(const char *name, size_t index) \
|
||||
{ \
|
||||
return \
|
||||
index == _size ? _optional_index() : \
|
||||
_enum::_namesMatch(_ENUM_NS(Enum)::name_array()[index], name) ? \
|
||||
_optional_index(index) : \
|
||||
_from_string_loop(name, index + 1); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline Enum::_optional_index \
|
||||
Enum::_from_string_nocase_loop(const char *name, size_t index) \
|
||||
{ \
|
||||
return \
|
||||
index == _size ? _optional_index() : \
|
||||
_enum::_namesMatchNocase( \
|
||||
_ENUM_NS(Enum)::name_array()[index], name) ? \
|
||||
_optional_index(index) : \
|
||||
_from_string_nocase_loop(name, index + 1); \
|
||||
} \
|
||||
\
|
||||
_ENUM_CONSTEXPR inline bool operator ==(const Enum &a, const Enum &b) \
|
||||
{ return a._value == b._value; } \
|
||||
@ -605,10 +621,7 @@ _ENUM_CONSTEXPR inline bool operator <=(const Enum &a, const Enum &b) \
|
||||
_ENUM_CONSTEXPR inline bool operator >(const Enum &a, const Enum &b) \
|
||||
{ return a._value > b._value; } \
|
||||
_ENUM_CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
|
||||
{ return a._value >= b._value; } \
|
||||
\
|
||||
} \
|
||||
}
|
||||
{ return a._value >= b._value; }
|
||||
|
||||
|
||||
|
||||
@ -621,7 +634,7 @@ _ENUM_CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
|
||||
|
||||
// C++98, C++11
|
||||
#define _ENUM_DISABLE_DEFAULT_BY_PRIVATE(Type) \
|
||||
private: Type() : Base((_enumerated)0) { }
|
||||
private: Type() { }
|
||||
|
||||
// C++11
|
||||
#define _ENUM_DISABLE_DEFAULT_BY_DELETE(Type) \
|
||||
@ -642,25 +655,8 @@ _ENUM_CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
|
||||
#define _ENUM_GENERATE_SWITCH_TYPE_ENUM_CLASS(Integral, ...) \
|
||||
enum class EnumClassForSwitchStatements : Integral { __VA_ARGS__ }
|
||||
|
||||
// C++98, C++11
|
||||
#define _ENUM_SHORT_ITERABLE_DECLARATIONS_NOT_AVAILABLE
|
||||
|
||||
// C++11
|
||||
#define _ENUM_SHORT_ITERABLE_DECLARATIONS \
|
||||
constexpr const _Iterable<Base> values{value_array, size}; \
|
||||
constexpr const _Iterable<const char*> names{name_array(), size};
|
||||
|
||||
// C++98, C++11
|
||||
#define _ENUM_SHORT_ITERABLE_ALIASES_NOT_AVAILABLE(Enum)
|
||||
|
||||
// C++11
|
||||
#define _ENUM_SHORT_ITERABLE_ALIASES(Enum) \
|
||||
constexpr static const _value_iterable &_values = _ENUM_NS(Enum)::values; \
|
||||
constexpr static const _name_iterable &_names = _ENUM_NS(Enum)::names; \
|
||||
constexpr static const char *_name = #Enum;
|
||||
|
||||
// C++98
|
||||
#define _ENUM_GENERATE_STRINGS_PREPARE_FOR_RUNTIME_WRAPPED(...) \
|
||||
#define _ENUM_GENERATE_STRINGS_PREPARE_FOR_RUNTIME_WRAPPED(Enum, ...) \
|
||||
inline const char** raw_names() \
|
||||
{ \
|
||||
static const char* value[] = { _ENUM_STRINGIZE(__VA_ARGS__) }; \
|
||||
@ -669,7 +665,7 @@ _ENUM_CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
|
||||
\
|
||||
inline const char** name_array() \
|
||||
{ \
|
||||
static const char* value[size]; \
|
||||
static const char* value[Enum::_size]; \
|
||||
return value; \
|
||||
} \
|
||||
\
|
||||
@ -680,13 +676,13 @@ _ENUM_CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
|
||||
}
|
||||
|
||||
// C++11 fast version
|
||||
#define _ENUM_GENERATE_STRINGS_PREPARE_FOR_RUNTIME_CONSTEXPR(...) \
|
||||
#define _ENUM_GENERATE_STRINGS_PREPARE_FOR_RUNTIME_CONSTEXPR(Enum, ...) \
|
||||
constexpr const char *raw_names[] = { _ENUM_STRINGIZE(__VA_ARGS__) }; \
|
||||
const char *name_array[size]; \
|
||||
const char *name_array[Enum::_size]; \
|
||||
bool initialized = false;
|
||||
|
||||
// C++11 slow all-constexpr version
|
||||
#define _ENUM_GENERATE_STRINGS_COMPILE_TIME(...) \
|
||||
#define _ENUM_GENERATE_STRINGS_COMPILE_TIME(Enum, ...) \
|
||||
_ENUM_TRIM_STRINGS(__VA_ARGS__) \
|
||||
constexpr const char * const the_name_array[] = \
|
||||
{ _ENUM_REFER_TO_STRINGS(__VA_ARGS__) }; \
|
||||
@ -695,9 +691,16 @@ _ENUM_CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
|
||||
return the_name_array; \
|
||||
}
|
||||
|
||||
// C++98, C++11 fast version
|
||||
#define _ENUM_DECLARE_INITIALIZE \
|
||||
static int initialize();
|
||||
|
||||
// C++11 slow all-constexpr version
|
||||
#define _ENUM_INITIALIZE_DECLARATION_NOT_NEEDED
|
||||
|
||||
// C++98, C++11 fast version
|
||||
#define _ENUM_DEFINE_INITIALIZE(Enum) \
|
||||
static int initialize() \
|
||||
inline int Enum::initialize() \
|
||||
{ \
|
||||
if (_ENUM_NS(Enum)::initialized()) \
|
||||
return 0; \
|
||||
@ -730,9 +733,8 @@ _ENUM_CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
|
||||
_ENUM_DISABLE_DEFAULT_BY_DELETE, \
|
||||
_ENUM_SWITCH_TYPE_IS_ENUM_CLASS, \
|
||||
_ENUM_GENERATE_SWITCH_TYPE_ENUM_CLASS, \
|
||||
_ENUM_SHORT_ITERABLE_DECLARATIONS, \
|
||||
_ENUM_SHORT_ITERABLE_ALIASES, \
|
||||
_ENUM_GENERATE_STRINGS_COMPILE_TIME, \
|
||||
_ENUM_INITIALIZE_DECLARATION_NOT_NEEDED, \
|
||||
_ENUM_DEFINE_INITIALIZE_NOT_NEEDED, \
|
||||
_ENUM_CALL_INITIALIZE_IS_NO_OP, \
|
||||
Enum, Integral, __VA_ARGS__)
|
||||
@ -744,9 +746,8 @@ _ENUM_CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
|
||||
_ENUM_DISABLE_DEFAULT_BY_PRIVATE, \
|
||||
_ENUM_SWITCH_TYPE_IS_REGULAR_ENUM, \
|
||||
_ENUM_GENERATE_SWITCH_TYPE_REGULAR_ENUM, \
|
||||
_ENUM_SHORT_ITERABLE_DECLARATIONS_NOT_AVAILABLE, \
|
||||
_ENUM_SHORT_ITERABLE_ALIASES_NOT_AVAILABLE, \
|
||||
_ENUM_GENERATE_STRINGS_PREPARE_FOR_RUNTIME_WRAPPED, \
|
||||
_ENUM_DECLARE_INITIALIZE, \
|
||||
_ENUM_DEFINE_INITIALIZE, \
|
||||
_ENUM_CALL_INITIALIZE, \
|
||||
Enum, Integral, __VA_ARGS__)
|
||||
|
||||
@ -93,7 +93,7 @@ int main()
|
||||
|
||||
|
||||
// The type name is available as a string.
|
||||
std::cout << Channel::_name << std::endl;
|
||||
std::cout << Channel::_name() << std::endl;
|
||||
|
||||
|
||||
|
||||
|
||||
@ -8,12 +8,12 @@ ENUM(Channel, int, Red = 3, Green = 4, Blue = 0)
|
||||
int main()
|
||||
{
|
||||
// Listing declared values. Output is 3 4 0.
|
||||
for (Channel channel : Channel::_values)
|
||||
for (Channel channel : Channel::_values())
|
||||
std::cout << channel._to_integral() << " ";
|
||||
std::cout << std::endl;
|
||||
|
||||
// Listing declared names. Output is Red Green Blue.
|
||||
for (const char *name : Channel::_names)
|
||||
for (const char *name : Channel::_names())
|
||||
std::cout << name << " ";
|
||||
std::cout << std::endl;
|
||||
|
||||
@ -22,7 +22,7 @@ int main()
|
||||
// Direct iterator usage. Output is Red.
|
||||
std::cout
|
||||
<< "first (using iterator): "
|
||||
<< *Channel::_names.begin()
|
||||
<< *Channel::_names().begin()
|
||||
<< std::endl;
|
||||
|
||||
return 0;
|
||||
|
||||
@ -31,12 +31,13 @@ constexpr bool should_be_valid_3 = Channel::_is_valid_nocase("red");
|
||||
constexpr bool should_be_invalid_3 = Channel::_is_valid_nocase("reed");
|
||||
|
||||
// _names and _values collections and iterators.
|
||||
constexpr Channel channel_5 = *(Channel::_values.begin() + 1);
|
||||
constexpr const char *name_through_iterator = *(Channel::_names.begin() + 1);
|
||||
constexpr const char *name_through_subscript = Channel::_names[2];
|
||||
constexpr Channel channel_5 = *(Channel::_values().begin() + 1);
|
||||
constexpr const char *name_through_iterator =
|
||||
*(Channel::_names().begin() + 1);
|
||||
constexpr const char *name_through_subscript = Channel::_names()[2];
|
||||
|
||||
// Type name.
|
||||
constexpr auto name = Channel::_name;
|
||||
constexpr auto name = Channel::_name();
|
||||
|
||||
// Explicit promotion.
|
||||
constexpr int converted = (+Channel::Green)._to_integral();
|
||||
|
||||
@ -30,7 +30,7 @@ int main()
|
||||
std::map<const char*, Channel> map = {{"first", Channel::Blue}};
|
||||
map.insert({"second", Channel::Green});
|
||||
|
||||
for (Channel channel : Channel::_values)
|
||||
for (Channel channel : Channel::_values())
|
||||
map.insert({channel._to_string(), channel});
|
||||
|
||||
bool first = true;
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
template <typename Enum>
|
||||
constexpr const Enum default_()
|
||||
{
|
||||
return Enum::_values[0];
|
||||
return Enum::_values()[0];
|
||||
}
|
||||
|
||||
// Make it possible to override the convention for specific enums.
|
||||
|
||||
@ -6,12 +6,12 @@
|
||||
|
||||
// Computes the maximum value of an enum at compile time.
|
||||
template <typename Enum>
|
||||
constexpr Enum maximum(Enum accumulator = Enum::_values[0], size_t index = 1)
|
||||
constexpr Enum maximum(Enum accumulator = Enum::_values()[0], size_t index = 1)
|
||||
{
|
||||
return
|
||||
index >= Enum::_size ? accumulator :
|
||||
+Enum::_values[index] > accumulator ?
|
||||
maximum(+Enum::_values[index], index + 1) :
|
||||
Enum::_values()[index] > accumulator ?
|
||||
maximum(Enum::_values()[index], index + 1) :
|
||||
maximum(accumulator, index + 1);
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ int main()
|
||||
|
||||
ChannelSet red_and_blue = red_only | blue_only;
|
||||
|
||||
for (Channel channel : Channel::_values) {
|
||||
for (Channel channel : Channel::_values()) {
|
||||
std::cout
|
||||
<< channel._to_string()
|
||||
<< " bit is set to "
|
||||
|
||||
@ -24,7 +24,7 @@ constexpr size_t total_names_length(size_t accumulator = 0, size_t index = 0)
|
||||
return
|
||||
index == Enum::_size ? accumulator :
|
||||
total_names_length<Enum>
|
||||
(accumulator + string_length(Enum::_names[index]), index + 1);
|
||||
(accumulator + string_length(Enum::_names()[index]), index + 1);
|
||||
}
|
||||
|
||||
// Computes the total length of an ENUM declaration, assuming the type is int.
|
||||
@ -36,7 +36,7 @@ template <typename Enum>
|
||||
constexpr size_t declaration_length()
|
||||
{
|
||||
return
|
||||
4 + 1 + string_length(Enum::_name) + 1 + 1 + 3 + 1 + 1 +
|
||||
4 + 1 + string_length(Enum::_name()) + 1 + 1 + 3 + 1 + 1 +
|
||||
total_names_length<Enum>() + (Enum::_size - 1) * 2 + 1 + 1 + 1;
|
||||
}
|
||||
|
||||
@ -45,16 +45,16 @@ template <typename Enum>
|
||||
void format_declaration(char *storage)
|
||||
{
|
||||
std::strcat(storage, "ENUM(");
|
||||
std::strcat(storage, Enum::_name);
|
||||
std::strcat(storage, Enum::_name());
|
||||
std::strcat(storage, ", int, ");
|
||||
|
||||
for (auto name_iterator = Enum::_names.begin();
|
||||
name_iterator < Enum::_names.end() - 1; ++name_iterator) {
|
||||
for (auto name_iterator = Enum::_names().begin();
|
||||
name_iterator < Enum::_names().end() - 1; ++name_iterator) {
|
||||
|
||||
std::strcat(storage, *name_iterator);
|
||||
std::strcat(storage, ", ");
|
||||
}
|
||||
std::strcat(storage, Enum::_names[Enum::_size - 1]);
|
||||
std::strcat(storage, Enum::_names()[Enum::_size - 1]);
|
||||
|
||||
std::strcat(storage, ");");
|
||||
|
||||
|
||||
@ -15,9 +15,9 @@ ENUM(Compression, short, None, Huffman, Default = Huffman)
|
||||
|
||||
// Type properties.
|
||||
static_assert_1(std::is_class<Channel>());
|
||||
static_assert_1(!std::is_trivial<Channel>());
|
||||
static_assert_1(std::is_trivial<Channel>());
|
||||
static_assert_1(std::is_standard_layout<Channel>());
|
||||
static_assert_1(!std::is_pod<Channel>());
|
||||
static_assert_1(std::is_pod<Channel>());
|
||||
static_assert_1(std::is_literal_type<Channel>());
|
||||
|
||||
|
||||
@ -69,7 +69,7 @@ static_assert_1(!(std::is_convertible<Channel, Depth>()));
|
||||
static_assert_1(!(std::is_convertible<Channel, Channel::_enumerated>()));
|
||||
static_assert_1(!(std::is_convertible<decltype(+Channel::Red),
|
||||
Channel::_integral>()));
|
||||
static_assert_1(!(std::is_convertible<decltype(Channel::_values[0]),
|
||||
static_assert_1(!(std::is_convertible<decltype(Channel::_values()[0]),
|
||||
Channel::_integral>()));
|
||||
|
||||
|
||||
@ -117,16 +117,16 @@ static_assert_1(!Channel::_is_valid_nocase("greeen"));
|
||||
// Iterables.
|
||||
static_assert_1(Channel::_size == 3);
|
||||
static_assert_1(Depth::_size == 2);
|
||||
static_assert_1(Channel::_values.size() == Channel::_size);
|
||||
static_assert_1(*Channel::_values.begin() == Channel::Red);
|
||||
static_assert_1(*(Channel::_values.begin() + 1) == Channel::Green);
|
||||
static_assert_1(*(Channel::_values.begin() + 2) == Channel::Blue);
|
||||
static_assert_1(Channel::_values[1] == Channel::Green);
|
||||
static_assert_1(Channel::_values[2] == Channel::Blue);
|
||||
static_assert_1(Channel::_values().size() == Channel::_size);
|
||||
static_assert_1(*Channel::_values().begin() == Channel::Red);
|
||||
static_assert_1(*(Channel::_values().begin() + 1) == Channel::Green);
|
||||
static_assert_1(*(Channel::_values().begin() + 2) == Channel::Blue);
|
||||
static_assert_1(Channel::_values()[1] == Channel::Green);
|
||||
static_assert_1(Channel::_values()[2] == Channel::Blue);
|
||||
|
||||
static_assert_1(Channel::_names.size() == Channel::_size);
|
||||
static_assert_1(Channel::_names().size() == Channel::_size);
|
||||
// The next one is a little janky, but actually the pointers should be the same.
|
||||
static_assert_1(*Channel::_names.begin() == (+Channel::Red)._to_string());
|
||||
static_assert_1(*Channel::_names().begin() == (+Channel::Red)._to_string());
|
||||
|
||||
|
||||
|
||||
@ -156,44 +156,44 @@ class EnumTests : public CxxTest::TestSuite {
|
||||
|
||||
void test_value_iterable()
|
||||
{
|
||||
auto value_iterator = Channel::_values.begin();
|
||||
auto value_iterator = Channel::_values().begin();
|
||||
TS_ASSERT_EQUALS(*value_iterator, Channel::Red);
|
||||
TS_ASSERT_DIFFERS(value_iterator, Channel::_values.end());
|
||||
TS_ASSERT_DIFFERS(value_iterator, Channel::_values().end());
|
||||
|
||||
++value_iterator;
|
||||
TS_ASSERT_EQUALS(*value_iterator, Channel::Green);
|
||||
TS_ASSERT_DIFFERS(value_iterator, Channel::_values.end());
|
||||
TS_ASSERT_DIFFERS(value_iterator, Channel::_values().end());
|
||||
|
||||
++value_iterator;
|
||||
TS_ASSERT_EQUALS(*value_iterator, Channel::Blue);
|
||||
TS_ASSERT_DIFFERS(value_iterator, Channel::_values.end());
|
||||
TS_ASSERT_DIFFERS(value_iterator, Channel::_values().end());
|
||||
|
||||
++value_iterator;
|
||||
TS_ASSERT_EQUALS(value_iterator, Channel::_values.end());
|
||||
TS_ASSERT_EQUALS(value_iterator, Channel::_values().end());
|
||||
}
|
||||
|
||||
void test_name_iterable()
|
||||
{
|
||||
auto name_iterator = Channel::_names.begin();
|
||||
auto name_iterator = Channel::_names().begin();
|
||||
TS_ASSERT_EQUALS(strcmp(*name_iterator, "Red"), 0);
|
||||
TS_ASSERT_DIFFERS(name_iterator, Channel::_names.end());
|
||||
TS_ASSERT_DIFFERS(name_iterator, Channel::_names().end());
|
||||
|
||||
++name_iterator;
|
||||
TS_ASSERT_EQUALS(strcmp(*name_iterator, "Green"), 0);
|
||||
TS_ASSERT_DIFFERS(name_iterator, Channel::_names.end());
|
||||
TS_ASSERT_DIFFERS(name_iterator, Channel::_names().end());
|
||||
|
||||
++name_iterator;
|
||||
TS_ASSERT_EQUALS(strcmp(*name_iterator, "Blue"), 0);
|
||||
TS_ASSERT_DIFFERS(name_iterator, Channel::_names.end());
|
||||
TS_ASSERT_DIFFERS(name_iterator, Channel::_names().end());
|
||||
|
||||
++name_iterator;
|
||||
TS_ASSERT_EQUALS(name_iterator, Channel::_names.end());
|
||||
TS_ASSERT_EQUALS(name_iterator, Channel::_names().end());
|
||||
}
|
||||
|
||||
void test_type_name()
|
||||
{
|
||||
TS_ASSERT_EQUALS(strcmp(Channel::_name, "Channel"), 0);
|
||||
TS_ASSERT_EQUALS(strcmp(Depth::_name, "Depth"), 0);
|
||||
TS_ASSERT_EQUALS(strcmp(Compression::_name, "Compression"), 0);
|
||||
TS_ASSERT_EQUALS(strcmp(Channel::_name(), "Channel"), 0);
|
||||
TS_ASSERT_EQUALS(strcmp(Depth::_name(), "Depth"), 0);
|
||||
TS_ASSERT_EQUALS(strcmp(Compression::_name(), "Compression"), 0);
|
||||
}
|
||||
};
|
||||
|
||||
@ -3,5 +3,5 @@
|
||||
|
||||
void print(Channel channel)
|
||||
{
|
||||
std::cout << Channel::_name << "::" << channel._to_string() << std::endl;
|
||||
std::cout << Channel::_name() << "::" << channel._to_string() << std::endl;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user