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