Fixed problem with multiple compilation units under C++98.

This commit is contained in:
Anton Bachin 2015-05-23 15:56:05 -05:00
parent 6bcca9bc8c
commit d0e4d9ffaa

107
enum.h
View File

@ -168,19 +168,19 @@
namespace better_enums { namespace better_enums {
template <typename T> template <typename T>
_ENUM_CONSTEXPR T _default() _ENUM_CONSTEXPR inline T _default()
{ {
return (typename T::_enumerated)0; return (typename T::_enumerated)0;
} }
template <> template <>
_ENUM_CONSTEXPR const char* _default<const char*>() _ENUM_CONSTEXPR inline const char* _default<const char*>()
{ {
return nullptr; return nullptr;
} }
template <> template <>
_ENUM_CONSTEXPR size_t _default<size_t>() _ENUM_CONSTEXPR inline size_t _default<size_t>()
{ {
return 0; return 0;
} }
@ -263,7 +263,7 @@ struct _Iterable {
_ENUM_CONSTEXPR bool _endsName(char c, size_t index = 0) _ENUM_CONSTEXPR inline bool _endsName(char c, size_t index = 0)
{ {
return return
// First, test whether c is equal to the current character in // First, test whether c is equal to the current character in
@ -278,7 +278,7 @@ _ENUM_CONSTEXPR bool _endsName(char c, size_t index = 0)
_endsName(c, index + 1); _endsName(c, index + 1);
} }
_ENUM_CONSTEXPR bool _hasExplicitValue(const char *s, size_t index = 0) _ENUM_CONSTEXPR inline bool _hasExplicitValue(const char *s, size_t index = 0)
{ {
return return
s[index] == '\0' ? false : s[index] == '\0' ? false :
@ -286,42 +286,34 @@ _ENUM_CONSTEXPR bool _hasExplicitValue(const char *s, size_t index = 0)
_hasExplicitValue(s, index + 1); _hasExplicitValue(s, index + 1);
} }
_ENUM_CONSTEXPR size_t _constantLength(const char *s, size_t index = 0) _ENUM_CONSTEXPR inline size_t _constantLength(const char *s, size_t index = 0)
{ {
return _endsName(s[index]) ? index : _constantLength(s, index + 1); return _endsName(s[index]) ? index : _constantLength(s, index + 1);
} }
_ENUM_CONSTEXPR char _select(const char *from, size_t from_length, size_t index) _ENUM_CONSTEXPR inline char _select(const char *from, size_t from_length,
size_t index)
{ {
return index >= from_length ? '\0' : from[index]; return index >= from_length ? '\0' : from[index];
} }
_ENUM_CONSTEXPR char _toLowercaseAscii(char c) _ENUM_CONSTEXPR inline char _toLowercaseAscii(char c)
{ {
return c >= 0x41 && c <= 0x5A ? (char) (c + 0x20) : c; return c >= 0x41 && c <= 0x5A ? (char) (c + 0x20) : c;
} }
_ENUM_CONSTEXPR bool _namesMatch(const char *stringizedName, _ENUM_CONSTEXPR inline bool _namesMatch(const char *stringizedName,
const char *referenceName, const char *referenceName,
size_t index = 0) size_t index = 0)
{ {
return return
// If the current character in the stringized name is a name ender,
// return true if the reference name ends as well, and false otherwise.
_endsName(stringizedName[index]) ? referenceName[index] == '\0' : _endsName(stringizedName[index]) ? referenceName[index] == '\0' :
// The current character in the stringized name is not a name ender. If
// the reference name ended, then it is too short, so return false.
referenceName[index] == '\0' ? false : referenceName[index] == '\0' ? false :
// Neither name has ended. If the two current characters don't match, stringizedName[index] != referenceName[index] ? false :
// return false.
stringizedName[index] !=
referenceName[index] ? false :
// Otherwise, if the characters match, continue by comparing the rest of
// the names.
_namesMatch(stringizedName, referenceName, index + 1); _namesMatch(stringizedName, referenceName, index + 1);
} }
_ENUM_CONSTEXPR bool _namesMatchNocase(const char *stringizedName, _ENUM_CONSTEXPR inline bool _namesMatchNocase(const char *stringizedName,
const char *referenceName, const char *referenceName,
size_t index = 0) size_t index = 0)
{ {
@ -374,7 +366,6 @@ constexpr const char *_final_ ## index = \
#include <cstring> #include <cstring>
// #include <map>
#define _ENUM_STRINGIZE_SINGLE(ignored, index, expression) #expression, #define _ENUM_STRINGIZE_SINGLE(ignored, index, expression) #expression,
@ -475,7 +466,7 @@ class Enum : public _ENUM_NS(Enum)::Base { \
return \ return \
_enum::_or_throw( \ _enum::_or_throw( \
_enum::_map_index<const char*>( \ _enum::_map_index<const char*>( \
_ENUM_NS(Enum)::name_array, \ _ENUM_NS(Enum)::name_array(), \
_from_int_loop(CallInitialize(_value))), \ _from_int_loop(CallInitialize(_value))), \
"Enum::to_string: invalid enum value"); \ "Enum::to_string: invalid enum value"); \
} \ } \
@ -551,7 +542,8 @@ class Enum : public _ENUM_NS(Enum)::Base { \
_ENUM_CONSTEXPR static _name_iterable _names_() \ _ENUM_CONSTEXPR static _name_iterable _names_() \
{ \ { \
return \ return \
_name_iterable(_ENUM_NS(Enum)::name_array, CallInitialize(_size)); \ _name_iterable(_ENUM_NS(Enum)::name_array(), \
CallInitialize(_size)); \
} \ } \
\ \
ShortIterableAliases(Enum) \ ShortIterableAliases(Enum) \
@ -576,7 +568,7 @@ class Enum : public _ENUM_NS(Enum)::Base { \
{ \ { \
return \ return \
index == _size ? _optional_index() : \ index == _size ? _optional_index() : \
_enum::_namesMatch(_ENUM_NS(Enum)::name_array[index], name) ? \ _enum::_namesMatch(_ENUM_NS(Enum)::name_array()[index], name) ? \
_optional_index(index) : \ _optional_index(index) : \
_from_string_loop(name, index + 1); \ _from_string_loop(name, index + 1); \
} \ } \
@ -587,32 +579,32 @@ class Enum : public _ENUM_NS(Enum)::Base { \
return \ return \
index == _size ? _optional_index() : \ index == _size ? _optional_index() : \
_enum::_namesMatchNocase( \ _enum::_namesMatchNocase( \
_ENUM_NS(Enum)::name_array[index], name) ? \ _ENUM_NS(Enum)::name_array()[index], name) ? \
_optional_index(index) : \ _optional_index(index) : \
_from_string_nocase_loop(name, index + 1); \ _from_string_nocase_loop(name, index + 1); \
} \ } \
}; \ }; \
\ \
_ENUM_CONSTEXPR const Enum operator +(Enum::_enumerated enumerated) \ _ENUM_CONSTEXPR inline const Enum operator +(Enum::_enumerated enumerated) \
{ return (Enum)enumerated; } \ { return (Enum)enumerated; } \
\ \
namespace _enum { \ namespace _enum { \
namespace _data_ ## Enum { \ namespace _data_ ## Enum { \
\ \
_ENUM_CONSTEXPR const Enum operator +(_ENUM_NS(Enum)::Base base) \ _ENUM_CONSTEXPR inline const Enum operator +(_ENUM_NS(Enum)::Base base) \
{ return (Enum)base; } \ { return (Enum)base; } \
\ \
_ENUM_CONSTEXPR bool operator ==(const Enum &a, const Enum &b) \ _ENUM_CONSTEXPR inline bool operator ==(const Enum &a, const Enum &b) \
{ return a._value == b._value; } \ { return a._value == b._value; } \
_ENUM_CONSTEXPR bool operator !=(const Enum &a, const Enum &b) \ _ENUM_CONSTEXPR inline bool operator !=(const Enum &a, const Enum &b) \
{ return a._value != b._value; } \ { return a._value != b._value; } \
_ENUM_CONSTEXPR bool operator <(const Enum &a, const Enum &b) \ _ENUM_CONSTEXPR inline bool operator <(const Enum &a, const Enum &b) \
{ return a._value < b._value; } \ { return a._value < b._value; } \
_ENUM_CONSTEXPR bool operator <=(const Enum &a, const Enum &b) \ _ENUM_CONSTEXPR inline bool operator <=(const Enum &a, const Enum &b) \
{ return a._value <= b._value; } \ { return a._value <= b._value; } \
_ENUM_CONSTEXPR bool operator >(const Enum &a, const Enum &b) \ _ENUM_CONSTEXPR inline bool operator >(const Enum &a, const Enum &b) \
{ return a._value > b._value; } \ { return a._value > b._value; } \
_ENUM_CONSTEXPR bool operator >=(const Enum &a, const Enum &b) \ _ENUM_CONSTEXPR inline bool operator >=(const Enum &a, const Enum &b) \
{ return a._value >= b._value; } \ { return a._value >= b._value; } \
\ \
} \ } \
@ -656,7 +648,7 @@ _ENUM_CONSTEXPR bool operator >=(const Enum &a, const Enum &b) \
// C++11 // C++11
#define _ENUM_SHORT_ITERABLE_DECLARATIONS \ #define _ENUM_SHORT_ITERABLE_DECLARATIONS \
constexpr const _Iterable<Base> values{value_array, size}; \ constexpr const _Iterable<Base> values{value_array, size}; \
constexpr const _Iterable<const char*> names{name_array, size}; constexpr const _Iterable<const char*> names{name_array(), size};
// C++98, C++11 // C++98, C++11
#define _ENUM_SHORT_ITERABLE_ALIASES_NOT_AVAILABLE(Enum) #define _ENUM_SHORT_ITERABLE_ALIASES_NOT_AVAILABLE(Enum)
@ -667,30 +659,53 @@ _ENUM_CONSTEXPR bool operator >=(const Enum &a, const Enum &b) \
constexpr static const _name_iterable &_names = _ENUM_NS(Enum)::names; \ constexpr static const _name_iterable &_names = _ENUM_NS(Enum)::names; \
constexpr static const char *_name = #Enum; constexpr static const char *_name = #Enum;
// C++98, C++11 fast version // C++98
#define _ENUM_GENERATE_STRINGS_PREPARE_FOR_RUNTIME(...) \ #define _ENUM_GENERATE_STRINGS_PREPARE_FOR_RUNTIME_WRAPPED(...) \
_ENUM_CONSTEXPR const char *raw_names[] = \ inline const char** raw_names() \
{ _ENUM_STRINGIZE(__VA_ARGS__) }; \ { \
_ENUM_CONSTEXPR const char *name_array[size]; \ static const char* value[] = { _ENUM_STRINGIZE(__VA_ARGS__) }; \
return value; \
} \
\
inline const char** name_array() \
{ \
static const char* value[size]; \
return value; \
} \
\
inline bool& initialized() \
{ \
static bool value = false; \
return value; \
}
// C++11 fast version
#define _ENUM_GENERATE_STRINGS_PREPARE_FOR_RUNTIME_CONSTEXPR(...) \
constexpr const char *raw_names[] = { _ENUM_STRINGIZE(__VA_ARGS__) }; \
const char *name_array[size]; \
bool initialized = false; bool initialized = false;
// C++11 slow all-constexpr version // C++11 slow all-constexpr version
#define _ENUM_GENERATE_STRINGS_COMPILE_TIME(...) \ #define _ENUM_GENERATE_STRINGS_COMPILE_TIME(...) \
_ENUM_TRIM_STRINGS(__VA_ARGS__) \ _ENUM_TRIM_STRINGS(__VA_ARGS__) \
constexpr const char * const name_array[] = \ constexpr const char * const the_name_array[] = \
{ _ENUM_REFER_TO_STRINGS(__VA_ARGS__) }; { _ENUM_REFER_TO_STRINGS(__VA_ARGS__) }; \
constexpr const char * const * name_array() \
{ \
return the_name_array; \
}
// C++98, C++11 fast version // C++98, C++11 fast version
#define _ENUM_DEFINE_INITIALIZE(Enum) \ #define _ENUM_DEFINE_INITIALIZE(Enum) \
static int initialize() \ static int initialize() \
{ \ { \
if (_ENUM_NS(Enum)::initialized) \ if (_ENUM_NS(Enum)::initialized()) \
return 0; \ return 0; \
\ \
_enum::_trim_names(_ENUM_NS(Enum)::raw_names, \ _enum::_trim_names(_ENUM_NS(Enum)::raw_names(), \
_ENUM_NS(Enum)::name_array, _size); \ _ENUM_NS(Enum)::name_array(), _size); \
\ \
_ENUM_NS(Enum)::initialized = true; \ _ENUM_NS(Enum)::initialized() = true; \
\ \
return 0; \ return 0; \
} }
@ -731,7 +746,7 @@ _ENUM_CONSTEXPR bool operator >=(const Enum &a, const Enum &b) \
_ENUM_GENERATE_SWITCH_TYPE_REGULAR_ENUM, \ _ENUM_GENERATE_SWITCH_TYPE_REGULAR_ENUM, \
_ENUM_SHORT_ITERABLE_DECLARATIONS_NOT_AVAILABLE, \ _ENUM_SHORT_ITERABLE_DECLARATIONS_NOT_AVAILABLE, \
_ENUM_SHORT_ITERABLE_ALIASES_NOT_AVAILABLE, \ _ENUM_SHORT_ITERABLE_ALIASES_NOT_AVAILABLE, \
_ENUM_GENERATE_STRINGS_PREPARE_FOR_RUNTIME, \ _ENUM_GENERATE_STRINGS_PREPARE_FOR_RUNTIME_WRAPPED, \
_ENUM_DEFINE_INITIALIZE, \ _ENUM_DEFINE_INITIALIZE, \
_ENUM_CALL_INITIALIZE, \ _ENUM_CALL_INITIALIZE, \
Enum, Integral, __VA_ARGS__) Enum, Integral, __VA_ARGS__)