mirror of
https://github.com/aantron/better-enums.git
synced 2025-12-06 08:46:42 +08:00
Changed _size to a function.
An alternative constant _size_constant is provided for use in C++98, for example for declaring arrays. Also renamed underlying_traits to integral_mapping.
This commit is contained in:
parent
aa34aad468
commit
9810dd07ce
@ -71,7 +71,7 @@ slightly more complex template function for the general case:
|
||||
constexpr <em>Enum default_imp</em>l()
|
||||
{
|
||||
return
|
||||
<em>Enum::_size < 2 ?
|
||||
<em>Enum::_size() < 2 ?
|
||||
throw std::logic_error("enum has no valid constants") :
|
||||
Enum::_values()[0] == invalid_impl<Enum>() ?
|
||||
Enum::_values()[1] :
|
||||
|
||||
@ -17,7 +17,7 @@ We simply need to find the maximum value of any given enum type.
|
||||
constexpr <em>Enum max_loop</em>(Enum accumulator, size_t index)
|
||||
{
|
||||
return
|
||||
<em>index >= Enum::_size ? accumulator :
|
||||
<em>index >= Enum::_size() ? accumulator :
|
||||
Enum::_values()[index] > accumulator ?
|
||||
max_loop<Enum>(Enum::_values()[index], index + 1) :
|
||||
max_loop<Enum>(accumulator, index + 1)</em>;
|
||||
|
||||
@ -82,7 +82,7 @@ initializers for sequential values, but I won't go through this exercise here.
|
||||
constexpr <em>size_t constants_length</em>(size_t index = 0, size_t accumulator = 0)
|
||||
{
|
||||
return
|
||||
<em>index >= Enum::_size ? accumulator :
|
||||
<em>index >= Enum::_size() ? accumulator :
|
||||
constants_length<Enum>(
|
||||
index + 1, accumulator
|
||||
+ string_length(", ")
|
||||
|
||||
@ -11,7 +11,7 @@ example, this:
|
||||
int main()
|
||||
{
|
||||
|
||||
<em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size</em>; <em>++index</em>) {
|
||||
<em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size()</em>; <em>++index</em>) {
|
||||
Channel channel = <em>Channel::_values()[index]</em>;
|
||||
std::cout << channel._to_integral() << " ";
|
||||
}
|
||||
@ -19,7 +19,7 @@ example, this:
|
||||
|
||||
will print "0 2 3". And this:
|
||||
|
||||
<em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size</em>; <em>++index</em>) {
|
||||
<em>for</em> (<em>size_t index = 0</em>; <em>index < Channel::_size()</em>; <em>++index</em>) {
|
||||
const char *name = <em>Channel::_names()[index]</em>;
|
||||
std::cout << name << " ";
|
||||
}
|
||||
|
||||
45
enum.h
45
enum.h
@ -499,7 +499,7 @@ template <> struct _representation<char32_t> { typedef char32_t type; };
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
struct underlying_traits {
|
||||
struct integral_mapping {
|
||||
typedef typename _representation<T>::type integral_representation;
|
||||
|
||||
BETTER_ENUMS__CONSTEXPR static integral_representation
|
||||
@ -620,20 +620,20 @@ class Enum { \
|
||||
private: \
|
||||
typedef ::better_enums::optional<Enum> _optional; \
|
||||
typedef ::better_enums::optional<std::size_t> _optional_index; \
|
||||
typedef ::better_enums::underlying_traits<Underlying> _traits; \
|
||||
typedef ::better_enums::integral_mapping<Underlying> _mapping; \
|
||||
\
|
||||
public: \
|
||||
typedef Underlying _underlying; \
|
||||
typedef _traits::integral_representation _integral; \
|
||||
typedef _mapping::integral_representation _integral; \
|
||||
\
|
||||
enum _enumerated SetUnderlyingType(Underlying) { __VA_ARGS__ }; \
|
||||
\
|
||||
BETTER_ENUMS__CONSTEXPR Enum(_enumerated value) : \
|
||||
_value(_traits::from_integral(value)) { } \
|
||||
_value(_mapping::from_integral(value)) { } \
|
||||
\
|
||||
BETTER_ENUMS__CONSTEXPR operator SwitchType(Enum)() const \
|
||||
{ \
|
||||
return (SwitchType(Enum))_traits::to_integral(_value); \
|
||||
return (SwitchType(Enum))_mapping::to_integral(_value); \
|
||||
} \
|
||||
\
|
||||
_underlying& operator *() { return _value; } \
|
||||
@ -689,8 +689,10 @@ class Enum { \
|
||||
typedef _value_iterable::iterator _value_iterator; \
|
||||
typedef _name_iterable::iterator _name_iterator; \
|
||||
\
|
||||
BETTER_ENUMS__CONSTEXPR static const std::size_t _size = \
|
||||
BETTER_ENUMS__CONSTEXPR static const std::size_t _size_constant = \
|
||||
BETTER_ENUMS__ID(BETTER_ENUMS__PP_COUNT(__VA_ARGS__)); \
|
||||
BETTER_ENUMS__CONSTEXPR static std::size_t _size() \
|
||||
{ return _size_constant; } \
|
||||
\
|
||||
BETTER_ENUMS__CONSTEXPR static const char* _name(); \
|
||||
BETTER_ENUMS__CONSTEXPR static _value_iterable _values(); \
|
||||
@ -699,7 +701,7 @@ class Enum { \
|
||||
_underlying _value; \
|
||||
\
|
||||
private: \
|
||||
Enum() : _value(_traits::from_integral(0)) { } \
|
||||
Enum() : _value(_mapping::from_integral(0)) { } \
|
||||
\
|
||||
explicit BETTER_ENUMS__CONSTEXPR Enum(const _underlying &value) : \
|
||||
_value(value) { } \
|
||||
@ -765,7 +767,7 @@ Enum::_from_underlying_nothrow(const _underlying &value) \
|
||||
\
|
||||
BETTER_ENUMS__CONSTEXPR inline Enum::_integral Enum::_to_integral() const \
|
||||
{ \
|
||||
return _traits::to_integral(_value); \
|
||||
return _mapping::to_integral(_value); \
|
||||
} \
|
||||
\
|
||||
BETTER_ENUMS__CONSTEXPR inline Enum \
|
||||
@ -786,7 +788,7 @@ BETTER_ENUMS__CONSTEXPR inline Enum Enum::_from_integral(_integral value) \
|
||||
BETTER_ENUMS__CONSTEXPR inline Enum::_optional \
|
||||
Enum::_from_integral_nothrow(_integral value) \
|
||||
{ \
|
||||
return _from_underlying_nothrow(_traits::from_integral(value)); \
|
||||
return _from_underlying_nothrow(_mapping::from_integral(value)); \
|
||||
} \
|
||||
\
|
||||
ToStringConstexpr inline const char* Enum::_to_string() const \
|
||||
@ -855,14 +857,14 @@ BETTER_ENUMS__CONSTEXPR inline const char* Enum::_name() \
|
||||
\
|
||||
BETTER_ENUMS__CONSTEXPR inline Enum::_value_iterable Enum::_values() \
|
||||
{ \
|
||||
return _value_iterable(BETTER_ENUMS__NS(Enum)::value_array, _size); \
|
||||
return _value_iterable(BETTER_ENUMS__NS(Enum)::value_array, _size()); \
|
||||
} \
|
||||
\
|
||||
ToStringConstexpr inline Enum::_name_iterable Enum::_names() \
|
||||
{ \
|
||||
return \
|
||||
_name_iterable(BETTER_ENUMS__NS(Enum)::name_array(), \
|
||||
CallInitialize(_size)); \
|
||||
CallInitialize(_size())); \
|
||||
} \
|
||||
\
|
||||
DefineInitialize(Enum) \
|
||||
@ -871,9 +873,10 @@ BETTER_ENUMS__CONSTEXPR inline Enum::_optional_index \
|
||||
Enum::_from_value_loop(const Enum::_underlying &value, std::size_t index) \
|
||||
{ \
|
||||
return \
|
||||
index == _size ? _optional_index() : \
|
||||
_traits::to_integral(BETTER_ENUMS__NS(Enum)::value_array[index]._value)\
|
||||
== _traits::to_integral(value) ? _optional_index(index) : \
|
||||
index == _size() ? _optional_index() : \
|
||||
_mapping::to_integral( \
|
||||
BETTER_ENUMS__NS(Enum)::value_array[index]._value) \
|
||||
== _mapping::to_integral(value) ? _optional_index(index) : \
|
||||
_from_value_loop(value, index + 1); \
|
||||
} \
|
||||
\
|
||||
@ -881,7 +884,7 @@ BETTER_ENUMS__CONSTEXPR inline Enum::_optional_index \
|
||||
Enum::_from_string_loop(const char *name, std::size_t index) \
|
||||
{ \
|
||||
return \
|
||||
index == _size ? _optional_index() : \
|
||||
index == _size() ? _optional_index() : \
|
||||
::better_enums::_names_match( \
|
||||
BETTER_ENUMS__NS(Enum)::raw_names()[index], name) ? \
|
||||
_optional_index(index) : \
|
||||
@ -892,7 +895,7 @@ BETTER_ENUMS__CONSTEXPR inline Enum::_optional_index \
|
||||
Enum::_from_string_nocase_loop(const char *name, std::size_t index) \
|
||||
{ \
|
||||
return \
|
||||
index == _size ? _optional_index() : \
|
||||
index == _size() ? _optional_index() : \
|
||||
::better_enums::_names_match_nocase( \
|
||||
BETTER_ENUMS__NS(Enum)::raw_names()[index], name) ? \
|
||||
_optional_index(index) : \
|
||||
@ -921,7 +924,7 @@ BETTER_ENUMS__CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
|
||||
|
||||
// C++11
|
||||
#define BETTER_ENUMS__CXX11_UNDERLYING_TYPE(Underlying) \
|
||||
: ::better_enums::underlying_traits<Underlying>::integral_representation
|
||||
: ::better_enums::integral_mapping<Underlying>::integral_representation
|
||||
|
||||
// C++98, C++11
|
||||
#define BETTER_ENUMS__REGULAR_ENUM_SWITCH_TYPE(Type) \
|
||||
@ -937,7 +940,7 @@ BETTER_ENUMS__CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
|
||||
// C++11
|
||||
#define BETTER_ENUMS__ENUM_CLASS_SWITCH_TYPE_GENERATE(Underlying, ...) \
|
||||
enum class EnumClassForSwitchStatements : \
|
||||
::better_enums::underlying_traits<Underlying>::integral_representation \
|
||||
::better_enums::integral_mapping<Underlying>::integral_representation \
|
||||
{ __VA_ARGS__ };
|
||||
|
||||
// C++98
|
||||
@ -958,7 +961,7 @@ BETTER_ENUMS__CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
|
||||
\
|
||||
inline const char** name_array() \
|
||||
{ \
|
||||
static const char *value[Enum::_size]; \
|
||||
static const char *value[Enum::_size_constant]; \
|
||||
return value; \
|
||||
} \
|
||||
\
|
||||
@ -987,7 +990,7 @@ BETTER_ENUMS__CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
|
||||
\
|
||||
inline const char** name_array() \
|
||||
{ \
|
||||
static const char *value[Enum::_size]; \
|
||||
static const char *value[Enum::_size_constant]; \
|
||||
return value; \
|
||||
} \
|
||||
\
|
||||
@ -1039,7 +1042,7 @@ BETTER_ENUMS__CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
|
||||
::better_enums::_trim_names(BETTER_ENUMS__NS(Enum)::raw_names(), \
|
||||
BETTER_ENUMS__NS(Enum)::name_array(), \
|
||||
BETTER_ENUMS__NS(Enum)::name_storage(), \
|
||||
_size); \
|
||||
_size()); \
|
||||
\
|
||||
BETTER_ENUMS__NS(Enum)::initialized() = true; \
|
||||
\
|
||||
|
||||
@ -69,7 +69,7 @@ template <typename Enum>
|
||||
constexpr Enum default_impl()
|
||||
{
|
||||
return
|
||||
Enum::_size < 2 ?
|
||||
Enum::_size() < 2 ?
|
||||
throw std::logic_error("enum has no valid constants") :
|
||||
Enum::_values()[0] == invalid_impl<Enum>() ?
|
||||
Enum::_values()[1] :
|
||||
|
||||
@ -17,7 +17,7 @@ template <typename Enum>
|
||||
constexpr Enum max_loop(Enum accumulator, size_t index)
|
||||
{
|
||||
return
|
||||
index >= Enum::_size ? accumulator :
|
||||
index >= Enum::_size() ? accumulator :
|
||||
Enum::_values()[index] > accumulator ?
|
||||
max_loop<Enum>(Enum::_values()[index], index + 1) :
|
||||
max_loop<Enum>(accumulator, index + 1);
|
||||
|
||||
@ -79,7 +79,7 @@ template <typename Enum>
|
||||
constexpr size_t constants_length(size_t index = 0, size_t accumulator = 0)
|
||||
{
|
||||
return
|
||||
index >= Enum::_size ? accumulator :
|
||||
index >= Enum::_size() ? accumulator :
|
||||
constants_length<Enum>(
|
||||
index + 1, accumulator
|
||||
+ string_length(", ")
|
||||
|
||||
@ -13,7 +13,7 @@ ENUM(Channel, int, Red, Green = 2, Blue)
|
||||
int main()
|
||||
{
|
||||
|
||||
for (size_t index = 0; index < Channel::_size; ++index) {
|
||||
for (size_t index = 0; index < Channel::_size(); ++index) {
|
||||
Channel channel = Channel::_values()[index];
|
||||
std::cout << channel._to_integral() << " ";
|
||||
}
|
||||
@ -21,7 +21,7 @@ int main()
|
||||
|
||||
// will print "0 2 3". And this:
|
||||
|
||||
for (size_t index = 0; index < Channel::_size; ++index) {
|
||||
for (size_t index = 0; index < Channel::_size(); ++index) {
|
||||
const char *name = Channel::_names()[index];
|
||||
std::cout << name << " ";
|
||||
}
|
||||
|
||||
@ -114,7 +114,7 @@ static_assert_1(
|
||||
static_assert_1(Channel::_is_valid("Green"));
|
||||
static_assert_1(Channel::_is_valid_nocase("green"));
|
||||
|
||||
static_assert_1(Channel::_size == 3);
|
||||
static_assert_1(Channel::_size() == 3);
|
||||
static_assert_1(Channel::_values().size() == 3);
|
||||
static_assert_1(*Channel::_values().begin() == +Channel::Red);
|
||||
static_assert_1(*(Channel::_values().end() - 1) == +Channel::Blue);
|
||||
@ -218,9 +218,9 @@ class EnumTests : public CxxTest::TestSuite {
|
||||
|
||||
void test_value_iterable()
|
||||
{
|
||||
TS_ASSERT_EQUALS(Channel::_size, 3);
|
||||
TS_ASSERT_EQUALS(Depth::_size, 2);
|
||||
TS_ASSERT_EQUALS(Channel::_values().size(), Channel::_size);
|
||||
TS_ASSERT_EQUALS(Channel::_size(), 3);
|
||||
TS_ASSERT_EQUALS(Depth::_size(), 2);
|
||||
TS_ASSERT_EQUALS(Channel::_values().size(), Channel::_size());
|
||||
TS_ASSERT_EQUALS(*Channel::_values().begin(), +Channel::Red);
|
||||
TS_ASSERT_EQUALS(*(Channel::_values().begin() + 1), +Channel::Green);
|
||||
TS_ASSERT_EQUALS(*(Channel::_values().begin() + 2), +Channel::Blue);
|
||||
@ -245,7 +245,7 @@ class EnumTests : public CxxTest::TestSuite {
|
||||
|
||||
void test_name_iterable()
|
||||
{
|
||||
TS_ASSERT_EQUALS(Channel::_names().size(), Channel::_size);
|
||||
TS_ASSERT_EQUALS(Channel::_names().size(), Channel::_size());
|
||||
TS_ASSERT_EQUALS(strcmp(*Channel::_names().begin(), "Red"), 0);
|
||||
TS_ASSERT_EQUALS(strcmp(Channel::_names()[0], "Red"), 0);
|
||||
TS_ASSERT_EQUALS(strcmp(Depth::_names()[0], "HighColor"), 0);
|
||||
|
||||
@ -19,11 +19,12 @@ struct html_color_1 {
|
||||
r(_r), g(_g), b(_b) { }
|
||||
};
|
||||
|
||||
// In C++11, can simply to struct ::better_enums::underlying_traits below.
|
||||
// In C++11, can simply use struct ::better_enums::integral_mapping below,
|
||||
// instead of having to enclose the specialization in the namespace.
|
||||
namespace better_enums {
|
||||
|
||||
template <>
|
||||
struct underlying_traits<html_color_1> {
|
||||
struct integral_mapping<html_color_1> {
|
||||
typedef unsigned int integral_representation;
|
||||
|
||||
BETTER_ENUMS__CONSTEXPR static html_color_1 from_integral(unsigned int i)
|
||||
|
||||
@ -4,5 +4,5 @@
|
||||
void print(Channel channel)
|
||||
{
|
||||
std::cout << Channel::_name() << "::" << channel._to_string() << std::endl;
|
||||
std::cout << Channel::_size << std::endl;
|
||||
std::cout << Channel::_size() << std::endl;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user