4#ifndef BETTER_ENUMS_ENUM_H
5#define BETTER_ENUMS_ENUM_H
20# if __has_feature(cxx_constexpr)
21# define BETTER_ENUMS_HAVE_CONSTEXPR
23# if !defined(__EXCEPTIONS) || !__has_feature(cxx_exceptions)
24# define BETTER_ENUMS_NO_EXCEPTIONS
27# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
28# if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6))
29# define BETTER_ENUMS_HAVE_CONSTEXPR
33# define BETTER_ENUMS_NO_EXCEPTIONS
40# define BETTER_ENUMS_HAVE_CONSTEXPR
43# if __has_feature(cxx_constexpr)
44# define BETTER_ENUMS_HAVE_CONSTEXPR
48# define BETTER_ENUMS_NO_EXCEPTIONS
51# define BETTER_ENUMS_VC2008_WORKAROUNDS
55#ifdef BETTER_ENUMS_CONSTEXPR
56# define BETTER_ENUMS_HAVE_CONSTEXPR
59#ifdef BETTER_ENUMS_NO_CONSTEXPR
60# ifdef BETTER_ENUMS_HAVE_CONSTEXPR
61# undef BETTER_ENUMS_HAVE_CONSTEXPR
73#ifdef BETTER_ENUMS_HAVE_CONSTEXPR
74# define BETTER_ENUMS_CONSTEXPR_ constexpr
75# define BETTER_ENUMS_NULLPTR nullptr
77# define BETTER_ENUMS_CONSTEXPR_
78# define BETTER_ENUMS_NULLPTR NULL
81#ifndef BETTER_ENUMS_NO_EXCEPTIONS
82# define BETTER_ENUMS_IF_EXCEPTIONS(x) x
84# define BETTER_ENUMS_IF_EXCEPTIONS(x)
88# define BETTER_ENUMS_UNUSED __attribute__((__unused__))
90# define BETTER_ENUMS_UNUSED
97#ifdef BETTER_ENUMS_MACRO_FILE
98# include BETTER_ENUMS_MACRO_FILE
101#define BETTER_ENUMS_PP_MAP(macro, data, ...) \
103 BETTER_ENUMS_APPLY( \
104 BETTER_ENUMS_PP_MAP_VAR_COUNT, \
105 BETTER_ENUMS_PP_COUNT(__VA_ARGS__)) \
106 (macro, data, __VA_ARGS__))
108#define BETTER_ENUMS_PP_MAP_VAR_COUNT(count) BETTER_ENUMS_M ## count
110#define BETTER_ENUMS_APPLY(macro, ...) BETTER_ENUMS_ID(macro(__VA_ARGS__))
112#define BETTER_ENUMS_ID(x) x
114#define BETTER_ENUMS_M1(m, d, x) m(d,0,x)
115#define BETTER_ENUMS_M2(m,d,x,...) m(d,1,x) \
116 BETTER_ENUMS_ID(BETTER_ENUMS_M1(m,d,__VA_ARGS__))
117#define BETTER_ENUMS_M3(m,d,x,...) m(d,2,x) \
118 BETTER_ENUMS_ID(BETTER_ENUMS_M2(m,d,__VA_ARGS__))
119#define BETTER_ENUMS_M4(m,d,x,...) m(d,3,x) \
120 BETTER_ENUMS_ID(BETTER_ENUMS_M3(m,d,__VA_ARGS__))
121#define BETTER_ENUMS_M5(m,d,x,...) m(d,4,x) \
122 BETTER_ENUMS_ID(BETTER_ENUMS_M4(m,d,__VA_ARGS__))
123#define BETTER_ENUMS_M6(m,d,x,...) m(d,5,x) \
124 BETTER_ENUMS_ID(BETTER_ENUMS_M5(m,d,__VA_ARGS__))
125#define BETTER_ENUMS_M7(m,d,x,...) m(d,6,x) \
126 BETTER_ENUMS_ID(BETTER_ENUMS_M6(m,d,__VA_ARGS__))
127#define BETTER_ENUMS_M8(m,d,x,...) m(d,7,x) \
128 BETTER_ENUMS_ID(BETTER_ENUMS_M7(m,d,__VA_ARGS__))
129#define BETTER_ENUMS_M9(m,d,x,...) m(d,8,x) \
130 BETTER_ENUMS_ID(BETTER_ENUMS_M8(m,d,__VA_ARGS__))
131#define BETTER_ENUMS_M10(m,d,x,...) m(d,9,x) \
132 BETTER_ENUMS_ID(BETTER_ENUMS_M9(m,d,__VA_ARGS__))
133#define BETTER_ENUMS_M11(m,d,x,...) m(d,10,x) \
134 BETTER_ENUMS_ID(BETTER_ENUMS_M10(m,d,__VA_ARGS__))
135#define BETTER_ENUMS_M12(m,d,x,...) m(d,11,x) \
136 BETTER_ENUMS_ID(BETTER_ENUMS_M11(m,d,__VA_ARGS__))
137#define BETTER_ENUMS_M13(m,d,x,...) m(d,12,x) \
138 BETTER_ENUMS_ID(BETTER_ENUMS_M12(m,d,__VA_ARGS__))
139#define BETTER_ENUMS_M14(m,d,x,...) m(d,13,x) \
140 BETTER_ENUMS_ID(BETTER_ENUMS_M13(m,d,__VA_ARGS__))
141#define BETTER_ENUMS_M15(m,d,x,...) m(d,14,x) \
142 BETTER_ENUMS_ID(BETTER_ENUMS_M14(m,d,__VA_ARGS__))
143#define BETTER_ENUMS_M16(m,d,x,...) m(d,15,x) \
144 BETTER_ENUMS_ID(BETTER_ENUMS_M15(m,d,__VA_ARGS__))
145#define BETTER_ENUMS_M17(m,d,x,...) m(d,16,x) \
146 BETTER_ENUMS_ID(BETTER_ENUMS_M16(m,d,__VA_ARGS__))
147#define BETTER_ENUMS_M18(m,d,x,...) m(d,17,x) \
148 BETTER_ENUMS_ID(BETTER_ENUMS_M17(m,d,__VA_ARGS__))
149#define BETTER_ENUMS_M19(m,d,x,...) m(d,18,x) \
150 BETTER_ENUMS_ID(BETTER_ENUMS_M18(m,d,__VA_ARGS__))
151#define BETTER_ENUMS_M20(m,d,x,...) m(d,19,x) \
152 BETTER_ENUMS_ID(BETTER_ENUMS_M19(m,d,__VA_ARGS__))
153#define BETTER_ENUMS_M21(m,d,x,...) m(d,20,x) \
154 BETTER_ENUMS_ID(BETTER_ENUMS_M20(m,d,__VA_ARGS__))
155#define BETTER_ENUMS_M22(m,d,x,...) m(d,21,x) \
156 BETTER_ENUMS_ID(BETTER_ENUMS_M21(m,d,__VA_ARGS__))
157#define BETTER_ENUMS_M23(m,d,x,...) m(d,22,x) \
158 BETTER_ENUMS_ID(BETTER_ENUMS_M22(m,d,__VA_ARGS__))
159#define BETTER_ENUMS_M24(m,d,x,...) m(d,23,x) \
160 BETTER_ENUMS_ID(BETTER_ENUMS_M23(m,d,__VA_ARGS__))
161#define BETTER_ENUMS_M25(m,d,x,...) m(d,24,x) \
162 BETTER_ENUMS_ID(BETTER_ENUMS_M24(m,d,__VA_ARGS__))
163#define BETTER_ENUMS_M26(m,d,x,...) m(d,25,x) \
164 BETTER_ENUMS_ID(BETTER_ENUMS_M25(m,d,__VA_ARGS__))
165#define BETTER_ENUMS_M27(m,d,x,...) m(d,26,x) \
166 BETTER_ENUMS_ID(BETTER_ENUMS_M26(m,d,__VA_ARGS__))
167#define BETTER_ENUMS_M28(m,d,x,...) m(d,27,x) \
168 BETTER_ENUMS_ID(BETTER_ENUMS_M27(m,d,__VA_ARGS__))
169#define BETTER_ENUMS_M29(m,d,x,...) m(d,28,x) \
170 BETTER_ENUMS_ID(BETTER_ENUMS_M28(m,d,__VA_ARGS__))
171#define BETTER_ENUMS_M30(m,d,x,...) m(d,29,x) \
172 BETTER_ENUMS_ID(BETTER_ENUMS_M29(m,d,__VA_ARGS__))
173#define BETTER_ENUMS_M31(m,d,x,...) m(d,30,x) \
174 BETTER_ENUMS_ID(BETTER_ENUMS_M30(m,d,__VA_ARGS__))
175#define BETTER_ENUMS_M32(m,d,x,...) m(d,31,x) \
176 BETTER_ENUMS_ID(BETTER_ENUMS_M31(m,d,__VA_ARGS__))
177#define BETTER_ENUMS_M33(m,d,x,...) m(d,32,x) \
178 BETTER_ENUMS_ID(BETTER_ENUMS_M32(m,d,__VA_ARGS__))
179#define BETTER_ENUMS_M34(m,d,x,...) m(d,33,x) \
180 BETTER_ENUMS_ID(BETTER_ENUMS_M33(m,d,__VA_ARGS__))
181#define BETTER_ENUMS_M35(m,d,x,...) m(d,34,x) \
182 BETTER_ENUMS_ID(BETTER_ENUMS_M34(m,d,__VA_ARGS__))
183#define BETTER_ENUMS_M36(m,d,x,...) m(d,35,x) \
184 BETTER_ENUMS_ID(BETTER_ENUMS_M35(m,d,__VA_ARGS__))
185#define BETTER_ENUMS_M37(m,d,x,...) m(d,36,x) \
186 BETTER_ENUMS_ID(BETTER_ENUMS_M36(m,d,__VA_ARGS__))
187#define BETTER_ENUMS_M38(m,d,x,...) m(d,37,x) \
188 BETTER_ENUMS_ID(BETTER_ENUMS_M37(m,d,__VA_ARGS__))
189#define BETTER_ENUMS_M39(m,d,x,...) m(d,38,x) \
190 BETTER_ENUMS_ID(BETTER_ENUMS_M38(m,d,__VA_ARGS__))
191#define BETTER_ENUMS_M40(m,d,x,...) m(d,39,x) \
192 BETTER_ENUMS_ID(BETTER_ENUMS_M39(m,d,__VA_ARGS__))
193#define BETTER_ENUMS_M41(m,d,x,...) m(d,40,x) \
194 BETTER_ENUMS_ID(BETTER_ENUMS_M40(m,d,__VA_ARGS__))
195#define BETTER_ENUMS_M42(m,d,x,...) m(d,41,x) \
196 BETTER_ENUMS_ID(BETTER_ENUMS_M41(m,d,__VA_ARGS__))
197#define BETTER_ENUMS_M43(m,d,x,...) m(d,42,x) \
198 BETTER_ENUMS_ID(BETTER_ENUMS_M42(m,d,__VA_ARGS__))
199#define BETTER_ENUMS_M44(m,d,x,...) m(d,43,x) \
200 BETTER_ENUMS_ID(BETTER_ENUMS_M43(m,d,__VA_ARGS__))
201#define BETTER_ENUMS_M45(m,d,x,...) m(d,44,x) \
202 BETTER_ENUMS_ID(BETTER_ENUMS_M44(m,d,__VA_ARGS__))
203#define BETTER_ENUMS_M46(m,d,x,...) m(d,45,x) \
204 BETTER_ENUMS_ID(BETTER_ENUMS_M45(m,d,__VA_ARGS__))
205#define BETTER_ENUMS_M47(m,d,x,...) m(d,46,x) \
206 BETTER_ENUMS_ID(BETTER_ENUMS_M46(m,d,__VA_ARGS__))
207#define BETTER_ENUMS_M48(m,d,x,...) m(d,47,x) \
208 BETTER_ENUMS_ID(BETTER_ENUMS_M47(m,d,__VA_ARGS__))
209#define BETTER_ENUMS_M49(m,d,x,...) m(d,48,x) \
210 BETTER_ENUMS_ID(BETTER_ENUMS_M48(m,d,__VA_ARGS__))
211#define BETTER_ENUMS_M50(m,d,x,...) m(d,49,x) \
212 BETTER_ENUMS_ID(BETTER_ENUMS_M49(m,d,__VA_ARGS__))
213#define BETTER_ENUMS_M51(m,d,x,...) m(d,50,x) \
214 BETTER_ENUMS_ID(BETTER_ENUMS_M50(m,d,__VA_ARGS__))
215#define BETTER_ENUMS_M52(m,d,x,...) m(d,51,x) \
216 BETTER_ENUMS_ID(BETTER_ENUMS_M51(m,d,__VA_ARGS__))
217#define BETTER_ENUMS_M53(m,d,x,...) m(d,52,x) \
218 BETTER_ENUMS_ID(BETTER_ENUMS_M52(m,d,__VA_ARGS__))
219#define BETTER_ENUMS_M54(m,d,x,...) m(d,53,x) \
220 BETTER_ENUMS_ID(BETTER_ENUMS_M53(m,d,__VA_ARGS__))
221#define BETTER_ENUMS_M55(m,d,x,...) m(d,54,x) \
222 BETTER_ENUMS_ID(BETTER_ENUMS_M54(m,d,__VA_ARGS__))
223#define BETTER_ENUMS_M56(m,d,x,...) m(d,55,x) \
224 BETTER_ENUMS_ID(BETTER_ENUMS_M55(m,d,__VA_ARGS__))
225#define BETTER_ENUMS_M57(m,d,x,...) m(d,56,x) \
226 BETTER_ENUMS_ID(BETTER_ENUMS_M56(m,d,__VA_ARGS__))
227#define BETTER_ENUMS_M58(m,d,x,...) m(d,57,x) \
228 BETTER_ENUMS_ID(BETTER_ENUMS_M57(m,d,__VA_ARGS__))
229#define BETTER_ENUMS_M59(m,d,x,...) m(d,58,x) \
230 BETTER_ENUMS_ID(BETTER_ENUMS_M58(m,d,__VA_ARGS__))
231#define BETTER_ENUMS_M60(m,d,x,...) m(d,59,x) \
232 BETTER_ENUMS_ID(BETTER_ENUMS_M59(m,d,__VA_ARGS__))
233#define BETTER_ENUMS_M61(m,d,x,...) m(d,60,x) \
234 BETTER_ENUMS_ID(BETTER_ENUMS_M60(m,d,__VA_ARGS__))
235#define BETTER_ENUMS_M62(m,d,x,...) m(d,61,x) \
236 BETTER_ENUMS_ID(BETTER_ENUMS_M61(m,d,__VA_ARGS__))
237#define BETTER_ENUMS_M63(m,d,x,...) m(d,62,x) \
238 BETTER_ENUMS_ID(BETTER_ENUMS_M62(m,d,__VA_ARGS__))
239#define BETTER_ENUMS_M64(m,d,x,...) m(d,63,x) \
240 BETTER_ENUMS_ID(BETTER_ENUMS_M63(m,d,__VA_ARGS__))
242#define BETTER_ENUMS_PP_COUNT_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
243 _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, \
244 _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
245 _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, \
246 _56, _57, _58, _59, _60, _61, _62, _63, _64, count, ...) count
248#define BETTER_ENUMS_PP_COUNT(...) \
249 BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT_IMPL(__VA_ARGS__, 64, 63, 62, 61, 60,\
250 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42,\
251 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24,\
252 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, \
255#define BETTER_ENUMS_ITERATE(X, f, l) X(f, l, 0) X(f, l, 1) X(f, l, 2) \
256 X(f, l, 3) X(f, l, 4) X(f, l, 5) X(f, l, 6) X(f, l, 7) X(f, l, 8) \
257 X(f, l, 9) X(f, l, 10) X(f, l, 11) X(f, l, 12) X(f, l, 13) X(f, l, 14) \
258 X(f, l, 15) X(f, l, 16) X(f, l, 17) X(f, l, 18) X(f, l, 19) X(f, l, 20) \
259 X(f, l, 21) X(f, l, 22) X(f, l, 23)
265namespace better_enums {
271BETTER_ENUMS_CONSTEXPR_
inline T _default()
273 return static_cast<typename T::_enumerated
>(0);
277BETTER_ENUMS_CONSTEXPR_
inline const char* _default<const char*>()
279 return BETTER_ENUMS_NULLPTR;
283BETTER_ENUMS_CONSTEXPR_
inline std::size_t _default<std::size_t>()
290 BETTER_ENUMS_CONSTEXPR_
optional() :
291 _valid(
false), _value(_default<T>()) { }
293 BETTER_ENUMS_CONSTEXPR_
optional(T v) : _valid(
true), _value(v) { }
295 BETTER_ENUMS_CONSTEXPR_
const T& operator *()
const {
return _value; }
296 BETTER_ENUMS_CONSTEXPR_
const T* operator ->()
const {
return &_value; }
298 BETTER_ENUMS_CONSTEXPR_
operator bool()
const {
return _valid; }
300 BETTER_ENUMS_CONSTEXPR_
const T& value()
const {
return _value; }
307template <
typename CastTo,
typename Element>
314#ifdef BETTER_ENUMS_VC2008_WORKAROUNDS
316#define BETTER_ENUMS_OR_THROW \
318 throw std::runtime_error(message); \
324#define BETTER_ENUMS_OR_THROW \
325 return maybe ? *maybe : throw std::runtime_error(message);
329BETTER_ENUMS_IF_EXCEPTIONS(
331BETTER_ENUMS_CONSTEXPR_
static T _or_throw(optional<T> maybe,
334 BETTER_ENUMS_OR_THROW
339BETTER_ENUMS_CONSTEXPR_
static T* _or_null(optional<T*> maybe)
341 return maybe ? *maybe : BETTER_ENUMS_NULLPTR;
351template <
typename T,
typename U>
352BETTER_ENUMS_CONSTEXPR_ U
353continue_with(T, U value) {
return value; }
359template <
typename EnumType>
361 explicit BETTER_ENUMS_CONSTEXPR_
_eat_assign(EnumType value) : _value(value)
364 template <
typename Any>
366 operator =(Any)
const {
return *
this; }
368 BETTER_ENUMS_CONSTEXPR_
operator EnumType ()
const {
return _value; }
378template <
typename Element>
380 typedef const Element* iterator;
382 BETTER_ENUMS_CONSTEXPR_ iterator begin()
const {
return iterator(_array); }
383 BETTER_ENUMS_CONSTEXPR_ iterator end()
const
384 {
return iterator(_array + _size); }
385 BETTER_ENUMS_CONSTEXPR_ std::size_t size()
const {
return _size; }
386 BETTER_ENUMS_CONSTEXPR_
const Element& operator [](std::size_t index)
const
387 {
return _array[index]; }
389 BETTER_ENUMS_CONSTEXPR_
_Iterable(
const Element *array, std::size_t s) :
390 _array(array), _size(s) { }
393 const Element *
const _array;
394 const std::size_t _size;
401BETTER_ENUMS_CONSTEXPR_
static const char *_name_enders =
"= \t\n";
403BETTER_ENUMS_CONSTEXPR_
inline bool _ends_name(
char c, std::size_t index = 0)
406 c == _name_enders[index] ? true :
407 _name_enders[index] ==
'\0' ? false :
408 _ends_name(c, index + 1);
411BETTER_ENUMS_CONSTEXPR_
inline bool _has_initializer(
const char *s,
412 std::size_t index = 0)
415 s[index] ==
'\0' ? false :
416 s[index] ==
'=' ? true :
417 _has_initializer(s, index + 1);
420BETTER_ENUMS_CONSTEXPR_
inline std::size_t
421_constant_length(
const char *s, std::size_t index = 0)
423 return _ends_name(s[index]) ? index : _constant_length(s, index + 1);
426BETTER_ENUMS_CONSTEXPR_
inline char
427_select(
const char *from, std::size_t from_length, std::size_t index)
429 return index >= from_length ?
'\0' : from[index];
432BETTER_ENUMS_CONSTEXPR_
inline char _to_lower_ascii(
char c)
434 return c >= 0x41 && c <= 0x5A ? static_cast<char>(c + 0x20) : c;
437BETTER_ENUMS_CONSTEXPR_
inline bool _names_match(
const char *stringizedName,
438 const char *referenceName,
439 std::size_t index = 0)
442 _ends_name(stringizedName[index]) ? referenceName[index] ==
'\0' :
443 referenceName[index] ==
'\0' ? false :
444 stringizedName[index] != referenceName[index] ? false :
445 _names_match(stringizedName, referenceName, index + 1);
448BETTER_ENUMS_CONSTEXPR_
inline bool
449_names_match_nocase(
const char *stringizedName,
const char *referenceName,
450 std::size_t index = 0)
453 _ends_name(stringizedName[index]) ? referenceName[index] ==
'\0' :
454 referenceName[index] ==
'\0' ? false :
455 _to_lower_ascii(stringizedName[index]) !=
456 _to_lower_ascii(referenceName[index]) ? false :
457 _names_match_nocase(stringizedName, referenceName, index + 1);
460inline void _trim_names(
const char *
const *raw_names,
461 const char **trimmed_names,
462 char *storage, std::size_t count)
464 std::size_t offset = 0;
466 for (std::size_t index = 0; index < count; ++index) {
467 trimmed_names[index] = storage + offset;
469 std::size_t trimmed_length =
470 std::strcspn(raw_names[index], _name_enders);
471 storage[offset + trimmed_length] =
'\0';
473 std::size_t raw_length = std::strlen(raw_names[index]);
474 offset += raw_length + 1;
481template <
typename Enum>
492#define BETTER_ENUMS_EAT_ASSIGN_SINGLE(EnumType, index, expression) \
493 ((::better_enums::_eat_assign<EnumType>)EnumType::expression),
495#define BETTER_ENUMS_EAT_ASSIGN(EnumType, ...) \
497 BETTER_ENUMS_PP_MAP( \
498 BETTER_ENUMS_EAT_ASSIGN_SINGLE, EnumType, __VA_ARGS__))
502#ifdef BETTER_ENUMS_HAVE_CONSTEXPR
506#define BETTER_ENUMS_SELECT_SINGLE_CHARACTER(from, from_length, index) \
507 ::better_enums::_select(from, from_length, index),
509#define BETTER_ENUMS_SELECT_CHARACTERS(from, from_length) \
510 BETTER_ENUMS_ITERATE( \
511 BETTER_ENUMS_SELECT_SINGLE_CHARACTER, from, from_length)
515#define BETTER_ENUMS_TRIM_SINGLE_STRING(ignored, index, expression) \
516constexpr std::size_t _length_ ## index = \
517 ::better_enums::_constant_length(#expression); \
518constexpr const char _trimmed_ ## index [] = \
519 { BETTER_ENUMS_SELECT_CHARACTERS(#expression, _length_ ## index) }; \
520constexpr const char *_final_ ## index = \
521 ::better_enums::_has_initializer(#expression) ? \
522 _trimmed_ ## index : #expression;
524#define BETTER_ENUMS_TRIM_STRINGS(...) \
526 BETTER_ENUMS_PP_MAP( \
527 BETTER_ENUMS_TRIM_SINGLE_STRING, ignored, __VA_ARGS__))
531#define BETTER_ENUMS_REFER_TO_SINGLE_STRING(ignored, index, expression) \
534#define BETTER_ENUMS_REFER_TO_STRINGS(...) \
536 BETTER_ENUMS_PP_MAP( \
537 BETTER_ENUMS_REFER_TO_SINGLE_STRING, ignored, __VA_ARGS__))
545#define BETTER_ENUMS_STRINGIZE_SINGLE(ignored, index, expression) #expression,
547#define BETTER_ENUMS_STRINGIZE(...) \
549 BETTER_ENUMS_PP_MAP( \
550 BETTER_ENUMS_STRINGIZE_SINGLE, ignored, __VA_ARGS__))
552#define BETTER_ENUMS_RESERVE_STORAGE_SINGLE(ignored, index, expression) \
555#define BETTER_ENUMS_RESERVE_STORAGE(...) \
557 BETTER_ENUMS_PP_MAP( \
558 BETTER_ENUMS_RESERVE_STORAGE_SINGLE, ignored, __VA_ARGS__))
564#define BETTER_ENUMS_NS(EnumType) better_enums_data_ ## EnumType
566#ifdef BETTER_ENUMS_VC2008_WORKAROUNDS
568#define BETTER_ENUMS_COPY_CONSTRUCTOR(Enum) \
569 BETTER_ENUMS_CONSTEXPR_ Enum(const Enum &other) : \
570 _value(other._value) { }
574#define BETTER_ENUMS_COPY_CONSTRUCTOR(Enum)
578#define BETTER_ENUMS_TYPE(SetUnderlyingType, SwitchType, GenerateSwitchType, \
579 GenerateStrings, ToStringConstexpr, \
580 DeclareInitialize, DefineInitialize, CallInitialize, \
581 Enum, Underlying, ...) \
583namespace better_enums_data_ ## Enum { \
585BETTER_ENUMS_ID(GenerateSwitchType(Underlying, __VA_ARGS__)) \
591 typedef ::better_enums::optional<Enum> _optional; \
592 typedef ::better_enums::optional<std::size_t> _optional_index; \
595 typedef Underlying _integral; \
597 enum _enumerated SetUnderlyingType(Underlying) { __VA_ARGS__ }; \
599 BETTER_ENUMS_CONSTEXPR_ Enum(_enumerated value) : _value(value) { } \
601 BETTER_ENUMS_COPY_CONSTRUCTOR(Enum) \
603 BETTER_ENUMS_CONSTEXPR_ operator SwitchType(Enum)() const \
605 return SwitchType(Enum)(_value); \
608 BETTER_ENUMS_CONSTEXPR_ _integral _to_integral() const; \
609 BETTER_ENUMS_IF_EXCEPTIONS( \
610 BETTER_ENUMS_CONSTEXPR_ static Enum _from_integral(_integral value); \
612 BETTER_ENUMS_CONSTEXPR_ static Enum \
613 _from_integral_unchecked(_integral value); \
614 BETTER_ENUMS_CONSTEXPR_ static _optional \
615 _from_integral_nothrow(_integral value); \
617 ToStringConstexpr const char* _to_string() const; \
618 BETTER_ENUMS_IF_EXCEPTIONS( \
619 BETTER_ENUMS_CONSTEXPR_ static Enum _from_string(const char *name); \
621 BETTER_ENUMS_CONSTEXPR_ static _optional \
622 _from_string_nothrow(const char *name); \
624 BETTER_ENUMS_IF_EXCEPTIONS( \
625 BETTER_ENUMS_CONSTEXPR_ static Enum _from_string_nocase(const char *name); \
627 BETTER_ENUMS_CONSTEXPR_ static _optional \
628 _from_string_nocase_nothrow(const char *name); \
630 BETTER_ENUMS_CONSTEXPR_ static bool _is_valid(_integral value); \
631 BETTER_ENUMS_CONSTEXPR_ static bool _is_valid(const char *name); \
632 BETTER_ENUMS_CONSTEXPR_ static bool _is_valid_nocase(const char *name); \
634 typedef ::better_enums::_Iterable<Enum> _value_iterable; \
635 typedef ::better_enums::_Iterable<const char*> _name_iterable; \
637 typedef _value_iterable::iterator _value_iterator; \
638 typedef _name_iterable::iterator _name_iterator; \
640 BETTER_ENUMS_CONSTEXPR_ static const std::size_t _size_constant = \
641 BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT(__VA_ARGS__)); \
642 BETTER_ENUMS_CONSTEXPR_ static std::size_t _size() \
643 { return _size_constant; } \
645 BETTER_ENUMS_CONSTEXPR_ static const char* _name(); \
646 BETTER_ENUMS_CONSTEXPR_ static _value_iterable _values(); \
647 ToStringConstexpr static _name_iterable _names(); \
651 BETTER_ENUMS_DEFAULT_CONSTRUCTOR(Enum) \
654 explicit BETTER_ENUMS_CONSTEXPR_ Enum(const _integral &value) : \
659 BETTER_ENUMS_CONSTEXPR_ static _optional_index \
660 _from_value_loop(_integral value, std::size_t index = 0); \
661 BETTER_ENUMS_CONSTEXPR_ static _optional_index \
662 _from_string_loop(const char *name, std::size_t index = 0); \
663 BETTER_ENUMS_CONSTEXPR_ static _optional_index \
664 _from_string_nocase_loop(const char *name, std::size_t index = 0); \
666 friend struct ::better_enums::_initialize_at_program_start<Enum>; \
669namespace better_enums_data_ ## Enum { \
671static ::better_enums::_initialize_at_program_start<Enum> \
672 _force_initialization; \
674enum _PutNamesInThisScopeAlso { __VA_ARGS__ }; \
676BETTER_ENUMS_CONSTEXPR_ const Enum _value_array[] = \
677 { BETTER_ENUMS_ID(BETTER_ENUMS_EAT_ASSIGN(Enum, __VA_ARGS__)) }; \
679BETTER_ENUMS_ID(GenerateStrings(Enum, __VA_ARGS__)) \
683BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
685operator +(Enum::_enumerated enumerated) \
687 return static_cast<Enum>(enumerated); \
690BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional_index \
691Enum::_from_value_loop(Enum::_integral value, std::size_t index) \
695 _optional_index() : \
696 BETTER_ENUMS_NS(Enum)::_value_array[index]._value == value ? \
697 _optional_index(index) : \
698 _from_value_loop(value, index + 1); \
701BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional_index \
702Enum::_from_string_loop(const char *name, std::size_t index) \
705 index == _size() ? _optional_index() : \
706 ::better_enums::_names_match( \
707 BETTER_ENUMS_NS(Enum)::_raw_names()[index], name) ? \
708 _optional_index(index) : \
709 _from_string_loop(name, index + 1); \
712BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional_index \
713Enum::_from_string_nocase_loop(const char *name, std::size_t index) \
716 index == _size() ? _optional_index() : \
717 ::better_enums::_names_match_nocase( \
718 BETTER_ENUMS_NS(Enum)::_raw_names()[index], name) ? \
719 _optional_index(index) : \
720 _from_string_nocase_loop(name, index + 1); \
723BETTER_ENUMS_CONSTEXPR_ inline Enum::_integral Enum::_to_integral() const \
725 return _integral(_value); \
728BETTER_ENUMS_CONSTEXPR_ inline Enum \
729Enum::_from_integral_unchecked(_integral value) \
731 return static_cast<_enumerated>(value); \
734BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional \
735Enum::_from_integral_nothrow(_integral value) \
738 ::better_enums::_map_index<Enum>(BETTER_ENUMS_NS(Enum)::_value_array, \
739 _from_value_loop(value)); \
742BETTER_ENUMS_IF_EXCEPTIONS( \
743BETTER_ENUMS_CONSTEXPR_ inline Enum Enum::_from_integral(_integral value) \
746 ::better_enums::_or_throw(_from_integral_nothrow(value), \
747 #Enum "::_from_integral: invalid argument"); \
751ToStringConstexpr inline const char* Enum::_to_string() const \
754 ::better_enums::_or_null( \
755 ::better_enums::_map_index<const char*>( \
756 BETTER_ENUMS_NS(Enum)::_name_array(), \
757 _from_value_loop(CallInitialize(_value)))); \
760BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional \
761Enum::_from_string_nothrow(const char *name) \
764 ::better_enums::_map_index<Enum>( \
765 BETTER_ENUMS_NS(Enum)::_value_array, _from_string_loop(name)); \
768BETTER_ENUMS_IF_EXCEPTIONS( \
769BETTER_ENUMS_CONSTEXPR_ inline Enum Enum::_from_string(const char *name) \
772 ::better_enums::_or_throw(_from_string_nothrow(name), \
773 #Enum "::_from_string: invalid argument"); \
777BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional \
778Enum::_from_string_nocase_nothrow(const char *name) \
781 ::better_enums::_map_index<Enum>(BETTER_ENUMS_NS(Enum)::_value_array, \
782 _from_string_nocase_loop(name)); \
785BETTER_ENUMS_IF_EXCEPTIONS( \
786BETTER_ENUMS_CONSTEXPR_ inline Enum Enum::_from_string_nocase(const char *name)\
789 ::better_enums::_or_throw( \
790 _from_string_nocase_nothrow(name), \
791 #Enum "::_from_string_nocase: invalid argument"); \
795BETTER_ENUMS_CONSTEXPR_ inline bool Enum::_is_valid(_integral value) \
797 return _from_value_loop(value); \
800BETTER_ENUMS_CONSTEXPR_ inline bool Enum::_is_valid(const char *name) \
802 return _from_string_loop(name); \
805BETTER_ENUMS_CONSTEXPR_ inline bool Enum::_is_valid_nocase(const char *name) \
807 return _from_string_nocase_loop(name); \
810BETTER_ENUMS_CONSTEXPR_ inline const char* Enum::_name() \
815BETTER_ENUMS_CONSTEXPR_ inline Enum::_value_iterable Enum::_values() \
817 return _value_iterable(BETTER_ENUMS_NS(Enum)::_value_array, _size()); \
820ToStringConstexpr inline Enum::_name_iterable Enum::_names() \
823 _name_iterable(BETTER_ENUMS_NS(Enum)::_name_array(), \
824 CallInitialize(_size())); \
827DefineInitialize(Enum) \
829BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
830inline bool operator ==(const Enum &a, const Enum &b) \
831 { return a._to_integral() == b._to_integral(); } \
833BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
834inline bool operator !=(const Enum &a, const Enum &b) \
835 { return a._to_integral() != b._to_integral(); } \
837BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
838inline bool operator <(const Enum &a, const Enum &b) \
839 { return a._to_integral() < b._to_integral(); } \
841BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
842inline bool operator <=(const Enum &a, const Enum &b) \
843 { return a._to_integral() <= b._to_integral(); } \
845BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
846inline bool operator >(const Enum &a, const Enum &b) \
847 { return a._to_integral() > b._to_integral(); } \
849BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
850inline bool operator >=(const Enum &a, const Enum &b) \
851 { return a._to_integral() >= b._to_integral(); } \
854template <typename Char, typename Traits> \
855std::basic_ostream<Char, Traits>& \
856operator <<(std::basic_ostream<Char, Traits>& stream, const Enum &value) \
858 return stream << value._to_string(); \
861template <typename Char, typename Traits> \
862std::basic_istream<Char, Traits>& \
863operator >>(std::basic_istream<Char, Traits>& stream, Enum &value) \
865 std::basic_string<Char, Traits> buffer; \
868 ::better_enums::optional<Enum> converted = \
869 Enum::_from_string_nothrow(buffer.c_str()); \
872 value = *converted; \
874 stream.setstate(std::basic_istream<Char, Traits>::failbit); \
884#define BETTER_ENUMS_CXX98_UNDERLYING_TYPE(Underlying)
887#define BETTER_ENUMS_CXX11_UNDERLYING_TYPE(Underlying) \
890#if defined(_MSC_VER) && _MSC_VER >= 1700
893# define BETTER_ENUMS_LEGACY_UNDERLYING_TYPE(Underlying) BETTER_ENUMS_CXX11_UNDERLYING_TYPE(Underlying)
895# define BETTER_ENUMS_LEGACY_UNDERLYING_TYPE(Underlying) BETTER_ENUMS_CXX98_UNDERLYING_TYPE(Underlying)
899#define BETTER_ENUMS_REGULAR_ENUM_SWITCH_TYPE(Type) \
903#define BETTER_ENUMS_ENUM_CLASS_SWITCH_TYPE(Type) \
904 BETTER_ENUMS_NS(Type)::_EnumClassForSwitchStatements
907#define BETTER_ENUMS_REGULAR_ENUM_SWITCH_TYPE_GENERATE(Underlying, ...)
910#define BETTER_ENUMS_ENUM_CLASS_SWITCH_TYPE_GENERATE(Underlying, ...) \
911 enum class _EnumClassForSwitchStatements : Underlying { __VA_ARGS__ };
914#define BETTER_ENUMS_CXX98_TRIM_STRINGS_ARRAYS(Enum, ...) \
915 inline const char** _raw_names() \
917 static const char *value[] = \
918 { BETTER_ENUMS_ID(BETTER_ENUMS_STRINGIZE(__VA_ARGS__)) }; \
922 inline char* _name_storage() \
924 static char storage[] = \
925 BETTER_ENUMS_ID(BETTER_ENUMS_RESERVE_STORAGE(__VA_ARGS__)); \
929 inline const char** _name_array() \
931 static const char *value[Enum::_size_constant]; \
935 inline bool& _initialized() \
937 static bool value = false; \
942#define BETTER_ENUMS_CXX11_PARTIAL_CONSTEXPR_TRIM_STRINGS_ARRAYS(Enum, ...) \
943 constexpr const char *_the_raw_names[] = \
944 { BETTER_ENUMS_ID(BETTER_ENUMS_STRINGIZE(__VA_ARGS__)) }; \
946 constexpr const char * const * _raw_names() \
948 return _the_raw_names; \
951 inline char* _name_storage() \
953 static char storage[] = \
954 BETTER_ENUMS_ID(BETTER_ENUMS_RESERVE_STORAGE(__VA_ARGS__)); \
958 inline const char** _name_array() \
960 static const char *value[Enum::_size_constant]; \
964 inline bool& _initialized() \
966 static bool value = false; \
971#define BETTER_ENUMS_CXX11_FULL_CONSTEXPR_TRIM_STRINGS_ARRAYS(Enum, ...) \
972 BETTER_ENUMS_ID(BETTER_ENUMS_TRIM_STRINGS(__VA_ARGS__)) \
974 constexpr const char * const _the_name_array[] = \
975 { BETTER_ENUMS_ID(BETTER_ENUMS_REFER_TO_STRINGS(__VA_ARGS__)) }; \
977 constexpr const char * const * _name_array() \
979 return _the_name_array; \
982 constexpr const char * const * _raw_names() \
984 return _the_name_array; \
988#define BETTER_ENUMS_NO_CONSTEXPR_TO_STRING_KEYWORD
991#define BETTER_ENUMS_CONSTEXPR_TO_STRING_KEYWORD \
995#define BETTER_ENUMS_DO_DECLARE_INITIALIZE \
996 static int initialize();
999#define BETTER_ENUMS_DECLARE_EMPTY_INITIALIZE \
1000 static int initialize() { return 0; }
1003#define BETTER_ENUMS_DO_DEFINE_INITIALIZE(Enum) \
1004 inline int Enum::initialize() \
1006 if (BETTER_ENUMS_NS(Enum)::_initialized()) \
1009 ::better_enums::_trim_names(BETTER_ENUMS_NS(Enum)::_raw_names(), \
1010 BETTER_ENUMS_NS(Enum)::_name_array(), \
1011 BETTER_ENUMS_NS(Enum)::_name_storage(), \
1014 BETTER_ENUMS_NS(Enum)::_initialized() = true; \
1020#define BETTER_ENUMS_DO_NOT_DEFINE_INITIALIZE(Enum)
1023#define BETTER_ENUMS_DO_CALL_INITIALIZE(value) \
1024 ::better_enums::continue_with(initialize(), value)
1027#define BETTER_ENUMS_DO_NOT_CALL_INITIALIZE(value) \
1034#ifdef BETTER_ENUMS_STRICT_CONVERSION
1035# define BETTER_ENUMS_DEFAULT_SWITCH_TYPE \
1036 BETTER_ENUMS_ENUM_CLASS_SWITCH_TYPE
1037# define BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE \
1038 BETTER_ENUMS_ENUM_CLASS_SWITCH_TYPE_GENERATE
1040# define BETTER_ENUMS_DEFAULT_SWITCH_TYPE \
1041 BETTER_ENUMS_REGULAR_ENUM_SWITCH_TYPE
1042# define BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE \
1043 BETTER_ENUMS_REGULAR_ENUM_SWITCH_TYPE_GENERATE
1048#ifndef BETTER_ENUMS_DEFAULT_CONSTRUCTOR
1049# define BETTER_ENUMS_DEFAULT_CONSTRUCTOR(Enum) \
1051 Enum() : _value(0) { }
1056#ifdef BETTER_ENUMS_HAVE_CONSTEXPR
1058#ifdef BETTER_ENUMS_CONSTEXPR_TO_STRING
1059# define BETTER_ENUMS_DEFAULT_TRIM_STRINGS_ARRAYS \
1060 BETTER_ENUMS_CXX11_FULL_CONSTEXPR_TRIM_STRINGS_ARRAYS
1061# define BETTER_ENUMS_DEFAULT_TO_STRING_KEYWORD \
1062 BETTER_ENUMS_CONSTEXPR_TO_STRING_KEYWORD
1063# define BETTER_ENUMS_DEFAULT_DECLARE_INITIALIZE \
1064 BETTER_ENUMS_DECLARE_EMPTY_INITIALIZE
1065# define BETTER_ENUMS_DEFAULT_DEFINE_INITIALIZE \
1066 BETTER_ENUMS_DO_NOT_DEFINE_INITIALIZE
1067# define BETTER_ENUMS_DEFAULT_CALL_INITIALIZE \
1068 BETTER_ENUMS_DO_NOT_CALL_INITIALIZE
1070# define BETTER_ENUMS_DEFAULT_TRIM_STRINGS_ARRAYS \
1071 BETTER_ENUMS_CXX11_PARTIAL_CONSTEXPR_TRIM_STRINGS_ARRAYS
1072# define BETTER_ENUMS_DEFAULT_TO_STRING_KEYWORD \
1073 BETTER_ENUMS_NO_CONSTEXPR_TO_STRING_KEYWORD
1074# define BETTER_ENUMS_DEFAULT_DECLARE_INITIALIZE \
1075 BETTER_ENUMS_DO_DECLARE_INITIALIZE
1076# define BETTER_ENUMS_DEFAULT_DEFINE_INITIALIZE \
1077 BETTER_ENUMS_DO_DEFINE_INITIALIZE
1078# define BETTER_ENUMS_DEFAULT_CALL_INITIALIZE \
1079 BETTER_ENUMS_DO_CALL_INITIALIZE
1086#define BETTER_ENUM(Enum, Underlying, ...) \
1087 BETTER_ENUMS_ID(BETTER_ENUMS_TYPE( \
1088 BETTER_ENUMS_CXX11_UNDERLYING_TYPE, \
1089 BETTER_ENUMS_DEFAULT_SWITCH_TYPE, \
1090 BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE, \
1091 BETTER_ENUMS_DEFAULT_TRIM_STRINGS_ARRAYS, \
1092 BETTER_ENUMS_DEFAULT_TO_STRING_KEYWORD, \
1093 BETTER_ENUMS_DEFAULT_DECLARE_INITIALIZE, \
1094 BETTER_ENUMS_DEFAULT_DEFINE_INITIALIZE, \
1095 BETTER_ENUMS_DEFAULT_CALL_INITIALIZE, \
1096 Enum, Underlying, __VA_ARGS__))
1098#define SLOW_ENUM(Enum, Underlying, ...) \
1099 BETTER_ENUMS_ID(BETTER_ENUMS_TYPE( \
1100 BETTER_ENUMS_CXX11_UNDERLYING_TYPE, \
1101 BETTER_ENUMS_DEFAULT_SWITCH_TYPE, \
1102 BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE, \
1103 BETTER_ENUMS_CXX11_FULL_CONSTEXPR_TRIM_STRINGS_ARRAYS, \
1104 BETTER_ENUMS_CONSTEXPR_TO_STRING_KEYWORD, \
1105 BETTER_ENUMS_DECLARE_EMPTY_INITIALIZE, \
1106 BETTER_ENUMS_DO_NOT_DEFINE_INITIALIZE, \
1107 BETTER_ENUMS_DO_NOT_CALL_INITIALIZE, \
1108 Enum, Underlying, __VA_ARGS__))
1112#define BETTER_ENUM(Enum, Underlying, ...) \
1113 BETTER_ENUMS_ID(BETTER_ENUMS_TYPE( \
1114 BETTER_ENUMS_LEGACY_UNDERLYING_TYPE, \
1115 BETTER_ENUMS_DEFAULT_SWITCH_TYPE, \
1116 BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE, \
1117 BETTER_ENUMS_CXX98_TRIM_STRINGS_ARRAYS, \
1118 BETTER_ENUMS_NO_CONSTEXPR_TO_STRING_KEYWORD, \
1119 BETTER_ENUMS_DO_DECLARE_INITIALIZE, \
1120 BETTER_ENUMS_DO_DEFINE_INITIALIZE, \
1121 BETTER_ENUMS_DO_CALL_INITIALIZE, \
1122 Enum, Underlying, __VA_ARGS__))
1128namespace better_enums {
1132template <
typename T>
1134 BETTER_ENUMS_CONSTEXPR_
static bool less(
const T& a,
const T& b)
1140 BETTER_ENUMS_CONSTEXPR_
static bool less(
const char *a,
const char *b)
1141 {
return less_loop(a, b); }
1144 BETTER_ENUMS_CONSTEXPR_
static bool
1145 less_loop(
const char *a,
const char *b,
size_t index = 0)
1148 a[index] != b[index] ? a[index] < b[index] :
1149 a[index] ==
'\0' ? false :
1150 less_loop(a, b, index + 1);
1157 BETTER_ENUMS_CONSTEXPR_
static bool less(
const wchar_t *a,
const wchar_t *b)
1158 {
return less_loop(a, b); }
1161 BETTER_ENUMS_CONSTEXPR_
static bool
1162 less_loop(
const wchar_t *a,
const wchar_t *b,
size_t index = 0)
1165 a[index] != b[index] ? a[index] < b[index] :
1166 a[index] == L
'\0' ? false :
1167 less_loop(a, b, index + 1);
1171template <
typename Enum,
typename T,
typename Compare = map_compare<T> >
1173 typedef T (*function)(Enum);
1175 BETTER_ENUMS_CONSTEXPR_
explicit map(function f) : _f(f) { }
1177 BETTER_ENUMS_CONSTEXPR_ T from_enum(Enum value)
const {
return _f(value); }
1178 BETTER_ENUMS_CONSTEXPR_ T operator [](Enum value)
const
1179 {
return _f(value); }
1181 BETTER_ENUMS_CONSTEXPR_ Enum to_enum(T value)
const
1184 _or_throw(to_enum_nothrow(value),
"map::to_enum: invalid argument");
1188 to_enum_nothrow(T value,
size_t index = 0)
const
1192 Compare::less(_f(Enum::_values()[index]), value) ||
1193 Compare::less(value, _f(Enum::_values()[index])) ?
1194 to_enum_nothrow(value, index + 1) :
1195 Enum::_values()[index];
1202template <
typename Enum,
typename T>
1203BETTER_ENUMS_CONSTEXPR_
map<Enum, T> make_map(T (*f)(Enum))