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.

1326 lines
66 KiB

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