enum.h
1 // This file is part of Better Enums, released under the BSD 2-clause license.
2 // See LICENSE.md for details, or visit http://github.com/aantron/better-enums.
3 
4 #pragma once
5 
6 #ifndef BETTER_ENUMS_ENUM_H
7 #define BETTER_ENUMS_ENUM_H
8 
9 
10 
11 #include <cstddef>
12 #include <cstring>
13 #include <iosfwd>
14 #include <stdexcept>
15 
16 
17 // in-line, non-#pragma warning handling
18 // not supported in very old compilers (namely gcc 4.4 or less)
19 #ifdef __GNUC__
20 # ifdef __clang__
21 # define BETTER_ENUMS_IGNORE_OLD_CAST_HEADER _Pragma("clang diagnostic push")
22 # define BETTER_ENUMS_IGNORE_OLD_CAST_BEGIN _Pragma("clang diagnostic ignored \"-Wold-style-cast\"")
23 # define BETTER_ENUMS_IGNORE_OLD_CAST_END _Pragma("clang diagnostic pop")
24 # else
25 # define BETTER_ENUMS_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100)
26 # if BETTER_ENUMS_GCC_VERSION > 40400
27 # define BETTER_ENUMS_IGNORE_OLD_CAST_HEADER _Pragma("GCC diagnostic push")
28 # define BETTER_ENUMS_IGNORE_OLD_CAST_BEGIN _Pragma("GCC diagnostic ignored \"-Wold-style-cast\"")
29 # define BETTER_ENUMS_IGNORE_OLD_CAST_END _Pragma("GCC diagnostic pop")
30 # if (BETTER_ENUMS_GCC_VERSION >= 70300)
31 # define BETTER_ENUMS_IGNORE_ATTRIBUTES_HEADER _Pragma("GCC diagnostic push")
32 # define BETTER_ENUMS_IGNORE_ATTRIBUTES_BEGIN _Pragma("GCC diagnostic ignored \"-Wattributes\"")
33 # define BETTER_ENUMS_IGNORE_ATTRIBUTES_END _Pragma("GCC diagnostic pop")
34 # else
35 # define BETTER_ENUMS_IGNORE_ATTRIBUTES_HEADER
36 # define BETTER_ENUMS_IGNORE_ATTRIBUTES_BEGIN
37 # define BETTER_ENUMS_IGNORE_ATTRIBUTES_END
38 # endif
39 # else
40 # define BETTER_ENUMS_IGNORE_OLD_CAST_HEADER
41 # define BETTER_ENUMS_IGNORE_OLD_CAST_BEGIN
42 # define BETTER_ENUMS_IGNORE_OLD_CAST_END
43 # define BETTER_ENUMS_IGNORE_ATTRIBUTES_HEADER
44 # define BETTER_ENUMS_IGNORE_ATTRIBUTES_BEGIN
45 # define BETTER_ENUMS_IGNORE_ATTRIBUTES_END
46 # endif
47 # endif
48 #else // empty definitions for compilers that don't support _Pragma
49 # define BETTER_ENUMS_IGNORE_OLD_CAST_HEADER
50 # define BETTER_ENUMS_IGNORE_OLD_CAST_BEGIN
51 # define BETTER_ENUMS_IGNORE_OLD_CAST_END
52 # define BETTER_ENUMS_IGNORE_ATTRIBUTES_HEADER
53 # define BETTER_ENUMS_IGNORE_ATTRIBUTES_BEGIN
54 # define BETTER_ENUMS_IGNORE_ATTRIBUTES_END
55 #endif
56 
57 // Feature detection.
58 
59 #ifdef __GNUC__
60 # ifdef __clang__
61 # if __has_feature(cxx_constexpr)
62 # define BETTER_ENUMS_HAVE_CONSTEXPR
63 # endif
64 # if !defined(__EXCEPTIONS) || !__has_feature(cxx_exceptions)
65 # define BETTER_ENUMS_NO_EXCEPTIONS
66 # endif
67 # else
68 # if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
69 # if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6))
70 # define BETTER_ENUMS_HAVE_CONSTEXPR
71 # endif
72 # endif
73 # ifndef __EXCEPTIONS
74 # define BETTER_ENUMS_NO_EXCEPTIONS
75 # endif
76 # endif
77 #endif
78 
79 #ifdef _MSC_VER
80 # if _MSC_VER >= 1911
81 # define BETTER_ENUMS_HAVE_CONSTEXPR
82 # endif
83 # ifdef __clang__
84 # if __has_feature(cxx_constexpr)
85 # define BETTER_ENUMS_HAVE_CONSTEXPR
86 # endif
87 # endif
88 # ifndef _CPPUNWIND
89 # define BETTER_ENUMS_NO_EXCEPTIONS
90 # endif
91 # if _MSC_VER < 1600
92 # define BETTER_ENUMS_VC2008_WORKAROUNDS
93 # endif
94 #endif
95 
96 #ifdef BETTER_ENUMS_CONSTEXPR
97 # define BETTER_ENUMS_HAVE_CONSTEXPR
98 #endif
99 
100 #ifdef BETTER_ENUMS_NO_CONSTEXPR
101 # ifdef BETTER_ENUMS_HAVE_CONSTEXPR
102 # undef BETTER_ENUMS_HAVE_CONSTEXPR
103 # endif
104 #endif
105 
106 // GCC (and maybe clang) can be made to warn about using 0 or NULL when nullptr
107 // is available, so Better Enums tries to use nullptr. This passage uses
108 // availability of constexpr as a proxy for availability of nullptr, i.e. it
109 // assumes that nullptr is available when compiling on the right versions of gcc
110 // and clang with the right -std flag. This is actually slightly wrong, because
111 // nullptr is also available in Visual C++, but constexpr isn't. This
112 // imprecision doesn't matter, however, because VC++ doesn't have the warnings
113 // that make using nullptr necessary.
114 #ifdef BETTER_ENUMS_HAVE_CONSTEXPR
115 # define BETTER_ENUMS_CONSTEXPR_ constexpr
116 # define BETTER_ENUMS_NULLPTR nullptr
117 #else
118 # define BETTER_ENUMS_CONSTEXPR_
119 # define BETTER_ENUMS_NULLPTR NULL
120 #endif
121 
122 #ifndef BETTER_ENUMS_NO_EXCEPTIONS
123 # define BETTER_ENUMS_IF_EXCEPTIONS(x) x
124 #else
125 # define BETTER_ENUMS_IF_EXCEPTIONS(x)
126 #endif
127 
128 #ifdef __GNUC__
129 # define BETTER_ENUMS_UNUSED __attribute__((__unused__))
130 #else
131 # define BETTER_ENUMS_UNUSED
132 #endif
133 
134 
135 
136 // Higher-order preprocessor macros.
137 
138 #ifdef BETTER_ENUMS_MACRO_FILE
139 # include BETTER_ENUMS_MACRO_FILE
140 #else
141 
142 #define BETTER_ENUMS_PP_MAP(macro, data, ...) \
143  BETTER_ENUMS_ID( \
144  BETTER_ENUMS_APPLY( \
145  BETTER_ENUMS_PP_MAP_VAR_COUNT, \
146  BETTER_ENUMS_PP_COUNT(__VA_ARGS__)) \
147  (macro, data, __VA_ARGS__))
148 
149 #define BETTER_ENUMS_PP_MAP_VAR_COUNT(count) BETTER_ENUMS_M ## count
150 
151 #define BETTER_ENUMS_APPLY(macro, ...) BETTER_ENUMS_ID(macro(__VA_ARGS__))
152 
153 #define BETTER_ENUMS_ID(x) x
154 
155 #define BETTER_ENUMS_M1(m, d, x) m(d,0,x)
156 #define BETTER_ENUMS_M2(m,d,x,...) m(d,1,x) \
157  BETTER_ENUMS_ID(BETTER_ENUMS_M1(m,d,__VA_ARGS__))
158 #define BETTER_ENUMS_M3(m,d,x,...) m(d,2,x) \
159  BETTER_ENUMS_ID(BETTER_ENUMS_M2(m,d,__VA_ARGS__))
160 #define BETTER_ENUMS_M4(m,d,x,...) m(d,3,x) \
161  BETTER_ENUMS_ID(BETTER_ENUMS_M3(m,d,__VA_ARGS__))
162 #define BETTER_ENUMS_M5(m,d,x,...) m(d,4,x) \
163  BETTER_ENUMS_ID(BETTER_ENUMS_M4(m,d,__VA_ARGS__))
164 #define BETTER_ENUMS_M6(m,d,x,...) m(d,5,x) \
165  BETTER_ENUMS_ID(BETTER_ENUMS_M5(m,d,__VA_ARGS__))
166 #define BETTER_ENUMS_M7(m,d,x,...) m(d,6,x) \
167  BETTER_ENUMS_ID(BETTER_ENUMS_M6(m,d,__VA_ARGS__))
168 #define BETTER_ENUMS_M8(m,d,x,...) m(d,7,x) \
169  BETTER_ENUMS_ID(BETTER_ENUMS_M7(m,d,__VA_ARGS__))
170 #define BETTER_ENUMS_M9(m,d,x,...) m(d,8,x) \
171  BETTER_ENUMS_ID(BETTER_ENUMS_M8(m,d,__VA_ARGS__))
172 #define BETTER_ENUMS_M10(m,d,x,...) m(d,9,x) \
173  BETTER_ENUMS_ID(BETTER_ENUMS_M9(m,d,__VA_ARGS__))
174 #define BETTER_ENUMS_M11(m,d,x,...) m(d,10,x) \
175  BETTER_ENUMS_ID(BETTER_ENUMS_M10(m,d,__VA_ARGS__))
176 #define BETTER_ENUMS_M12(m,d,x,...) m(d,11,x) \
177  BETTER_ENUMS_ID(BETTER_ENUMS_M11(m,d,__VA_ARGS__))
178 #define BETTER_ENUMS_M13(m,d,x,...) m(d,12,x) \
179  BETTER_ENUMS_ID(BETTER_ENUMS_M12(m,d,__VA_ARGS__))
180 #define BETTER_ENUMS_M14(m,d,x,...) m(d,13,x) \
181  BETTER_ENUMS_ID(BETTER_ENUMS_M13(m,d,__VA_ARGS__))
182 #define BETTER_ENUMS_M15(m,d,x,...) m(d,14,x) \
183  BETTER_ENUMS_ID(BETTER_ENUMS_M14(m,d,__VA_ARGS__))
184 #define BETTER_ENUMS_M16(m,d,x,...) m(d,15,x) \
185  BETTER_ENUMS_ID(BETTER_ENUMS_M15(m,d,__VA_ARGS__))
186 #define BETTER_ENUMS_M17(m,d,x,...) m(d,16,x) \
187  BETTER_ENUMS_ID(BETTER_ENUMS_M16(m,d,__VA_ARGS__))
188 #define BETTER_ENUMS_M18(m,d,x,...) m(d,17,x) \
189  BETTER_ENUMS_ID(BETTER_ENUMS_M17(m,d,__VA_ARGS__))
190 #define BETTER_ENUMS_M19(m,d,x,...) m(d,18,x) \
191  BETTER_ENUMS_ID(BETTER_ENUMS_M18(m,d,__VA_ARGS__))
192 #define BETTER_ENUMS_M20(m,d,x,...) m(d,19,x) \
193  BETTER_ENUMS_ID(BETTER_ENUMS_M19(m,d,__VA_ARGS__))
194 #define BETTER_ENUMS_M21(m,d,x,...) m(d,20,x) \
195  BETTER_ENUMS_ID(BETTER_ENUMS_M20(m,d,__VA_ARGS__))
196 #define BETTER_ENUMS_M22(m,d,x,...) m(d,21,x) \
197  BETTER_ENUMS_ID(BETTER_ENUMS_M21(m,d,__VA_ARGS__))
198 #define BETTER_ENUMS_M23(m,d,x,...) m(d,22,x) \
199  BETTER_ENUMS_ID(BETTER_ENUMS_M22(m,d,__VA_ARGS__))
200 #define BETTER_ENUMS_M24(m,d,x,...) m(d,23,x) \
201  BETTER_ENUMS_ID(BETTER_ENUMS_M23(m,d,__VA_ARGS__))
202 #define BETTER_ENUMS_M25(m,d,x,...) m(d,24,x) \
203  BETTER_ENUMS_ID(BETTER_ENUMS_M24(m,d,__VA_ARGS__))
204 #define BETTER_ENUMS_M26(m,d,x,...) m(d,25,x) \
205  BETTER_ENUMS_ID(BETTER_ENUMS_M25(m,d,__VA_ARGS__))
206 #define BETTER_ENUMS_M27(m,d,x,...) m(d,26,x) \
207  BETTER_ENUMS_ID(BETTER_ENUMS_M26(m,d,__VA_ARGS__))
208 #define BETTER_ENUMS_M28(m,d,x,...) m(d,27,x) \
209  BETTER_ENUMS_ID(BETTER_ENUMS_M27(m,d,__VA_ARGS__))
210 #define BETTER_ENUMS_M29(m,d,x,...) m(d,28,x) \
211  BETTER_ENUMS_ID(BETTER_ENUMS_M28(m,d,__VA_ARGS__))
212 #define BETTER_ENUMS_M30(m,d,x,...) m(d,29,x) \
213  BETTER_ENUMS_ID(BETTER_ENUMS_M29(m,d,__VA_ARGS__))
214 #define BETTER_ENUMS_M31(m,d,x,...) m(d,30,x) \
215  BETTER_ENUMS_ID(BETTER_ENUMS_M30(m,d,__VA_ARGS__))
216 #define BETTER_ENUMS_M32(m,d,x,...) m(d,31,x) \
217  BETTER_ENUMS_ID(BETTER_ENUMS_M31(m,d,__VA_ARGS__))
218 #define BETTER_ENUMS_M33(m,d,x,...) m(d,32,x) \
219  BETTER_ENUMS_ID(BETTER_ENUMS_M32(m,d,__VA_ARGS__))
220 #define BETTER_ENUMS_M34(m,d,x,...) m(d,33,x) \
221  BETTER_ENUMS_ID(BETTER_ENUMS_M33(m,d,__VA_ARGS__))
222 #define BETTER_ENUMS_M35(m,d,x,...) m(d,34,x) \
223  BETTER_ENUMS_ID(BETTER_ENUMS_M34(m,d,__VA_ARGS__))
224 #define BETTER_ENUMS_M36(m,d,x,...) m(d,35,x) \
225  BETTER_ENUMS_ID(BETTER_ENUMS_M35(m,d,__VA_ARGS__))
226 #define BETTER_ENUMS_M37(m,d,x,...) m(d,36,x) \
227  BETTER_ENUMS_ID(BETTER_ENUMS_M36(m,d,__VA_ARGS__))
228 #define BETTER_ENUMS_M38(m,d,x,...) m(d,37,x) \
229  BETTER_ENUMS_ID(BETTER_ENUMS_M37(m,d,__VA_ARGS__))
230 #define BETTER_ENUMS_M39(m,d,x,...) m(d,38,x) \
231  BETTER_ENUMS_ID(BETTER_ENUMS_M38(m,d,__VA_ARGS__))
232 #define BETTER_ENUMS_M40(m,d,x,...) m(d,39,x) \
233  BETTER_ENUMS_ID(BETTER_ENUMS_M39(m,d,__VA_ARGS__))
234 #define BETTER_ENUMS_M41(m,d,x,...) m(d,40,x) \
235  BETTER_ENUMS_ID(BETTER_ENUMS_M40(m,d,__VA_ARGS__))
236 #define BETTER_ENUMS_M42(m,d,x,...) m(d,41,x) \
237  BETTER_ENUMS_ID(BETTER_ENUMS_M41(m,d,__VA_ARGS__))
238 #define BETTER_ENUMS_M43(m,d,x,...) m(d,42,x) \
239  BETTER_ENUMS_ID(BETTER_ENUMS_M42(m,d,__VA_ARGS__))
240 #define BETTER_ENUMS_M44(m,d,x,...) m(d,43,x) \
241  BETTER_ENUMS_ID(BETTER_ENUMS_M43(m,d,__VA_ARGS__))
242 #define BETTER_ENUMS_M45(m,d,x,...) m(d,44,x) \
243  BETTER_ENUMS_ID(BETTER_ENUMS_M44(m,d,__VA_ARGS__))
244 #define BETTER_ENUMS_M46(m,d,x,...) m(d,45,x) \
245  BETTER_ENUMS_ID(BETTER_ENUMS_M45(m,d,__VA_ARGS__))
246 #define BETTER_ENUMS_M47(m,d,x,...) m(d,46,x) \
247  BETTER_ENUMS_ID(BETTER_ENUMS_M46(m,d,__VA_ARGS__))
248 #define BETTER_ENUMS_M48(m,d,x,...) m(d,47,x) \
249  BETTER_ENUMS_ID(BETTER_ENUMS_M47(m,d,__VA_ARGS__))
250 #define BETTER_ENUMS_M49(m,d,x,...) m(d,48,x) \
251  BETTER_ENUMS_ID(BETTER_ENUMS_M48(m,d,__VA_ARGS__))
252 #define BETTER_ENUMS_M50(m,d,x,...) m(d,49,x) \
253  BETTER_ENUMS_ID(BETTER_ENUMS_M49(m,d,__VA_ARGS__))
254 #define BETTER_ENUMS_M51(m,d,x,...) m(d,50,x) \
255  BETTER_ENUMS_ID(BETTER_ENUMS_M50(m,d,__VA_ARGS__))
256 #define BETTER_ENUMS_M52(m,d,x,...) m(d,51,x) \
257  BETTER_ENUMS_ID(BETTER_ENUMS_M51(m,d,__VA_ARGS__))
258 #define BETTER_ENUMS_M53(m,d,x,...) m(d,52,x) \
259  BETTER_ENUMS_ID(BETTER_ENUMS_M52(m,d,__VA_ARGS__))
260 #define BETTER_ENUMS_M54(m,d,x,...) m(d,53,x) \
261  BETTER_ENUMS_ID(BETTER_ENUMS_M53(m,d,__VA_ARGS__))
262 #define BETTER_ENUMS_M55(m,d,x,...) m(d,54,x) \
263  BETTER_ENUMS_ID(BETTER_ENUMS_M54(m,d,__VA_ARGS__))
264 #define BETTER_ENUMS_M56(m,d,x,...) m(d,55,x) \
265  BETTER_ENUMS_ID(BETTER_ENUMS_M55(m,d,__VA_ARGS__))
266 #define BETTER_ENUMS_M57(m,d,x,...) m(d,56,x) \
267  BETTER_ENUMS_ID(BETTER_ENUMS_M56(m,d,__VA_ARGS__))
268 #define BETTER_ENUMS_M58(m,d,x,...) m(d,57,x) \
269  BETTER_ENUMS_ID(BETTER_ENUMS_M57(m,d,__VA_ARGS__))
270 #define BETTER_ENUMS_M59(m,d,x,...) m(d,58,x) \
271  BETTER_ENUMS_ID(BETTER_ENUMS_M58(m,d,__VA_ARGS__))
272 #define BETTER_ENUMS_M60(m,d,x,...) m(d,59,x) \
273  BETTER_ENUMS_ID(BETTER_ENUMS_M59(m,d,__VA_ARGS__))
274 #define BETTER_ENUMS_M61(m,d,x,...) m(d,60,x) \
275  BETTER_ENUMS_ID(BETTER_ENUMS_M60(m,d,__VA_ARGS__))
276 #define BETTER_ENUMS_M62(m,d,x,...) m(d,61,x) \
277  BETTER_ENUMS_ID(BETTER_ENUMS_M61(m,d,__VA_ARGS__))
278 #define BETTER_ENUMS_M63(m,d,x,...) m(d,62,x) \
279  BETTER_ENUMS_ID(BETTER_ENUMS_M62(m,d,__VA_ARGS__))
280 #define BETTER_ENUMS_M64(m,d,x,...) m(d,63,x) \
281  BETTER_ENUMS_ID(BETTER_ENUMS_M63(m,d,__VA_ARGS__))
282 
283 #define BETTER_ENUMS_PP_COUNT_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
284  _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, \
285  _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
286  _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, \
287  _56, _57, _58, _59, _60, _61, _62, _63, _64, count, ...) count
288 
289 #define BETTER_ENUMS_PP_COUNT(...) \
290  BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT_IMPL(__VA_ARGS__, 64, 63, 62, 61, 60,\
291  59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42,\
292  41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24,\
293  23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, \
294  4, 3, 2, 1))
295 
296 #define BETTER_ENUMS_ITERATE(X, f, l) X(f, l, 0) X(f, l, 1) X(f, l, 2) \
297  X(f, l, 3) X(f, l, 4) X(f, l, 5) X(f, l, 6) X(f, l, 7) X(f, l, 8) \
298  X(f, l, 9) X(f, l, 10) X(f, l, 11) X(f, l, 12) X(f, l, 13) X(f, l, 14) \
299  X(f, l, 15) X(f, l, 16) X(f, l, 17) X(f, l, 18) X(f, l, 19) X(f, l, 20) \
300  X(f, l, 21) X(f, l, 22) X(f, l, 23)
301 
302 #endif // #ifdef BETTER_ENUMS_MACRO_FILE else case
303 
304 
305 
306 namespace better_enums {
307 
308 
309 // Optional type.
310 
311 template <typename T>
312 BETTER_ENUMS_CONSTEXPR_ inline T _default()
313 {
314  return static_cast<typename T::_enumerated>(0);
315 }
316 
317 template <>
318 BETTER_ENUMS_CONSTEXPR_ inline const char* _default<const char*>()
319 {
320  return BETTER_ENUMS_NULLPTR;
321 }
322 
323 template <>
324 BETTER_ENUMS_CONSTEXPR_ inline std::size_t _default<std::size_t>()
325 {
326  return 0;
327 }
328 
329 template <typename T>
330 struct optional {
331  BETTER_ENUMS_CONSTEXPR_ optional() :
332  _valid(false), _value(_default<T>()) { }
333 
334  BETTER_ENUMS_CONSTEXPR_ optional(T v) : _valid(true), _value(v) { }
335 
336  BETTER_ENUMS_CONSTEXPR_ const T& operator *() const { return _value; }
337  BETTER_ENUMS_CONSTEXPR_ const T* operator ->() const { return &_value; }
338 
339  BETTER_ENUMS_CONSTEXPR_ operator bool() const { return _valid; }
340 
341  BETTER_ENUMS_CONSTEXPR_ const T& value() const { return _value; }
342 
343  private:
344  bool _valid;
345  T _value;
346 };
347 
348 template <typename CastTo, typename Element>
349 BETTER_ENUMS_CONSTEXPR_ static optional<CastTo>
350 _map_index(const Element *array, optional<std::size_t> index)
351 {
352  return index ? static_cast<CastTo>(array[*index]) : optional<CastTo>();
353 }
354 
355 #ifdef BETTER_ENUMS_VC2008_WORKAROUNDS
356 
357 #define BETTER_ENUMS_OR_THROW \
358  if (!maybe) \
359  throw std::runtime_error(message); \
360  \
361  return *maybe;
362 
363 #else
364 
365 #define BETTER_ENUMS_OR_THROW \
366  return maybe ? *maybe : throw std::runtime_error(message);
367 
368 #endif
369 
370 BETTER_ENUMS_IF_EXCEPTIONS(
371 template <typename T>
372 BETTER_ENUMS_CONSTEXPR_ static T _or_throw(optional<T> maybe,
373  const char *message)
374 {
375  BETTER_ENUMS_OR_THROW
376 }
377 )
378 
379 template <typename T>
380 BETTER_ENUMS_CONSTEXPR_ static T* _or_null(optional<T*> maybe)
381 {
382  return maybe ? *maybe : BETTER_ENUMS_NULLPTR;
383 }
384 
385 template <typename T>
386 BETTER_ENUMS_CONSTEXPR_ static T _or_zero(optional<T> maybe)
387 {
388  return maybe ? *maybe : T::_from_integral_unchecked(0);
389 }
390 
391 
392 
393 // Functional sequencing. This is essentially a comma operator wrapped in a
394 // constexpr function. g++ 4.7 doesn't "accept" integral constants in the second
395 // position for the comma operator, and emits an external symbol, which then
396 // causes a linking error.
397 
398 template <typename T, typename U>
399 BETTER_ENUMS_CONSTEXPR_ U
400 continue_with(T, U value) { return value; }
401 
402 
403 
404 // Values array declaration helper.
405 
407 template <typename EnumType>
408 struct _eat_assign {
409  explicit BETTER_ENUMS_CONSTEXPR_ _eat_assign(EnumType value) : _value(value)
410  { }
411 
412  template <typename Any>
413  BETTER_ENUMS_CONSTEXPR_ const _eat_assign&
414  operator =(Any) const { return *this; }
415 
416  BETTER_ENUMS_CONSTEXPR_ operator EnumType () const { return _value; }
417 
418  private:
419  EnumType _value;
420 };
421 
422 
423 
424 // Iterables.
425 
426 template <typename Element>
427 struct _iterable {
428  typedef const Element* iterator;
429 
430  BETTER_ENUMS_CONSTEXPR_ iterator begin() const { return iterator(_array); }
431  BETTER_ENUMS_CONSTEXPR_ iterator end() const
432  { return iterator(_array + _size); }
433  BETTER_ENUMS_CONSTEXPR_ std::size_t size() const { return _size; }
434  BETTER_ENUMS_CONSTEXPR_ const Element& operator [](std::size_t index) const
435  { return _array[index]; }
436 
437  BETTER_ENUMS_CONSTEXPR_ _iterable(const Element *array, std::size_t s) :
438  _array(array), _size(s) { }
439 
440  private:
441  const Element * const _array;
442  const std::size_t _size;
443 };
444 
445 
446 
447 // String routines.
448 
449 BETTER_ENUMS_CONSTEXPR_ static const char *_name_enders = "= \t\n";
450 
451 BETTER_ENUMS_CONSTEXPR_ inline bool _ends_name(char c, std::size_t index = 0)
452 {
453  return
454  c == _name_enders[index] ? true :
455  _name_enders[index] == '\0' ? false :
456  _ends_name(c, index + 1);
457 }
458 
459 BETTER_ENUMS_CONSTEXPR_ inline bool _has_initializer(const char *s,
460  std::size_t index = 0)
461 {
462  return
463  s[index] == '\0' ? false :
464  s[index] == '=' ? true :
465  _has_initializer(s, index + 1);
466 }
467 
468 BETTER_ENUMS_CONSTEXPR_ inline std::size_t
469 _constant_length(const char *s, std::size_t index = 0)
470 {
471  return _ends_name(s[index]) ? index : _constant_length(s, index + 1);
472 }
473 
474 BETTER_ENUMS_CONSTEXPR_ inline char
475 _select(const char *from, std::size_t from_length, std::size_t index)
476 {
477  return index >= from_length ? '\0' : from[index];
478 }
479 
480 BETTER_ENUMS_CONSTEXPR_ inline char _to_lower_ascii(char c)
481 {
482  return c >= 0x41 && c <= 0x5A ? static_cast<char>(c + 0x20) : c;
483 }
484 
485 BETTER_ENUMS_CONSTEXPR_ inline bool _names_match(const char *stringizedName,
486  const char *referenceName,
487  std::size_t index = 0)
488 {
489  return
490  _ends_name(stringizedName[index]) ? referenceName[index] == '\0' :
491  referenceName[index] == '\0' ? false :
492  stringizedName[index] != referenceName[index] ? false :
493  _names_match(stringizedName, referenceName, index + 1);
494 }
495 
496 BETTER_ENUMS_CONSTEXPR_ inline bool
497 _names_match_nocase(const char *stringizedName, const char *referenceName,
498  std::size_t index = 0)
499 {
500  return
501  _ends_name(stringizedName[index]) ? referenceName[index] == '\0' :
502  referenceName[index] == '\0' ? false :
503  _to_lower_ascii(stringizedName[index]) !=
504  _to_lower_ascii(referenceName[index]) ? false :
505  _names_match_nocase(stringizedName, referenceName, index + 1);
506 }
507 
508 inline void _trim_names(const char * const *raw_names,
509  const char **trimmed_names,
510  char *storage, std::size_t count)
511 {
512  std::size_t offset = 0;
513 
514  for (std::size_t index = 0; index < count; ++index) {
515  trimmed_names[index] = storage + offset;
516 
517  std::size_t trimmed_length =
518  std::strcspn(raw_names[index], _name_enders);
519  storage[offset + trimmed_length] = '\0';
520 
521  std::size_t raw_length = std::strlen(raw_names[index]);
522  offset += raw_length + 1;
523  }
524 }
525 
526 
527 
528 // Eager initialization.
529 template <typename Enum>
531  _initialize_at_program_start() { Enum::initialize(); }
532 };
533 
534 } // namespace better_enums
535 
536 
537 
538 // Array generation macros.
539 
540 #define BETTER_ENUMS_EAT_ASSIGN_SINGLE(EnumType, index, expression) \
541  (EnumType)((::better_enums::_eat_assign<EnumType>)EnumType::expression),
542 
543 #define BETTER_ENUMS_EAT_ASSIGN(EnumType, ...) \
544  BETTER_ENUMS_ID( \
545  BETTER_ENUMS_PP_MAP( \
546  BETTER_ENUMS_EAT_ASSIGN_SINGLE, EnumType, __VA_ARGS__))
547 
548 
549 
550 #ifdef BETTER_ENUMS_HAVE_CONSTEXPR
551 
552 
553 
554 #define BETTER_ENUMS_SELECT_SINGLE_CHARACTER(from, from_length, index) \
555  ::better_enums::_select(from, from_length, index),
556 
557 #define BETTER_ENUMS_SELECT_CHARACTERS(from, from_length) \
558  BETTER_ENUMS_ITERATE( \
559  BETTER_ENUMS_SELECT_SINGLE_CHARACTER, from, from_length)
560 
561 
562 
563 #define BETTER_ENUMS_TRIM_SINGLE_STRING(ignored, index, expression) \
564 constexpr std::size_t _length_ ## index = \
565  ::better_enums::_constant_length(#expression); \
566 constexpr const char _trimmed_ ## index [] = \
567  { BETTER_ENUMS_SELECT_CHARACTERS(#expression, _length_ ## index) }; \
568 constexpr const char *_final_ ## index = \
569  ::better_enums::_has_initializer(#expression) ? \
570  _trimmed_ ## index : #expression;
571 
572 #define BETTER_ENUMS_TRIM_STRINGS(...) \
573  BETTER_ENUMS_ID( \
574  BETTER_ENUMS_PP_MAP( \
575  BETTER_ENUMS_TRIM_SINGLE_STRING, ignored, __VA_ARGS__))
576 
577 
578 
579 #define BETTER_ENUMS_REFER_TO_SINGLE_STRING(ignored, index, expression) \
580  _final_ ## index,
581 
582 #define BETTER_ENUMS_REFER_TO_STRINGS(...) \
583  BETTER_ENUMS_ID( \
584  BETTER_ENUMS_PP_MAP( \
585  BETTER_ENUMS_REFER_TO_SINGLE_STRING, ignored, __VA_ARGS__))
586 
587 
588 
589 #endif // #ifdef BETTER_ENUMS_HAVE_CONSTEXPR
590 
591 
592 
593 #define BETTER_ENUMS_STRINGIZE_SINGLE(ignored, index, expression) #expression,
594 
595 #define BETTER_ENUMS_STRINGIZE(...) \
596  BETTER_ENUMS_ID( \
597  BETTER_ENUMS_PP_MAP( \
598  BETTER_ENUMS_STRINGIZE_SINGLE, ignored, __VA_ARGS__))
599 
600 #define BETTER_ENUMS_RESERVE_STORAGE_SINGLE(ignored, index, expression) \
601  #expression ","
602 
603 #define BETTER_ENUMS_RESERVE_STORAGE(...) \
604  BETTER_ENUMS_ID( \
605  BETTER_ENUMS_PP_MAP( \
606  BETTER_ENUMS_RESERVE_STORAGE_SINGLE, ignored, __VA_ARGS__))
607 
608 
609 
610 // The enums proper.
611 
612 #define BETTER_ENUMS_NS(EnumType) better_enums_data_ ## EnumType
613 
614 #ifdef BETTER_ENUMS_VC2008_WORKAROUNDS
615 
616 #define BETTER_ENUMS_COPY_CONSTRUCTOR(Enum) \
617  BETTER_ENUMS_CONSTEXPR_ Enum(const Enum &other) : \
618  _value(other._value) { }
619 
620 #else
621 
622 #define BETTER_ENUMS_COPY_CONSTRUCTOR(Enum)
623 
624 #endif
625 
626 #ifndef BETTER_ENUMS_CLASS_ATTRIBUTE
627 # define BETTER_ENUMS_CLASS_ATTRIBUTE
628 #endif
629 
630 #define BETTER_ENUMS_TYPE(SetUnderlyingType, SwitchType, GenerateSwitchType, \
631  GenerateStrings, ToStringConstexpr, \
632  DeclareInitialize, DefineInitialize, CallInitialize, \
633  Enum, Underlying, ...) \
634  \
635 namespace better_enums_data_ ## Enum { \
636  \
637 BETTER_ENUMS_ID(GenerateSwitchType(Underlying, __VA_ARGS__)) \
638  \
639 } \
640  \
641 class BETTER_ENUMS_CLASS_ATTRIBUTE Enum { \
642  private: \
643  typedef ::better_enums::optional<Enum> _optional; \
644  typedef ::better_enums::optional<std::size_t> _optional_index; \
645  \
646  public: \
647  typedef Underlying _integral; \
648  \
649  enum _enumerated SetUnderlyingType(Underlying) { __VA_ARGS__ }; \
650  \
651  BETTER_ENUMS_CONSTEXPR_ Enum(_enumerated value) : _value(value) { } \
652  \
653  BETTER_ENUMS_COPY_CONSTRUCTOR(Enum) \
654  \
655  BETTER_ENUMS_CONSTEXPR_ operator SwitchType(Enum)() const \
656  { \
657  return SwitchType(Enum)(_value); \
658  } \
659  \
660  BETTER_ENUMS_CONSTEXPR_ _integral _to_integral() const; \
661  BETTER_ENUMS_IF_EXCEPTIONS( \
662  BETTER_ENUMS_CONSTEXPR_ static Enum _from_integral(_integral value); \
663  ) \
664  BETTER_ENUMS_CONSTEXPR_ static Enum \
665  _from_integral_unchecked(_integral value); \
666  BETTER_ENUMS_CONSTEXPR_ static _optional \
667  _from_integral_nothrow(_integral value); \
668  \
669  BETTER_ENUMS_CONSTEXPR_ std::size_t _to_index() const; \
670  BETTER_ENUMS_IF_EXCEPTIONS( \
671  BETTER_ENUMS_CONSTEXPR_ static Enum _from_index(std::size_t value); \
672  ) \
673  BETTER_ENUMS_CONSTEXPR_ static Enum \
674  _from_index_unchecked(std::size_t value); \
675  BETTER_ENUMS_CONSTEXPR_ static _optional \
676  _from_index_nothrow(std::size_t value); \
677  \
678  ToStringConstexpr const char* _to_string() const; \
679  BETTER_ENUMS_IF_EXCEPTIONS( \
680  BETTER_ENUMS_CONSTEXPR_ static Enum _from_string(const char *name); \
681  ) \
682  BETTER_ENUMS_CONSTEXPR_ static _optional \
683  _from_string_nothrow(const char *name); \
684  \
685  BETTER_ENUMS_IF_EXCEPTIONS( \
686  BETTER_ENUMS_CONSTEXPR_ static Enum _from_string_nocase(const char *name); \
687  ) \
688  BETTER_ENUMS_CONSTEXPR_ static _optional \
689  _from_string_nocase_nothrow(const char *name); \
690  \
691  BETTER_ENUMS_CONSTEXPR_ static bool _is_valid(_integral value); \
692  BETTER_ENUMS_CONSTEXPR_ static bool _is_valid(const char *name); \
693  BETTER_ENUMS_CONSTEXPR_ static bool _is_valid_nocase(const char *name); \
694  \
695  typedef ::better_enums::_iterable<Enum> _value_iterable; \
696  typedef ::better_enums::_iterable<const char*> _name_iterable; \
697  \
698  typedef _value_iterable::iterator _value_iterator; \
699  typedef _name_iterable::iterator _name_iterator; \
700  \
701  BETTER_ENUMS_CONSTEXPR_ static const std::size_t _size_constant = \
702  BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT(__VA_ARGS__)); \
703  BETTER_ENUMS_CONSTEXPR_ static std::size_t _size() \
704  { return _size_constant; } \
705  \
706  BETTER_ENUMS_CONSTEXPR_ static const char* _name(); \
707  BETTER_ENUMS_CONSTEXPR_ static _value_iterable _values(); \
708  ToStringConstexpr static _name_iterable _names(); \
709  \
710  _integral _value; \
711  \
712  BETTER_ENUMS_DEFAULT_CONSTRUCTOR(Enum) \
713  \
714  private: \
715  explicit BETTER_ENUMS_CONSTEXPR_ Enum(const _integral &value) : \
716  _value(value) { } \
717  \
718  DeclareInitialize \
719  \
720  BETTER_ENUMS_CONSTEXPR_ static _optional_index \
721  _from_value_loop(_integral value, std::size_t index = 0); \
722  BETTER_ENUMS_CONSTEXPR_ static _optional_index \
723  _from_string_loop(const char *name, std::size_t index = 0); \
724  BETTER_ENUMS_CONSTEXPR_ static _optional_index \
725  _from_string_nocase_loop(const char *name, std::size_t index = 0); \
726  \
727  friend struct ::better_enums::_initialize_at_program_start<Enum>; \
728 }; \
729  \
730 namespace better_enums_data_ ## Enum { \
731  \
732 static ::better_enums::_initialize_at_program_start<Enum> \
733  _force_initialization; \
734  \
735 enum _putNamesInThisScopeAlso { __VA_ARGS__ }; \
736  \
737 BETTER_ENUMS_IGNORE_OLD_CAST_HEADER \
738 BETTER_ENUMS_IGNORE_OLD_CAST_BEGIN \
739 BETTER_ENUMS_CONSTEXPR_ const Enum _value_array[] = \
740  { BETTER_ENUMS_ID(BETTER_ENUMS_EAT_ASSIGN(Enum, __VA_ARGS__)) }; \
741 BETTER_ENUMS_IGNORE_OLD_CAST_END \
742  \
743 BETTER_ENUMS_ID(GenerateStrings(Enum, __VA_ARGS__)) \
744  \
745 } \
746  \
747 BETTER_ENUMS_IGNORE_ATTRIBUTES_HEADER \
748 BETTER_ENUMS_IGNORE_ATTRIBUTES_BEGIN \
749 BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
750 inline const Enum \
751 operator +(Enum::_enumerated enumerated) \
752 { \
753  return static_cast<Enum>(enumerated); \
754 } \
755 BETTER_ENUMS_IGNORE_ATTRIBUTES_END \
756  \
757 BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional_index \
758 Enum::_from_value_loop(Enum::_integral value, std::size_t index) \
759 { \
760  return \
761  index == _size() ? \
762  _optional_index() : \
763  BETTER_ENUMS_NS(Enum)::_value_array[index]._value == value ? \
764  _optional_index(index) : \
765  _from_value_loop(value, index + 1); \
766 } \
767  \
768 BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional_index \
769 Enum::_from_string_loop(const char *name, std::size_t index) \
770 { \
771  return \
772  index == _size() ? _optional_index() : \
773  ::better_enums::_names_match( \
774  BETTER_ENUMS_NS(Enum)::_raw_names()[index], name) ? \
775  _optional_index(index) : \
776  _from_string_loop(name, index + 1); \
777 } \
778  \
779 BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional_index \
780 Enum::_from_string_nocase_loop(const char *name, std::size_t index) \
781 { \
782  return \
783  index == _size() ? _optional_index() : \
784  ::better_enums::_names_match_nocase( \
785  BETTER_ENUMS_NS(Enum)::_raw_names()[index], name) ? \
786  _optional_index(index) : \
787  _from_string_nocase_loop(name, index + 1); \
788 } \
789  \
790 BETTER_ENUMS_CONSTEXPR_ inline Enum::_integral Enum::_to_integral() const \
791 { \
792  return _integral(_value); \
793 } \
794  \
795 BETTER_ENUMS_CONSTEXPR_ inline std::size_t Enum::_to_index() const \
796 { \
797  return *_from_value_loop(_value); \
798 } \
799  \
800 BETTER_ENUMS_CONSTEXPR_ inline Enum \
801 Enum::_from_index_unchecked(std::size_t index) \
802 { \
803  return \
804  ::better_enums::_or_zero(_from_index_nothrow(index)); \
805 } \
806  \
807 BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional \
808 Enum::_from_index_nothrow(std::size_t index) \
809 { \
810  return \
811  index >= _size() ? \
812  _optional() : \
813  _optional(BETTER_ENUMS_NS(Enum)::_value_array[index]); \
814 } \
815  \
816 BETTER_ENUMS_IF_EXCEPTIONS( \
817 BETTER_ENUMS_CONSTEXPR_ inline Enum Enum::_from_index(std::size_t index) \
818 { \
819  return \
820  ::better_enums::_or_throw(_from_index_nothrow(index), \
821  #Enum "::_from_index: invalid argument"); \
822 } \
823 ) \
824  \
825 BETTER_ENUMS_CONSTEXPR_ inline Enum \
826 Enum::_from_integral_unchecked(_integral value) \
827 { \
828  return static_cast<_enumerated>(value); \
829 } \
830  \
831 BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional \
832 Enum::_from_integral_nothrow(_integral value) \
833 { \
834  return \
835  ::better_enums::_map_index<Enum>(BETTER_ENUMS_NS(Enum)::_value_array, \
836  _from_value_loop(value)); \
837 } \
838  \
839 BETTER_ENUMS_IF_EXCEPTIONS( \
840 BETTER_ENUMS_CONSTEXPR_ inline Enum Enum::_from_integral(_integral value) \
841 { \
842  return \
843  ::better_enums::_or_throw(_from_integral_nothrow(value), \
844  #Enum "::_from_integral: invalid argument"); \
845 } \
846 ) \
847  \
848 ToStringConstexpr inline const char* Enum::_to_string() const \
849 { \
850  return \
851  ::better_enums::_or_null( \
852  ::better_enums::_map_index<const char*>( \
853  BETTER_ENUMS_NS(Enum)::_name_array(), \
854  _from_value_loop(CallInitialize(_value)))); \
855 } \
856  \
857 BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional \
858 Enum::_from_string_nothrow(const char *name) \
859 { \
860  return \
861  ::better_enums::_map_index<Enum>( \
862  BETTER_ENUMS_NS(Enum)::_value_array, _from_string_loop(name)); \
863 } \
864  \
865 BETTER_ENUMS_IF_EXCEPTIONS( \
866 BETTER_ENUMS_CONSTEXPR_ inline Enum Enum::_from_string(const char *name) \
867 { \
868  return \
869  ::better_enums::_or_throw(_from_string_nothrow(name), \
870  #Enum "::_from_string: invalid argument"); \
871 } \
872 ) \
873  \
874 BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional \
875 Enum::_from_string_nocase_nothrow(const char *name) \
876 { \
877  return \
878  ::better_enums::_map_index<Enum>(BETTER_ENUMS_NS(Enum)::_value_array, \
879  _from_string_nocase_loop(name)); \
880 } \
881  \
882 BETTER_ENUMS_IF_EXCEPTIONS( \
883 BETTER_ENUMS_CONSTEXPR_ inline Enum Enum::_from_string_nocase(const char *name)\
884 { \
885  return \
886  ::better_enums::_or_throw( \
887  _from_string_nocase_nothrow(name), \
888  #Enum "::_from_string_nocase: invalid argument"); \
889 } \
890 ) \
891  \
892 BETTER_ENUMS_CONSTEXPR_ inline bool Enum::_is_valid(_integral value) \
893 { \
894  return _from_value_loop(value); \
895 } \
896  \
897 BETTER_ENUMS_CONSTEXPR_ inline bool Enum::_is_valid(const char *name) \
898 { \
899  return _from_string_loop(name); \
900 } \
901  \
902 BETTER_ENUMS_CONSTEXPR_ inline bool Enum::_is_valid_nocase(const char *name) \
903 { \
904  return _from_string_nocase_loop(name); \
905 } \
906  \
907 BETTER_ENUMS_CONSTEXPR_ inline const char* Enum::_name() \
908 { \
909  return #Enum; \
910 } \
911  \
912 BETTER_ENUMS_CONSTEXPR_ inline Enum::_value_iterable Enum::_values() \
913 { \
914  return _value_iterable(BETTER_ENUMS_NS(Enum)::_value_array, _size()); \
915 } \
916  \
917 ToStringConstexpr inline Enum::_name_iterable Enum::_names() \
918 { \
919  return \
920  _name_iterable(BETTER_ENUMS_NS(Enum)::_name_array(), \
921  CallInitialize(_size())); \
922 } \
923  \
924 DefineInitialize(Enum) \
925  \
926 BETTER_ENUMS_IGNORE_ATTRIBUTES_HEADER \
927 BETTER_ENUMS_IGNORE_ATTRIBUTES_BEGIN \
928 BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
929 inline bool operator ==(const Enum &a, const Enum &b) \
930  { return a._to_integral() == b._to_integral(); } \
931  \
932 BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
933 inline bool operator !=(const Enum &a, const Enum &b) \
934  { return a._to_integral() != b._to_integral(); } \
935  \
936 BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
937 inline bool operator <(const Enum &a, const Enum &b) \
938  { return a._to_integral() < b._to_integral(); } \
939  \
940 BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
941 inline bool operator <=(const Enum &a, const Enum &b) \
942  { return a._to_integral() <= b._to_integral(); } \
943  \
944 BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
945 inline bool operator >(const Enum &a, const Enum &b) \
946  { return a._to_integral() > b._to_integral(); } \
947  \
948 BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
949 inline bool operator >=(const Enum &a, const Enum &b) \
950  { return a._to_integral() >= b._to_integral(); } \
951 BETTER_ENUMS_IGNORE_ATTRIBUTES_END \
952  \
953  \
954 template <typename Char, typename Traits> \
955 std::basic_ostream<Char, Traits>& \
956 operator <<(std::basic_ostream<Char, Traits>& stream, const Enum &value) \
957 { \
958  return stream << value._to_string(); \
959 } \
960  \
961 template <typename Char, typename Traits> \
962 std::basic_istream<Char, Traits>& \
963 operator >>(std::basic_istream<Char, Traits>& stream, Enum &value) \
964 { \
965  std::basic_string<Char, Traits> buffer; \
966  \
967  stream >> buffer; \
968  ::better_enums::optional<Enum> converted = \
969  Enum::_from_string_nothrow(buffer.c_str()); \
970  \
971  if (converted) \
972  value = *converted; \
973  else \
974  stream.setstate(std::basic_istream<Char, Traits>::failbit); \
975  \
976  return stream; \
977 }
978 
979 
980 
981 // Enum feature options.
982 
983 // C++98, C++11
984 #define BETTER_ENUMS_CXX98_UNDERLYING_TYPE(Underlying)
985 
986 // C++11
987 #define BETTER_ENUMS_CXX11_UNDERLYING_TYPE(Underlying) \
988  : Underlying
989 
990 #if defined(_MSC_VER) && _MSC_VER >= 1700
991 // VS 2012 and above fully support strongly typed enums and will warn about
992 // incorrect usage.
993 # define BETTER_ENUMS_LEGACY_UNDERLYING_TYPE(Underlying) \
994  BETTER_ENUMS_CXX11_UNDERLYING_TYPE(Underlying)
995 #else
996 # define BETTER_ENUMS_LEGACY_UNDERLYING_TYPE(Underlying) \
997  BETTER_ENUMS_CXX98_UNDERLYING_TYPE(Underlying)
998 #endif
999 
1000 // C++98, C++11
1001 #define BETTER_ENUMS_REGULAR_ENUM_SWITCH_TYPE(Type) \
1002  _enumerated
1003 
1004 // C++11
1005 #define BETTER_ENUMS_ENUM_CLASS_SWITCH_TYPE(Type) \
1006  BETTER_ENUMS_NS(Type)::_enumClassForSwitchStatements
1007 
1008 // C++98, C++11
1009 #define BETTER_ENUMS_REGULAR_ENUM_SWITCH_TYPE_GENERATE(Underlying, ...)
1010 
1011 // C++11
1012 #define BETTER_ENUMS_ENUM_CLASS_SWITCH_TYPE_GENERATE(Underlying, ...) \
1013  enum class _enumClassForSwitchStatements : Underlying { __VA_ARGS__ };
1014 
1015 // C++98
1016 #define BETTER_ENUMS_CXX98_TRIM_STRINGS_ARRAYS(Enum, ...) \
1017  inline const char** _raw_names() \
1018  { \
1019  static const char *value[] = \
1020  { BETTER_ENUMS_ID(BETTER_ENUMS_STRINGIZE(__VA_ARGS__)) }; \
1021  return value; \
1022  } \
1023  \
1024  inline char* _name_storage() \
1025  { \
1026  static char storage[] = \
1027  BETTER_ENUMS_ID(BETTER_ENUMS_RESERVE_STORAGE(__VA_ARGS__)); \
1028  return storage; \
1029  } \
1030  \
1031  inline const char** _name_array() \
1032  { \
1033  static const char *value[Enum::_size_constant]; \
1034  return value; \
1035  } \
1036  \
1037  inline bool& _initialized() \
1038  { \
1039  static bool value = false; \
1040  return value; \
1041  }
1042 
1043 // C++11 fast version
1044 #define BETTER_ENUMS_CXX11_PARTIAL_CONSTEXPR_TRIM_STRINGS_ARRAYS(Enum, ...) \
1045  constexpr const char *_the_raw_names[] = \
1046  { BETTER_ENUMS_ID(BETTER_ENUMS_STRINGIZE(__VA_ARGS__)) }; \
1047  \
1048  constexpr const char * const * _raw_names() \
1049  { \
1050  return _the_raw_names; \
1051  } \
1052  \
1053  inline char* _name_storage() \
1054  { \
1055  static char storage[] = \
1056  BETTER_ENUMS_ID(BETTER_ENUMS_RESERVE_STORAGE(__VA_ARGS__)); \
1057  return storage; \
1058  } \
1059  \
1060  inline const char** _name_array() \
1061  { \
1062  static const char *value[Enum::_size_constant]; \
1063  return value; \
1064  } \
1065  \
1066  inline bool& _initialized() \
1067  { \
1068  static bool value = false; \
1069  return value; \
1070  }
1071 
1072 // C++11 slow all-constexpr version
1073 #define BETTER_ENUMS_CXX11_FULL_CONSTEXPR_TRIM_STRINGS_ARRAYS(Enum, ...) \
1074  BETTER_ENUMS_ID(BETTER_ENUMS_TRIM_STRINGS(__VA_ARGS__)) \
1075  \
1076  constexpr const char * const _the_name_array[] = \
1077  { BETTER_ENUMS_ID(BETTER_ENUMS_REFER_TO_STRINGS(__VA_ARGS__)) }; \
1078  \
1079  constexpr const char * const * _name_array() \
1080  { \
1081  return _the_name_array; \
1082  } \
1083  \
1084  constexpr const char * const * _raw_names() \
1085  { \
1086  return _the_name_array; \
1087  }
1088 
1089 // C++98, C++11 fast version
1090 #define BETTER_ENUMS_NO_CONSTEXPR_TO_STRING_KEYWORD
1091 
1092 // C++11 slow all-constexpr version
1093 #define BETTER_ENUMS_CONSTEXPR_TO_STRING_KEYWORD \
1094  constexpr
1095 
1096 // C++98, C++11 fast version
1097 #define BETTER_ENUMS_DO_DECLARE_INITIALIZE \
1098  static int initialize();
1099 
1100 // C++11 slow all-constexpr version
1101 #define BETTER_ENUMS_DECLARE_EMPTY_INITIALIZE \
1102  static int initialize() { return 0; }
1103 
1104 // C++98, C++11 fast version
1105 #define BETTER_ENUMS_DO_DEFINE_INITIALIZE(Enum) \
1106  inline int Enum::initialize() \
1107  { \
1108  if (BETTER_ENUMS_NS(Enum)::_initialized()) \
1109  return 0; \
1110  \
1111  ::better_enums::_trim_names(BETTER_ENUMS_NS(Enum)::_raw_names(), \
1112  BETTER_ENUMS_NS(Enum)::_name_array(), \
1113  BETTER_ENUMS_NS(Enum)::_name_storage(), \
1114  _size()); \
1115  \
1116  BETTER_ENUMS_NS(Enum)::_initialized() = true; \
1117  \
1118  return 0; \
1119  }
1120 
1121 // C++11 slow all-constexpr version
1122 #define BETTER_ENUMS_DO_NOT_DEFINE_INITIALIZE(Enum)
1123 
1124 // C++98, C++11 fast version
1125 #define BETTER_ENUMS_DO_CALL_INITIALIZE(value) \
1126  ::better_enums::continue_with(initialize(), value)
1127 
1128 // C++11 slow all-constexpr version
1129 #define BETTER_ENUMS_DO_NOT_CALL_INITIALIZE(value) \
1130  value
1131 
1132 
1133 
1134 // User feature selection.
1135 
1136 #ifdef BETTER_ENUMS_STRICT_CONVERSION
1137 # define BETTER_ENUMS_DEFAULT_SWITCH_TYPE \
1138  BETTER_ENUMS_ENUM_CLASS_SWITCH_TYPE
1139 # define BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE \
1140  BETTER_ENUMS_ENUM_CLASS_SWITCH_TYPE_GENERATE
1141 #else
1142 # define BETTER_ENUMS_DEFAULT_SWITCH_TYPE \
1143  BETTER_ENUMS_REGULAR_ENUM_SWITCH_TYPE
1144 # define BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE \
1145  BETTER_ENUMS_REGULAR_ENUM_SWITCH_TYPE_GENERATE
1146 #endif
1147 
1148 
1149 
1150 #ifndef BETTER_ENUMS_DEFAULT_CONSTRUCTOR
1151 # define BETTER_ENUMS_DEFAULT_CONSTRUCTOR(Enum) \
1152  private: \
1153  Enum() : _value(0) { }
1154 #endif
1155 
1156 
1157 
1158 #ifdef BETTER_ENUMS_HAVE_CONSTEXPR
1159 
1160 #ifdef BETTER_ENUMS_CONSTEXPR_TO_STRING
1161 # define BETTER_ENUMS_DEFAULT_TRIM_STRINGS_ARRAYS \
1162  BETTER_ENUMS_CXX11_FULL_CONSTEXPR_TRIM_STRINGS_ARRAYS
1163 # define BETTER_ENUMS_DEFAULT_TO_STRING_KEYWORD \
1164  BETTER_ENUMS_CONSTEXPR_TO_STRING_KEYWORD
1165 # define BETTER_ENUMS_DEFAULT_DECLARE_INITIALIZE \
1166  BETTER_ENUMS_DECLARE_EMPTY_INITIALIZE
1167 # define BETTER_ENUMS_DEFAULT_DEFINE_INITIALIZE \
1168  BETTER_ENUMS_DO_NOT_DEFINE_INITIALIZE
1169 # define BETTER_ENUMS_DEFAULT_CALL_INITIALIZE \
1170  BETTER_ENUMS_DO_NOT_CALL_INITIALIZE
1171 #else
1172 # define BETTER_ENUMS_DEFAULT_TRIM_STRINGS_ARRAYS \
1173  BETTER_ENUMS_CXX11_PARTIAL_CONSTEXPR_TRIM_STRINGS_ARRAYS
1174 # define BETTER_ENUMS_DEFAULT_TO_STRING_KEYWORD \
1175  BETTER_ENUMS_NO_CONSTEXPR_TO_STRING_KEYWORD
1176 # define BETTER_ENUMS_DEFAULT_DECLARE_INITIALIZE \
1177  BETTER_ENUMS_DO_DECLARE_INITIALIZE
1178 # define BETTER_ENUMS_DEFAULT_DEFINE_INITIALIZE \
1179  BETTER_ENUMS_DO_DEFINE_INITIALIZE
1180 # define BETTER_ENUMS_DEFAULT_CALL_INITIALIZE \
1181  BETTER_ENUMS_DO_CALL_INITIALIZE
1182 #endif
1183 
1184 
1185 
1186 // Top-level macros.
1187 
1188 #define BETTER_ENUM(Enum, Underlying, ...) \
1189  BETTER_ENUMS_ID(BETTER_ENUMS_TYPE( \
1190  BETTER_ENUMS_CXX11_UNDERLYING_TYPE, \
1191  BETTER_ENUMS_DEFAULT_SWITCH_TYPE, \
1192  BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE, \
1193  BETTER_ENUMS_DEFAULT_TRIM_STRINGS_ARRAYS, \
1194  BETTER_ENUMS_DEFAULT_TO_STRING_KEYWORD, \
1195  BETTER_ENUMS_DEFAULT_DECLARE_INITIALIZE, \
1196  BETTER_ENUMS_DEFAULT_DEFINE_INITIALIZE, \
1197  BETTER_ENUMS_DEFAULT_CALL_INITIALIZE, \
1198  Enum, Underlying, __VA_ARGS__))
1199 
1200 #define SLOW_ENUM(Enum, Underlying, ...) \
1201  BETTER_ENUMS_ID(BETTER_ENUMS_TYPE( \
1202  BETTER_ENUMS_CXX11_UNDERLYING_TYPE, \
1203  BETTER_ENUMS_DEFAULT_SWITCH_TYPE, \
1204  BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE, \
1205  BETTER_ENUMS_CXX11_FULL_CONSTEXPR_TRIM_STRINGS_ARRAYS, \
1206  BETTER_ENUMS_CONSTEXPR_TO_STRING_KEYWORD, \
1207  BETTER_ENUMS_DECLARE_EMPTY_INITIALIZE, \
1208  BETTER_ENUMS_DO_NOT_DEFINE_INITIALIZE, \
1209  BETTER_ENUMS_DO_NOT_CALL_INITIALIZE, \
1210  Enum, Underlying, __VA_ARGS__))
1211 
1212 #else
1213 
1214 #define BETTER_ENUM(Enum, Underlying, ...) \
1215  BETTER_ENUMS_ID(BETTER_ENUMS_TYPE( \
1216  BETTER_ENUMS_LEGACY_UNDERLYING_TYPE, \
1217  BETTER_ENUMS_DEFAULT_SWITCH_TYPE, \
1218  BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE, \
1219  BETTER_ENUMS_CXX98_TRIM_STRINGS_ARRAYS, \
1220  BETTER_ENUMS_NO_CONSTEXPR_TO_STRING_KEYWORD, \
1221  BETTER_ENUMS_DO_DECLARE_INITIALIZE, \
1222  BETTER_ENUMS_DO_DEFINE_INITIALIZE, \
1223  BETTER_ENUMS_DO_CALL_INITIALIZE, \
1224  Enum, Underlying, __VA_ARGS__))
1225 
1226 #endif
1227 
1228 
1229 
1230 namespace better_enums {
1231 
1232 // Maps.
1233 
1234 template <typename T>
1235 struct map_compare {
1236  BETTER_ENUMS_CONSTEXPR_ static bool less(const T& a, const T& b)
1237  { return a < b; }
1238 };
1239 
1240 template <>
1241 struct map_compare<const char*> {
1242  BETTER_ENUMS_CONSTEXPR_ static bool less(const char *a, const char *b)
1243  { return less_loop(a, b); }
1244 
1245  private:
1246  BETTER_ENUMS_CONSTEXPR_ static bool
1247  less_loop(const char *a, const char *b, size_t index = 0)
1248  {
1249  return
1250  a[index] != b[index] ? a[index] < b[index] :
1251  a[index] == '\0' ? false :
1252  less_loop(a, b, index + 1);
1253  }
1254 };
1255 
1256 template <>
1257 struct map_compare<const wchar_t*> {
1258  BETTER_ENUMS_CONSTEXPR_ static bool less(const wchar_t *a, const wchar_t *b)
1259  { return less_loop(a, b); }
1260 
1261  private:
1262  BETTER_ENUMS_CONSTEXPR_ static bool
1263  less_loop(const wchar_t *a, const wchar_t *b, size_t index = 0)
1264  {
1265  return
1266  a[index] != b[index] ? a[index] < b[index] :
1267  a[index] == L'\0' ? false :
1268  less_loop(a, b, index + 1);
1269  }
1270 };
1271 
1272 template <typename Enum, typename T, typename Compare = map_compare<T> >
1273 struct map {
1274  typedef T (*function)(Enum);
1275 
1276  BETTER_ENUMS_CONSTEXPR_ explicit map(function f) : _f(f) { }
1277 
1278  BETTER_ENUMS_CONSTEXPR_ T from_enum(Enum value) const { return _f(value); }
1279  BETTER_ENUMS_CONSTEXPR_ T operator [](Enum value) const
1280  { return _f(value); }
1281 
1282  BETTER_ENUMS_CONSTEXPR_ Enum to_enum(T value) const
1283  {
1284  return
1285  _or_throw(to_enum_nothrow(value), "map::to_enum: invalid argument");
1286  }
1287 
1288  BETTER_ENUMS_CONSTEXPR_ optional<Enum>
1289  to_enum_nothrow(T value, size_t index = 0) const
1290  {
1291  return
1292  index >= Enum::_size() ? optional<Enum>() :
1293  Compare::less(_f(Enum::_values()[index]), value) ||
1294  Compare::less(value, _f(Enum::_values()[index])) ?
1295  to_enum_nothrow(value, index + 1) :
1296  Enum::_values()[index];
1297  }
1298 
1299  private:
1300  const function _f;
1301 };
1302 
1303 template <typename Enum, typename T>
1304 BETTER_ENUMS_CONSTEXPR_ map<Enum, T> make_map(T (*f)(Enum))
1305 {
1306  return map<Enum, T>(f);
1307 }
1308 
1309 }
1310 
1311 #define BETTER_ENUMS_DECLARE_STD_HASH(type) \
1312  namespace std { \
1313  template <> struct hash<type> \
1314  { \
1315  size_t operator()(const type &x) const \
1316  { \
1317  return std::hash<size_t>()(x._to_integral()); \
1318  } \
1319  }; \
1320  }
1321 
1322 #endif // #ifndef BETTER_ENUMS_ENUM_H
struct to keep a message from a sender
Definition: defTypes.h:24
Definition: enum.h:1235
Get intrinsic value of an (Enum::value) by taking advantage of C-conversion&#39;s parentheses priority...
Definition: enum.h:408
Definition: enum.h:330
Definition: enum.h:1273
Definition: enum.h:306
Definition: enum.h:427