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