mirror of
https://github.com/aantron/better-enums.git
synced 2026-02-06 09:49:45 +08:00
Made ENUM usable in namespaces.
This commit is contained in:
parent
97197088fe
commit
5edcb3e121
10
README.md
10
README.md
@ -65,7 +65,7 @@ enums that are missing from standard C++.
|
||||
- Supported and tested on clang, gcc, and msvc.
|
||||
- Fast compilation. You have to declare a few dozen enums to slow down your
|
||||
compiler as much as [just including `iostream` does][performance].
|
||||
- Use any initializers, just like with a built-in enum.
|
||||
- Use any initializers and sparse ranges, just like with a built-in enum.
|
||||
- Guaranteed size and alignment — you choose the representation type.
|
||||
|
||||
[performance]: http://aantron.github.io/better-enums/Performance.html
|
||||
@ -73,8 +73,8 @@ enums that are missing from standard C++.
|
||||
## Limitations
|
||||
|
||||
The biggest current limitation is that the `ENUM` macro can't be used inside a
|
||||
class or namespace. This seems difficult to remove, but I am looking into it. In
|
||||
the meantime, there is a workaround with a `typedef` (or `using`):
|
||||
class. This seems difficult to remove, but I am looking into it. In the
|
||||
meantime, there is a workaround with a `typedef` (or `using`):
|
||||
|
||||
```cpp
|
||||
ENUM(UniquePrefix_Color, uint8_t, Red, Green, Blue)
|
||||
@ -83,8 +83,12 @@ struct triplet {
|
||||
typedef UniquePrefix_Color Color;
|
||||
Color r, g, b;
|
||||
};
|
||||
|
||||
triplet::Color color;
|
||||
```
|
||||
|
||||
You can, however, use `ENUM` inside a namespace.
|
||||
|
||||
## Contact
|
||||
|
||||
Don't hesitate to contact me about features or bugs:
|
||||
|
||||
58
enum.h
58
enum.h
@ -229,7 +229,7 @@
|
||||
|
||||
|
||||
#define BETTER_ENUMS__EAT_ASSIGN_SINGLE(EnumType, index, expression) \
|
||||
((better_enums::_eat_assign<EnumType>)EnumType::expression),
|
||||
((::better_enums::_eat_assign<EnumType>)EnumType::expression),
|
||||
|
||||
#define BETTER_ENUMS__EAT_ASSIGN(EnumType, ...) \
|
||||
BETTER_ENUMS__ID( \
|
||||
@ -422,7 +422,7 @@ inline void _trim_names(const char * const *raw_names,
|
||||
|
||||
|
||||
#define BETTER_ENUMS__SELECT_SINGLE_CHARACTER(from, from_length, index) \
|
||||
_select(from, from_length, index),
|
||||
::better_enums::_select(from, from_length, index),
|
||||
|
||||
#define BETTER_ENUMS__SELECT_CHARACTERS(from, from_length) \
|
||||
BETTER_ENUMS__ITERATE( \
|
||||
@ -431,11 +431,13 @@ inline void _trim_names(const char * const *raw_names,
|
||||
|
||||
|
||||
#define BETTER_ENUMS__TRIM_SINGLE_STRING(ignored, index, expression) \
|
||||
constexpr std::size_t _length_ ## index = _constantLength(#expression); \
|
||||
constexpr std::size_t _length_ ## index = \
|
||||
::better_enums::_constantLength(#expression); \
|
||||
constexpr const char _trimmed_ ## index [] = \
|
||||
{ BETTER_ENUMS__SELECT_CHARACTERS(#expression, _length_ ## index) }; \
|
||||
constexpr const char *_final_ ## index = \
|
||||
_hasExplicitValue(#expression) ? _trimmed_ ## index : #expression;
|
||||
::better_enums::_hasExplicitValue(#expression) ? \
|
||||
_trimmed_ ## index : #expression;
|
||||
|
||||
#define BETTER_ENUMS__TRIM_STRINGS(...) \
|
||||
BETTER_ENUMS__ID( \
|
||||
@ -482,8 +484,8 @@ BETTER_ENUMS__ID(GenerateSwitchType(Integral, __VA_ARGS__)) \
|
||||
\
|
||||
class Enum { \
|
||||
private: \
|
||||
typedef better_enums::optional<Enum> _optional; \
|
||||
typedef better_enums::optional<std::size_t> _optional_index; \
|
||||
typedef ::better_enums::optional<Enum> _optional; \
|
||||
typedef ::better_enums::optional<std::size_t> _optional_index; \
|
||||
\
|
||||
public: \
|
||||
enum _enumerated SetUnderlyingType(Integral) { __VA_ARGS__ }; \
|
||||
@ -516,8 +518,8 @@ class Enum { \
|
||||
BETTER_ENUMS__CONSTEXPR static bool _is_valid(const char *name); \
|
||||
BETTER_ENUMS__CONSTEXPR static bool _is_valid_nocase(const char *name); \
|
||||
\
|
||||
typedef better_enums::_Iterable<Enum> _value_iterable; \
|
||||
typedef better_enums::_Iterable<const char*> _name_iterable; \
|
||||
typedef ::better_enums::_Iterable<Enum> _value_iterable; \
|
||||
typedef ::better_enums::_Iterable<const char*> _name_iterable; \
|
||||
\
|
||||
typedef _value_iterable::iterator _value_iterator; \
|
||||
typedef _name_iterable::iterator _name_iterator; \
|
||||
@ -577,23 +579,23 @@ Enum::_from_integral_unchecked(Enum::_integral value) \
|
||||
BETTER_ENUMS__CONSTEXPR inline Enum Enum::_from_integral(Enum::_integral value)\
|
||||
{ \
|
||||
return \
|
||||
better_enums::_or_throw(_from_integral_nothrow(value), \
|
||||
"Enum::_from_integral: invalid argument"); \
|
||||
::better_enums::_or_throw(_from_integral_nothrow(value), \
|
||||
"Enum::_from_integral: invalid argument"); \
|
||||
} \
|
||||
\
|
||||
BETTER_ENUMS__CONSTEXPR inline Enum::_optional \
|
||||
Enum::_from_integral_nothrow(Enum::_integral value) \
|
||||
{ \
|
||||
return \
|
||||
better_enums::_map_index<Enum>(BETTER_ENUMS__NS(Enum)::value_array, \
|
||||
_from_int_loop(value)); \
|
||||
::better_enums::_map_index<Enum>(BETTER_ENUMS__NS(Enum)::value_array, \
|
||||
_from_int_loop(value)); \
|
||||
} \
|
||||
\
|
||||
ToStringConstexpr inline const char* Enum::_to_string() const \
|
||||
{ \
|
||||
return \
|
||||
better_enums::_or_throw( \
|
||||
better_enums::_map_index<const char*>( \
|
||||
::better_enums::_or_throw( \
|
||||
::better_enums::_map_index<const char*>( \
|
||||
BETTER_ENUMS__NS(Enum)::name_array(), \
|
||||
_from_int_loop(CallInitialize(_value))), \
|
||||
"Enum::to_string: invalid enum value"); \
|
||||
@ -602,31 +604,32 @@ ToStringConstexpr inline const char* Enum::_to_string() const \
|
||||
BETTER_ENUMS__CONSTEXPR inline Enum Enum::_from_string(const char *name) \
|
||||
{ \
|
||||
return \
|
||||
better_enums::_or_throw(_from_string_nothrow(name), \
|
||||
"Enum::_from_string: invalid argument"); \
|
||||
::better_enums::_or_throw(_from_string_nothrow(name), \
|
||||
"Enum::_from_string: invalid argument"); \
|
||||
} \
|
||||
\
|
||||
BETTER_ENUMS__CONSTEXPR inline Enum::_optional \
|
||||
Enum::_from_string_nothrow(const char *name) \
|
||||
{ \
|
||||
return \
|
||||
better_enums::_map_index<Enum>( \
|
||||
::better_enums::_map_index<Enum>( \
|
||||
BETTER_ENUMS__NS(Enum)::value_array, _from_string_loop(name)); \
|
||||
} \
|
||||
\
|
||||
BETTER_ENUMS__CONSTEXPR inline Enum Enum::_from_string_nocase(const char *name)\
|
||||
{ \
|
||||
return \
|
||||
better_enums::_or_throw(_from_string_nocase_nothrow(name), \
|
||||
"Enum::_from_string_nocase: invalid argument");\
|
||||
::better_enums::_or_throw( \
|
||||
_from_string_nocase_nothrow(name), \
|
||||
"Enum::_from_string_nocase: invalid argument"); \
|
||||
} \
|
||||
\
|
||||
BETTER_ENUMS__CONSTEXPR inline Enum::_optional \
|
||||
Enum::_from_string_nocase_nothrow(const char *name) \
|
||||
{ \
|
||||
return \
|
||||
better_enums::_map_index<Enum>(BETTER_ENUMS__NS(Enum)::value_array, \
|
||||
_from_string_nocase_loop(name)); \
|
||||
::better_enums::_map_index<Enum>(BETTER_ENUMS__NS(Enum)::value_array, \
|
||||
_from_string_nocase_loop(name)); \
|
||||
} \
|
||||
\
|
||||
BETTER_ENUMS__CONSTEXPR inline bool Enum::_is_valid(Enum::_integral value) \
|
||||
@ -678,8 +681,8 @@ Enum::_from_string_loop(const char *name, std::size_t index) \
|
||||
{ \
|
||||
return \
|
||||
index == _size ? _optional_index() : \
|
||||
better_enums::_namesMatch(BETTER_ENUMS__NS(Enum)::raw_names()[index], \
|
||||
name) ? \
|
||||
::better_enums::_namesMatch(BETTER_ENUMS__NS(Enum)::raw_names()[index],\
|
||||
name) ? \
|
||||
_optional_index(index) : \
|
||||
_from_string_loop(name, index + 1); \
|
||||
} \
|
||||
@ -689,7 +692,7 @@ Enum::_from_string_nocase_loop(const char *name, std::size_t index) \
|
||||
{ \
|
||||
return \
|
||||
index == _size ? _optional_index() : \
|
||||
better_enums::_namesMatchNocase( \
|
||||
::better_enums::_namesMatchNocase( \
|
||||
BETTER_ENUMS__NS(Enum)::raw_names()[index], name) ? \
|
||||
_optional_index(index) : \
|
||||
_from_string_nocase_loop(name, index + 1); \
|
||||
@ -813,8 +816,9 @@ BETTER_ENUMS__CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
|
||||
if (BETTER_ENUMS__NS(Enum)::initialized()) \
|
||||
return 0; \
|
||||
\
|
||||
better_enums::_trim_names(BETTER_ENUMS__NS(Enum)::raw_names(), \
|
||||
BETTER_ENUMS__NS(Enum)::name_array(), _size);\
|
||||
::better_enums::_trim_names(BETTER_ENUMS__NS(Enum)::raw_names(), \
|
||||
BETTER_ENUMS__NS(Enum)::name_array(), \
|
||||
_size); \
|
||||
\
|
||||
BETTER_ENUMS__NS(Enum)::initialized() = true; \
|
||||
\
|
||||
@ -826,7 +830,7 @@ BETTER_ENUMS__CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
|
||||
|
||||
// C++98, C++11 fast version
|
||||
#define BETTER_ENUMS__DO_CALL_INITIALIZE(value) \
|
||||
better_enums::continue_with(initialize(), value)
|
||||
::better_enums::continue_with(initialize(), value)
|
||||
|
||||
// C++11 slow all-constexpr version
|
||||
#define BETTER_ENUMS__DO_NOT_CALL_INITIALIZE(value) \
|
||||
|
||||
@ -18,6 +18,14 @@ ENUM(Compression, short, None, Huffman, Default = Huffman)
|
||||
|
||||
|
||||
|
||||
namespace test {
|
||||
|
||||
ENUM(Namespaced, short, One, Two)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Using _ENUM_HAVE_CONSTEXPR as a proxy for C++11 support. This should be
|
||||
// changed to be more precise in the future.
|
||||
#ifdef _ENUM_HAVE_CONSTEXPR
|
||||
@ -269,4 +277,23 @@ class EnumTests : public CxxTest::TestSuite {
|
||||
{
|
||||
TS_ASSERT_EQUALS(Compression::Default, Compression::Huffman);
|
||||
}
|
||||
|
||||
void test_namespaced()
|
||||
{
|
||||
TS_ASSERT_EQUALS((+test::Namespaced::One)._to_integral(), 0);
|
||||
TS_ASSERT_EQUALS(test::Namespaced::_from_integral(0),
|
||||
+test::Namespaced::One);
|
||||
TS_ASSERT_EQUALS(strcmp((+test::Namespaced::One)._to_string(), "One"),
|
||||
0);
|
||||
TS_ASSERT_EQUALS(test::Namespaced::_from_string("Two"),
|
||||
+test::Namespaced::Two);
|
||||
|
||||
TS_ASSERT_EQUALS(test::Namespaced::_values()[0],
|
||||
+test::Namespaced::One);
|
||||
TS_ASSERT_EQUALS(strcmp(test::Namespaced::_names()[0], "One"), 0);
|
||||
|
||||
TS_ASSERT_EQUALS(*test::Namespaced::_values().begin(),
|
||||
+test::Namespaced::One);
|
||||
TS_ASSERT_EQUALS(strcmp(*test::Namespaced::_names().begin(), "One"), 0);
|
||||
}
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user