From fc609e58aa98e11b4f2a0b0b2ec130b58815e7a5 Mon Sep 17 00:00:00 2001 From: Anton Bachin Date: Mon, 15 Jun 2015 10:48:05 -0500 Subject: [PATCH] Internal clean-up. --- enum.h | 151 +++++++++++++++++++++++++++----------------- test/link/helper.cc | 1 + 2 files changed, 93 insertions(+), 59 deletions(-) diff --git a/enum.h b/enum.h index af672e1..3e0f619 100644 --- a/enum.h +++ b/enum.h @@ -15,6 +15,8 @@ +// Feature detection. + #ifdef __GNUC__ # ifdef __clang__ # if __has_feature(cxx_constexpr) @@ -89,6 +91,8 @@ +// Higher-order preprocessor macros. + #ifdef BETTER_ENUMS_MACRO_FILE # include BETTER_ENUMS_MACRO_FILE #else @@ -257,23 +261,11 @@ -#define BETTER_ENUMS__EAT_ASSIGN_SINGLE(EnumType, index, expression) \ - ((::better_enums::_eat_assign)EnumType::expression), - -#define BETTER_ENUMS__EAT_ASSIGN(EnumType, ...) \ - BETTER_ENUMS__ID( \ - BETTER_ENUMS__PP_MAP( \ - BETTER_ENUMS__EAT_ASSIGN_SINGLE, EnumType, __VA_ARGS__)) - - - -#define BETTER_ENUMS__NS(EnumType) better_enums::_data_ ## EnumType -#define BETTER_ENUMS__NAME_ENDERS "= \t\n" - - - namespace better_enums { + +// Optional type. + template BETTER_ENUMS__CONSTEXPR inline T _default() { @@ -335,11 +327,18 @@ BETTER_ENUMS__CONSTEXPR static T* _or_null(optional maybe) +// Functional sequencing. This is essentially a comma operator wrapped in a +// constexpr function. g++ 4.7 doesn't "accept" integral constants in the second +// position for the comma operator, and emits an external symbol, which then +// causes a linking error. + template BETTER_ENUMS__CONSTEXPR U continue_with(T ignored, U value) { return value; } +// Values array declaration helper. + template struct _eat_assign { explicit BETTER_ENUMS__CONSTEXPR _eat_assign(EnumType value) : _value(value) @@ -357,6 +356,8 @@ struct _eat_assign { +// Iterables. + template struct _Iterable { typedef const Element* iterator; @@ -378,27 +379,31 @@ struct _Iterable { -BETTER_ENUMS__CONSTEXPR inline bool _endsName(char c, std::size_t index = 0) +// String routines. + +BETTER_ENUMS__CONSTEXPR static const char *_name_enders = "= \t\n"; + +BETTER_ENUMS__CONSTEXPR inline bool _ends_name(char c, std::size_t index = 0) { return - c == BETTER_ENUMS__NAME_ENDERS[index] ? true : - BETTER_ENUMS__NAME_ENDERS[index] == '\0' ? false : - _endsName(c, index + 1); + c == _name_enders[index] ? true : + _name_enders[index] == '\0' ? false : + _ends_name(c, index + 1); } -BETTER_ENUMS__CONSTEXPR inline bool _hasExplicitValue(const char *s, - std::size_t index = 0) +BETTER_ENUMS__CONSTEXPR inline bool _has_initializer(const char *s, + std::size_t index = 0) { return s[index] == '\0' ? false : s[index] == '=' ? true : - _hasExplicitValue(s, index + 1); + _has_initializer(s, index + 1); } BETTER_ENUMS__CONSTEXPR inline std::size_t -_constantLength(const char *s, std::size_t index = 0) +_constant_length(const char *s, std::size_t index = 0) { - return _endsName(s[index]) ? index : _constantLength(s, index + 1); + return _ends_name(s[index]) ? index : _constant_length(s, index + 1); } BETTER_ENUMS__CONSTEXPR inline char @@ -407,32 +412,32 @@ _select(const char *from, std::size_t from_length, std::size_t index) return index >= from_length ? '\0' : from[index]; } -BETTER_ENUMS__CONSTEXPR inline char _toLowercaseAscii(char c) +BETTER_ENUMS__CONSTEXPR inline char _to_lower_ascii(char c) { return c >= 0x41 && c <= 0x5A ? (char)(c + 0x20) : c; } -BETTER_ENUMS__CONSTEXPR inline bool _namesMatch(const char *stringizedName, - const char *referenceName, - std::size_t index = 0) +BETTER_ENUMS__CONSTEXPR inline bool _names_match(const char *stringizedName, + const char *referenceName, + std::size_t index = 0) { return - _endsName(stringizedName[index]) ? referenceName[index] == '\0' : + _ends_name(stringizedName[index]) ? referenceName[index] == '\0' : referenceName[index] == '\0' ? false : stringizedName[index] != referenceName[index] ? false : - _namesMatch(stringizedName, referenceName, index + 1); + _names_match(stringizedName, referenceName, index + 1); } BETTER_ENUMS__CONSTEXPR inline bool -_namesMatchNocase(const char *stringizedName, const char *referenceName, - std::size_t index = 0) +_names_match_nocase(const char *stringizedName, const char *referenceName, + std::size_t index = 0) { return - _endsName(stringizedName[index]) ? referenceName[index] == '\0' : + _ends_name(stringizedName[index]) ? referenceName[index] == '\0' : referenceName[index] == '\0' ? false : - _toLowercaseAscii(stringizedName[index]) != - _toLowercaseAscii(referenceName[index]) ? false : - _namesMatchNocase(stringizedName, referenceName, index + 1); + _to_lower_ascii(stringizedName[index]) != + _to_lower_ascii(referenceName[index]) ? false : + _names_match_nocase(stringizedName, referenceName, index + 1); } inline void _trim_names(const char * const *raw_names, @@ -445,7 +450,7 @@ inline void _trim_names(const char * const *raw_names, trimmed_names[index] = storage + offset; std::size_t trimmed_length = - std::strcspn(raw_names[index], BETTER_ENUMS__NAME_ENDERS); + std::strcspn(raw_names[index], _name_enders); storage[offset + trimmed_length] = '\0'; std::size_t raw_length = std::strlen(raw_names[index]); @@ -455,45 +460,47 @@ inline void _trim_names(const char * const *raw_names, +// General underlying types. + // This template is unfortunately necessary (?) due to the lack of // in C++98. , this template could be replaced with a // combination of std::conditional and std::is_integral. template -struct representation { typedef typename T::integral_representation type; }; +struct _representation { typedef typename T::integral_representation type; }; -template <> struct representation { typedef bool type; }; -template <> struct representation { typedef char type; }; -template <> struct representation { typedef wchar_t type; }; -template <> struct representation { typedef signed char type; }; -template <> struct representation +template <> struct _representation { typedef bool type; }; +template <> struct _representation { typedef char type; }; +template <> struct _representation { typedef wchar_t type; }; +template <> struct _representation { typedef signed char type; }; +template <> struct _representation { typedef unsigned char type; }; -template <> struct representation { typedef short type; }; -template <> struct representation +template <> struct _representation { typedef short type; }; +template <> struct _representation { typedef unsigned short type; }; -template <> struct representation { typedef int type; }; -template <> struct representation { typedef unsigned int type; }; -template <> struct representation { typedef long type; }; -template <> struct representation +template <> struct _representation { typedef int type; }; +template <> struct _representation { typedef unsigned int type; }; +template <> struct _representation { typedef long type; }; +template <> struct _representation { typedef unsigned long type; }; #ifdef BETTER_ENUMS__HAVE_LONG_LONG -template <> struct representation { typedef long long type; }; -template <> struct representation +template <> struct _representation { typedef long long type; }; +template <> struct _representation { typedef unsigned long long type; }; #endif #ifdef BETTER_ENUMS__HAVE_NEW_CHAR_TYPES -template <> struct representation { typedef char16_t type; }; -template <> struct representation { typedef char32_t type; }; +template <> struct _representation { typedef char16_t type; }; +template <> struct _representation { typedef char32_t type; }; #endif template struct underlying_traits { - typedef typename representation::type integral_representation; + typedef typename _representation::type integral_representation; BETTER_ENUMS__CONSTEXPR static integral_representation to_integral(const T &v) { return (integral_representation)v; } @@ -507,6 +514,18 @@ struct underlying_traits { +// Array generation macros. + +#define BETTER_ENUMS__EAT_ASSIGN_SINGLE(EnumType, index, expression) \ + ((::better_enums::_eat_assign)EnumType::expression), + +#define BETTER_ENUMS__EAT_ASSIGN(EnumType, ...) \ + BETTER_ENUMS__ID( \ + BETTER_ENUMS__PP_MAP( \ + BETTER_ENUMS__EAT_ASSIGN_SINGLE, EnumType, __VA_ARGS__)) + + + #ifdef BETTER_ENUMS__HAVE_CONSTEXPR @@ -522,11 +541,11 @@ struct underlying_traits { #define BETTER_ENUMS__TRIM_SINGLE_STRING(ignored, index, expression) \ constexpr std::size_t _length_ ## index = \ - ::better_enums::_constantLength(#expression); \ + ::better_enums::_constant_length(#expression); \ constexpr const char _trimmed_ ## index [] = \ { BETTER_ENUMS__SELECT_CHARACTERS(#expression, _length_ ## index) }; \ constexpr const char *_final_ ## index = \ - ::better_enums::_hasExplicitValue(#expression) ? \ + ::better_enums::_has_initializer(#expression) ? \ _trimmed_ ## index : #expression; #define BETTER_ENUMS__TRIM_STRINGS(...) \ @@ -567,6 +586,8 @@ constexpr const char *_final_ ## index = \ +// The enums proper. + // TODO Convert integral to underlying only at the last possible moment, if the // integral value is valid. This should prevent unexpected behavior. For this to // work, the underlying values array must store the integral equivalents. That @@ -576,6 +597,8 @@ constexpr const char *_final_ ## index = \ // TODO Choose the right return type semantics once the _values array // representation is chosen: values if integral, const references if underlying. +#define BETTER_ENUMS__NS(EnumType) better_enums::_data_ ## EnumType + #define BETTER_ENUMS__TYPE(SetUnderlyingType, SwitchType, GenerateSwitchType, \ GenerateStrings, ToStringConstexpr, \ DeclareInitialize, DefineInitialize, CallInitialize,\ @@ -851,8 +874,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::_names_match( \ + BETTER_ENUMS__NS(Enum)::raw_names()[index], name) ? \ _optional_index(index) : \ _from_string_loop(name, index + 1); \ } \ @@ -862,7 +885,7 @@ Enum::_from_string_nocase_loop(const char *name, std::size_t index) \ { \ return \ index == _size ? _optional_index() : \ - ::better_enums::_namesMatchNocase( \ + ::better_enums::_names_match_nocase( \ BETTER_ENUMS__NS(Enum)::raw_names()[index], name) ? \ _optional_index(index) : \ _from_string_nocase_loop(name, index + 1); \ @@ -880,6 +903,8 @@ BETTER_ENUMS__CONSTEXPR inline bool operator !=(const Enum &a, const Enum &b) \ +// Enum feature options. + // C++98, C++11 #define BETTER_ENUMS__CXX98_UNDERLYING_TYPE(Underlying) @@ -1022,6 +1047,8 @@ BETTER_ENUMS__CONSTEXPR inline bool operator !=(const Enum &a, const Enum &b) \ +// User feature selection. + #ifdef BETTER_ENUMS_STRICT_CONVERSION # define BETTER_ENUMS__DEFAULT_SWITCH_TYPE \ BETTER_ENUMS__ENUM_CLASS_SWITCH_TYPE @@ -1062,6 +1089,10 @@ BETTER_ENUMS__CONSTEXPR inline bool operator !=(const Enum &a, const Enum &b) \ BETTER_ENUMS__DO_CALL_INITIALIZE #endif + + +// Top-level macros. + #define ENUM(Enum, Underlying, ...) \ BETTER_ENUMS__ID(BETTER_ENUMS__TYPE( \ BETTER_ENUMS__CXX11_UNDERLYING_TYPE, \ @@ -1106,6 +1137,8 @@ BETTER_ENUMS__CONSTEXPR inline bool operator !=(const Enum &a, const Enum &b) \ namespace better_enums { +// Stream I/O operators. + // This template is used as a sort of enable_if for SFINAE. It should be // possible to use std::enable_if, however is not available in // C++98. Non-char streams are currently not supported. diff --git a/test/link/helper.cc b/test/link/helper.cc index e95846f..09289d2 100644 --- a/test/link/helper.cc +++ b/test/link/helper.cc @@ -4,4 +4,5 @@ void print(Channel channel) { std::cout << Channel::_name() << "::" << channel._to_string() << std::endl; + std::cout << Channel::_size << std::endl; }