You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1328 lines
66 KiB

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