enum.h 74 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043
  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(BETTER_ENUMS_APPLY(BETTER_ENUMS_PP_MAP_VAR_COUNT, \
  127. BETTER_ENUMS_PP_COUNT(__VA_ARGS__))(macro, data, __VA_ARGS__))
  128. #define BETTER_ENUMS_PP_MAP_VAR_COUNT(count) BETTER_ENUMS_M##count
  129. #define BETTER_ENUMS_APPLY(macro, ...) BETTER_ENUMS_ID(macro(__VA_ARGS__))
  130. #define BETTER_ENUMS_ID(x) x
  131. #define BETTER_ENUMS_M1(m, d, x) m(d, 0, x)
  132. #define BETTER_ENUMS_M2(m, d, x, ...) m(d, 1, x) BETTER_ENUMS_ID(BETTER_ENUMS_M1(m, d, __VA_ARGS__))
  133. #define BETTER_ENUMS_M3(m, d, x, ...) m(d, 2, x) BETTER_ENUMS_ID(BETTER_ENUMS_M2(m, d, __VA_ARGS__))
  134. #define BETTER_ENUMS_M4(m, d, x, ...) m(d, 3, x) BETTER_ENUMS_ID(BETTER_ENUMS_M3(m, d, __VA_ARGS__))
  135. #define BETTER_ENUMS_M5(m, d, x, ...) m(d, 4, x) BETTER_ENUMS_ID(BETTER_ENUMS_M4(m, d, __VA_ARGS__))
  136. #define BETTER_ENUMS_M6(m, d, x, ...) m(d, 5, x) BETTER_ENUMS_ID(BETTER_ENUMS_M5(m, d, __VA_ARGS__))
  137. #define BETTER_ENUMS_M7(m, d, x, ...) m(d, 6, x) BETTER_ENUMS_ID(BETTER_ENUMS_M6(m, d, __VA_ARGS__))
  138. #define BETTER_ENUMS_M8(m, d, x, ...) m(d, 7, x) BETTER_ENUMS_ID(BETTER_ENUMS_M7(m, d, __VA_ARGS__))
  139. #define BETTER_ENUMS_M9(m, d, x, ...) m(d, 8, x) BETTER_ENUMS_ID(BETTER_ENUMS_M8(m, d, __VA_ARGS__))
  140. #define BETTER_ENUMS_M10(m, d, x, ...) m(d, 9, x) BETTER_ENUMS_ID(BETTER_ENUMS_M9(m, d, __VA_ARGS__))
  141. #define BETTER_ENUMS_M11(m, d, x, ...) m(d, 10, x) BETTER_ENUMS_ID(BETTER_ENUMS_M10(m, d, __VA_ARGS__))
  142. #define BETTER_ENUMS_M12(m, d, x, ...) m(d, 11, x) BETTER_ENUMS_ID(BETTER_ENUMS_M11(m, d, __VA_ARGS__))
  143. #define BETTER_ENUMS_M13(m, d, x, ...) m(d, 12, x) BETTER_ENUMS_ID(BETTER_ENUMS_M12(m, d, __VA_ARGS__))
  144. #define BETTER_ENUMS_M14(m, d, x, ...) m(d, 13, x) BETTER_ENUMS_ID(BETTER_ENUMS_M13(m, d, __VA_ARGS__))
  145. #define BETTER_ENUMS_M15(m, d, x, ...) m(d, 14, x) BETTER_ENUMS_ID(BETTER_ENUMS_M14(m, d, __VA_ARGS__))
  146. #define BETTER_ENUMS_M16(m, d, x, ...) m(d, 15, x) BETTER_ENUMS_ID(BETTER_ENUMS_M15(m, d, __VA_ARGS__))
  147. #define BETTER_ENUMS_M17(m, d, x, ...) m(d, 16, x) BETTER_ENUMS_ID(BETTER_ENUMS_M16(m, d, __VA_ARGS__))
  148. #define BETTER_ENUMS_M18(m, d, x, ...) m(d, 17, x) BETTER_ENUMS_ID(BETTER_ENUMS_M17(m, d, __VA_ARGS__))
  149. #define BETTER_ENUMS_M19(m, d, x, ...) m(d, 18, x) BETTER_ENUMS_ID(BETTER_ENUMS_M18(m, d, __VA_ARGS__))
  150. #define BETTER_ENUMS_M20(m, d, x, ...) m(d, 19, x) BETTER_ENUMS_ID(BETTER_ENUMS_M19(m, d, __VA_ARGS__))
  151. #define BETTER_ENUMS_M21(m, d, x, ...) m(d, 20, x) BETTER_ENUMS_ID(BETTER_ENUMS_M20(m, d, __VA_ARGS__))
  152. #define BETTER_ENUMS_M22(m, d, x, ...) m(d, 21, x) BETTER_ENUMS_ID(BETTER_ENUMS_M21(m, d, __VA_ARGS__))
  153. #define BETTER_ENUMS_M23(m, d, x, ...) m(d, 22, x) BETTER_ENUMS_ID(BETTER_ENUMS_M22(m, d, __VA_ARGS__))
  154. #define BETTER_ENUMS_M24(m, d, x, ...) m(d, 23, x) BETTER_ENUMS_ID(BETTER_ENUMS_M23(m, d, __VA_ARGS__))
  155. #define BETTER_ENUMS_M25(m, d, x, ...) m(d, 24, x) BETTER_ENUMS_ID(BETTER_ENUMS_M24(m, d, __VA_ARGS__))
  156. #define BETTER_ENUMS_M26(m, d, x, ...) m(d, 25, x) BETTER_ENUMS_ID(BETTER_ENUMS_M25(m, d, __VA_ARGS__))
  157. #define BETTER_ENUMS_M27(m, d, x, ...) m(d, 26, x) BETTER_ENUMS_ID(BETTER_ENUMS_M26(m, d, __VA_ARGS__))
  158. #define BETTER_ENUMS_M28(m, d, x, ...) m(d, 27, x) BETTER_ENUMS_ID(BETTER_ENUMS_M27(m, d, __VA_ARGS__))
  159. #define BETTER_ENUMS_M29(m, d, x, ...) m(d, 28, x) BETTER_ENUMS_ID(BETTER_ENUMS_M28(m, d, __VA_ARGS__))
  160. #define BETTER_ENUMS_M30(m, d, x, ...) m(d, 29, x) BETTER_ENUMS_ID(BETTER_ENUMS_M29(m, d, __VA_ARGS__))
  161. #define BETTER_ENUMS_M31(m, d, x, ...) m(d, 30, x) BETTER_ENUMS_ID(BETTER_ENUMS_M30(m, d, __VA_ARGS__))
  162. #define BETTER_ENUMS_M32(m, d, x, ...) m(d, 31, x) BETTER_ENUMS_ID(BETTER_ENUMS_M31(m, d, __VA_ARGS__))
  163. #define BETTER_ENUMS_M33(m, d, x, ...) m(d, 32, x) BETTER_ENUMS_ID(BETTER_ENUMS_M32(m, d, __VA_ARGS__))
  164. #define BETTER_ENUMS_M34(m, d, x, ...) m(d, 33, x) BETTER_ENUMS_ID(BETTER_ENUMS_M33(m, d, __VA_ARGS__))
  165. #define BETTER_ENUMS_M35(m, d, x, ...) m(d, 34, x) BETTER_ENUMS_ID(BETTER_ENUMS_M34(m, d, __VA_ARGS__))
  166. #define BETTER_ENUMS_M36(m, d, x, ...) m(d, 35, x) BETTER_ENUMS_ID(BETTER_ENUMS_M35(m, d, __VA_ARGS__))
  167. #define BETTER_ENUMS_M37(m, d, x, ...) m(d, 36, x) BETTER_ENUMS_ID(BETTER_ENUMS_M36(m, d, __VA_ARGS__))
  168. #define BETTER_ENUMS_M38(m, d, x, ...) m(d, 37, x) BETTER_ENUMS_ID(BETTER_ENUMS_M37(m, d, __VA_ARGS__))
  169. #define BETTER_ENUMS_M39(m, d, x, ...) m(d, 38, x) BETTER_ENUMS_ID(BETTER_ENUMS_M38(m, d, __VA_ARGS__))
  170. #define BETTER_ENUMS_M40(m, d, x, ...) m(d, 39, x) BETTER_ENUMS_ID(BETTER_ENUMS_M39(m, d, __VA_ARGS__))
  171. #define BETTER_ENUMS_M41(m, d, x, ...) m(d, 40, x) BETTER_ENUMS_ID(BETTER_ENUMS_M40(m, d, __VA_ARGS__))
  172. #define BETTER_ENUMS_M42(m, d, x, ...) m(d, 41, x) BETTER_ENUMS_ID(BETTER_ENUMS_M41(m, d, __VA_ARGS__))
  173. #define BETTER_ENUMS_M43(m, d, x, ...) m(d, 42, x) BETTER_ENUMS_ID(BETTER_ENUMS_M42(m, d, __VA_ARGS__))
  174. #define BETTER_ENUMS_M44(m, d, x, ...) m(d, 43, x) BETTER_ENUMS_ID(BETTER_ENUMS_M43(m, d, __VA_ARGS__))
  175. #define BETTER_ENUMS_M45(m, d, x, ...) m(d, 44, x) BETTER_ENUMS_ID(BETTER_ENUMS_M44(m, d, __VA_ARGS__))
  176. #define BETTER_ENUMS_M46(m, d, x, ...) m(d, 45, x) BETTER_ENUMS_ID(BETTER_ENUMS_M45(m, d, __VA_ARGS__))
  177. #define BETTER_ENUMS_M47(m, d, x, ...) m(d, 46, x) BETTER_ENUMS_ID(BETTER_ENUMS_M46(m, d, __VA_ARGS__))
  178. #define BETTER_ENUMS_M48(m, d, x, ...) m(d, 47, x) BETTER_ENUMS_ID(BETTER_ENUMS_M47(m, d, __VA_ARGS__))
  179. #define BETTER_ENUMS_M49(m, d, x, ...) m(d, 48, x) BETTER_ENUMS_ID(BETTER_ENUMS_M48(m, d, __VA_ARGS__))
  180. #define BETTER_ENUMS_M50(m, d, x, ...) m(d, 49, x) BETTER_ENUMS_ID(BETTER_ENUMS_M49(m, d, __VA_ARGS__))
  181. #define BETTER_ENUMS_M51(m, d, x, ...) m(d, 50, x) BETTER_ENUMS_ID(BETTER_ENUMS_M50(m, d, __VA_ARGS__))
  182. #define BETTER_ENUMS_M52(m, d, x, ...) m(d, 51, x) BETTER_ENUMS_ID(BETTER_ENUMS_M51(m, d, __VA_ARGS__))
  183. #define BETTER_ENUMS_M53(m, d, x, ...) m(d, 52, x) BETTER_ENUMS_ID(BETTER_ENUMS_M52(m, d, __VA_ARGS__))
  184. #define BETTER_ENUMS_M54(m, d, x, ...) m(d, 53, x) BETTER_ENUMS_ID(BETTER_ENUMS_M53(m, d, __VA_ARGS__))
  185. #define BETTER_ENUMS_M55(m, d, x, ...) m(d, 54, x) BETTER_ENUMS_ID(BETTER_ENUMS_M54(m, d, __VA_ARGS__))
  186. #define BETTER_ENUMS_M56(m, d, x, ...) m(d, 55, x) BETTER_ENUMS_ID(BETTER_ENUMS_M55(m, d, __VA_ARGS__))
  187. #define BETTER_ENUMS_M57(m, d, x, ...) m(d, 56, x) BETTER_ENUMS_ID(BETTER_ENUMS_M56(m, d, __VA_ARGS__))
  188. #define BETTER_ENUMS_M58(m, d, x, ...) m(d, 57, x) BETTER_ENUMS_ID(BETTER_ENUMS_M57(m, d, __VA_ARGS__))
  189. #define BETTER_ENUMS_M59(m, d, x, ...) m(d, 58, x) BETTER_ENUMS_ID(BETTER_ENUMS_M58(m, d, __VA_ARGS__))
  190. #define BETTER_ENUMS_M60(m, d, x, ...) m(d, 59, x) BETTER_ENUMS_ID(BETTER_ENUMS_M59(m, d, __VA_ARGS__))
  191. #define BETTER_ENUMS_M61(m, d, x, ...) m(d, 60, x) BETTER_ENUMS_ID(BETTER_ENUMS_M60(m, d, __VA_ARGS__))
  192. #define BETTER_ENUMS_M62(m, d, x, ...) m(d, 61, x) BETTER_ENUMS_ID(BETTER_ENUMS_M61(m, d, __VA_ARGS__))
  193. #define BETTER_ENUMS_M63(m, d, x, ...) m(d, 62, x) BETTER_ENUMS_ID(BETTER_ENUMS_M62(m, d, __VA_ARGS__))
  194. #define BETTER_ENUMS_M64(m, d, x, ...) m(d, 63, x) BETTER_ENUMS_ID(BETTER_ENUMS_M63(m, d, __VA_ARGS__))
  195. #define BETTER_ENUMS_PP_COUNT_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, \
  196. _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, \
  197. _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, \
  198. _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, \
  199. _63, _64, count, ...) \
  200. count
  201. #define BETTER_ENUMS_PP_COUNT(...) \
  202. BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT_IMPL( \
  203. __VA_ARGS__, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, \
  204. 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \
  205. 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1))
  206. #define BETTER_ENUMS_ITERATE(X, f, l) \
  207. X(f, l, 0) \
  208. X(f, l, 1) X(f, l, 2) X(f, l, 3) X(f, l, 4) X(f, l, 5) X(f, l, 6) X(f, l, 7) X(f, l, 8) X(f, l, 9) \
  209. X(f, l, 10) X(f, l, 11) X(f, l, 12) X(f, l, 13) X(f, l, 14) X(f, l, 15) X(f, l, 16) X(f, l, 17) \
  210. X(f, l, 18) X(f, l, 19) X(f, l, 20) X(f, l, 21) X(f, l, 22) X(f, l, 23)
  211. #endif // #ifdef BETTER_ENUMS_MACRO_FILE else case
  212. namespace better_enums
  213. {
  214. // Optional type.
  215. template<typename T>
  216. BETTER_ENUMS_CONSTEXPR_ inline T _default()
  217. {
  218. return static_cast<typename T::_enumerated>(0);
  219. }
  220. template<>
  221. BETTER_ENUMS_CONSTEXPR_ inline const char *_default<const char *>()
  222. {
  223. return BETTER_ENUMS_NULLPTR;
  224. }
  225. template<>
  226. BETTER_ENUMS_CONSTEXPR_ inline std::size_t _default<std::size_t>()
  227. {
  228. return 0;
  229. }
  230. template<typename T>
  231. struct optional
  232. {
  233. BETTER_ENUMS_CONSTEXPR_ optional() : _valid(false), _value(_default<T>()) { }
  234. BETTER_ENUMS_CONSTEXPR_ optional(T v) : _valid(true), _value(v) { }
  235. BETTER_ENUMS_CONSTEXPR_ const T &operator*() const { return _value; }
  236. BETTER_ENUMS_CONSTEXPR_ const T *operator->() const { return &_value; }
  237. BETTER_ENUMS_CONSTEXPR_ operator bool() const { return _valid; }
  238. BETTER_ENUMS_CONSTEXPR_ const T &value() const { return _value; }
  239. private:
  240. bool _valid;
  241. T _value;
  242. };
  243. template<typename CastTo, typename Element>
  244. BETTER_ENUMS_CONSTEXPR_ static optional<CastTo> _map_index(const Element *array, optional<std::size_t> index)
  245. {
  246. return index ? static_cast<CastTo>(array[*index]) : optional<CastTo>();
  247. }
  248. #ifdef BETTER_ENUMS_VC2008_WORKAROUNDS
  249. #define BETTER_ENUMS_OR_THROW \
  250. if (!maybe) \
  251. throw std::runtime_error(message); \
  252. \
  253. return *maybe;
  254. #else
  255. #define BETTER_ENUMS_OR_THROW return maybe ? *maybe : throw std::runtime_error(message);
  256. #endif
  257. BETTER_ENUMS_IF_EXCEPTIONS(template<typename T>
  258. BETTER_ENUMS_CONSTEXPR_ static T _or_throw(optional<T> maybe,
  259. const char *message){ BETTER_ENUMS_OR_THROW })
  260. template<typename T>
  261. BETTER_ENUMS_CONSTEXPR_ static T *_or_null(optional<T *> maybe)
  262. {
  263. return maybe ? *maybe : BETTER_ENUMS_NULLPTR;
  264. }
  265. template<typename T>
  266. BETTER_ENUMS_CONSTEXPR_ static T _or_zero(optional<T> maybe)
  267. {
  268. return maybe ? *maybe : T::_from_integral_unchecked(0);
  269. }
  270. // Functional sequencing. This is essentially a comma operator wrapped in a
  271. // constexpr function. g++ 4.7 doesn't "accept" integral constants in the second
  272. // position for the comma operator, and emits an external symbol, which then
  273. // causes a linking error.
  274. template<typename T, typename U>
  275. BETTER_ENUMS_CONSTEXPR_ U continue_with(T, U value)
  276. {
  277. return value;
  278. }
  279. // Values array declaration helper.
  280. //! Get intrinsic value of an (Enum::value) by taking advantage of
  281. // C-conversion's parentheses priority
  282. template<typename EnumType>
  283. struct _eat_assign
  284. {
  285. explicit BETTER_ENUMS_CONSTEXPR_ _eat_assign(EnumType value) : _value(value) { }
  286. template<typename Any>
  287. BETTER_ENUMS_CONSTEXPR_ const _eat_assign &operator=(Any) const
  288. {
  289. return *this;
  290. }
  291. BETTER_ENUMS_CONSTEXPR_ operator EnumType() const { return _value; }
  292. private:
  293. EnumType _value;
  294. };
  295. // Iterables.
  296. template<typename Element>
  297. struct _iterable
  298. {
  299. typedef const Element *iterator;
  300. BETTER_ENUMS_CONSTEXPR_ iterator begin() const { return iterator(_array); }
  301. BETTER_ENUMS_CONSTEXPR_ iterator end() const { return iterator(_array + _size); }
  302. BETTER_ENUMS_CONSTEXPR_ std::size_t size() const { return _size; }
  303. BETTER_ENUMS_CONSTEXPR_ const Element &operator[](std::size_t index) const { return _array[index]; }
  304. BETTER_ENUMS_CONSTEXPR_ _iterable(const Element *array, std::size_t s) : _array(array), _size(s) { }
  305. private:
  306. const Element *const _array;
  307. const std::size_t _size;
  308. };
  309. // String routines.
  310. BETTER_ENUMS_CONSTEXPR_ static const char *_name_enders = "= \t\n";
  311. BETTER_ENUMS_CONSTEXPR_ inline bool _ends_name(char c, std::size_t index = 0)
  312. {
  313. return c == _name_enders[index] ? true : _name_enders[index] == '\0' ? false : _ends_name(c, index + 1);
  314. }
  315. BETTER_ENUMS_CONSTEXPR_ inline bool _has_initializer(const char *s, std::size_t index = 0)
  316. {
  317. return s[index] == '\0' ? false : s[index] == '=' ? true : _has_initializer(s, index + 1);
  318. }
  319. BETTER_ENUMS_CONSTEXPR_ inline std::size_t _constant_length(const char *s, std::size_t index = 0)
  320. {
  321. return _ends_name(s[index]) ? index : _constant_length(s, index + 1);
  322. }
  323. BETTER_ENUMS_CONSTEXPR_ inline char _select(const char *from, std::size_t from_length, std::size_t index)
  324. {
  325. return index >= from_length ? '\0' : from[index];
  326. }
  327. BETTER_ENUMS_CONSTEXPR_ inline char _to_lower_ascii(char c)
  328. {
  329. return c >= 0x41 && c <= 0x5A ? static_cast<char>(c + 0x20) : c;
  330. }
  331. BETTER_ENUMS_CONSTEXPR_ inline bool _names_match(const char *stringizedName, const char *referenceName,
  332. std::size_t index = 0)
  333. {
  334. return _ends_name(stringizedName[index])
  335. ? referenceName[index] == '\0'
  336. : referenceName[index] == '\0' ? false
  337. : stringizedName[index] != referenceName[index]
  338. ? false
  339. : _names_match(stringizedName, referenceName, index + 1);
  340. }
  341. BETTER_ENUMS_CONSTEXPR_ inline bool _names_match_nocase(const char *stringizedName, const char *referenceName,
  342. std::size_t index = 0)
  343. {
  344. return _ends_name(stringizedName[index]) ? referenceName[index] == '\0'
  345. : referenceName[index] == '\0'
  346. ? false
  347. : _to_lower_ascii(stringizedName[index]) != _to_lower_ascii(referenceName[index])
  348. ? false
  349. : _names_match_nocase(stringizedName, referenceName, index + 1);
  350. }
  351. inline void _trim_names(const char *const *raw_names, const char **trimmed_names, char *storage, std::size_t count)
  352. {
  353. std::size_t offset = 0;
  354. for (std::size_t index = 0; index < count; ++index) {
  355. trimmed_names[index] = storage + offset;
  356. std::size_t trimmed_length = std::strcspn(raw_names[index], _name_enders);
  357. storage[offset + trimmed_length] = '\0';
  358. std::size_t raw_length = std::strlen(raw_names[index]);
  359. offset += raw_length + 1;
  360. }
  361. }
  362. // Eager initialization.
  363. template<typename Enum>
  364. struct _initialize_at_program_start
  365. {
  366. _initialize_at_program_start() { Enum::initialize(); }
  367. };
  368. } // namespace better_enums
  369. // Array generation macros.
  370. #define BETTER_ENUMS_EAT_ASSIGN_SINGLE(EnumType, index, expression) \
  371. (EnumType)((::better_enums::_eat_assign<EnumType>)EnumType::expression),
  372. #define BETTER_ENUMS_EAT_ASSIGN(EnumType, ...) \
  373. BETTER_ENUMS_ID(BETTER_ENUMS_PP_MAP(BETTER_ENUMS_EAT_ASSIGN_SINGLE, EnumType, __VA_ARGS__))
  374. #ifdef BETTER_ENUMS_HAVE_CONSTEXPR
  375. #define BETTER_ENUMS_SELECT_SINGLE_CHARACTER(from, from_length, index) \
  376. ::better_enums::_select(from, from_length, index),
  377. #define BETTER_ENUMS_SELECT_CHARACTERS(from, from_length) \
  378. BETTER_ENUMS_ITERATE(BETTER_ENUMS_SELECT_SINGLE_CHARACTER, from, from_length)
  379. #define BETTER_ENUMS_TRIM_SINGLE_STRING(ignored, index, expression) \
  380. constexpr std::size_t _length_##index = ::better_enums::_constant_length(#expression); \
  381. constexpr const char _trimmed_##index[] = { BETTER_ENUMS_SELECT_CHARACTERS(#expression, \
  382. _length_##index) }; \
  383. constexpr const char *_final_##index = \
  384. ::better_enums::_has_initializer(#expression) ? _trimmed_##index : #expression;
  385. #define BETTER_ENUMS_TRIM_STRINGS(...) \
  386. BETTER_ENUMS_ID(BETTER_ENUMS_PP_MAP(BETTER_ENUMS_TRIM_SINGLE_STRING, ignored, __VA_ARGS__))
  387. #define BETTER_ENUMS_REFER_TO_SINGLE_STRING(ignored, index, expression) _final_##index,
  388. #define BETTER_ENUMS_REFER_TO_STRINGS(...) \
  389. BETTER_ENUMS_ID(BETTER_ENUMS_PP_MAP(BETTER_ENUMS_REFER_TO_SINGLE_STRING, ignored, __VA_ARGS__))
  390. #endif // #ifdef BETTER_ENUMS_HAVE_CONSTEXPR
  391. #define BETTER_ENUMS_STRINGIZE_SINGLE(ignored, index, expression) #expression,
  392. #define BETTER_ENUMS_STRINGIZE(...) \
  393. BETTER_ENUMS_ID(BETTER_ENUMS_PP_MAP(BETTER_ENUMS_STRINGIZE_SINGLE, ignored, __VA_ARGS__))
  394. #define BETTER_ENUMS_RESERVE_STORAGE_SINGLE(ignored, index, expression) #expression ","
  395. #define BETTER_ENUMS_RESERVE_STORAGE(...) \
  396. BETTER_ENUMS_ID(BETTER_ENUMS_PP_MAP(BETTER_ENUMS_RESERVE_STORAGE_SINGLE, ignored, __VA_ARGS__))
  397. // The enums proper.
  398. #define BETTER_ENUMS_NS(EnumType) better_enums_data_##EnumType
  399. #ifdef BETTER_ENUMS_VC2008_WORKAROUNDS
  400. #define BETTER_ENUMS_COPY_CONSTRUCTOR(Enum) \
  401. BETTER_ENUMS_CONSTEXPR_ Enum(const Enum &other) : _value(other._value) { }
  402. #else
  403. #define BETTER_ENUMS_COPY_CONSTRUCTOR(Enum)
  404. #endif
  405. #ifndef BETTER_ENUMS_CLASS_ATTRIBUTE
  406. #define BETTER_ENUMS_CLASS_ATTRIBUTE
  407. #endif
  408. #define BETTER_ENUMS_TYPE(SetUnderlyingType, SwitchType, GenerateSwitchType, GenerateStrings, ToStringConstexpr, \
  409. DeclareInitialize, DefineInitialize, CallInitialize, Enum, Underlying, ...) \
  410. \
  411. namespace better_enums_data_##Enum { BETTER_ENUMS_ID(GenerateSwitchType(Underlying, __VA_ARGS__)) } \
  412. \
  413. class BETTER_ENUMS_CLASS_ATTRIBUTE Enum \
  414. { \
  415. private: \
  416. typedef ::better_enums::optional<Enum> _optional; \
  417. typedef ::better_enums::optional<std::size_t> _optional_index; \
  418. \
  419. public: \
  420. typedef Underlying _integral; \
  421. \
  422. enum _enumerated SetUnderlyingType(Underlying){ __VA_ARGS__ }; \
  423. \
  424. BETTER_ENUMS_CONSTEXPR_ Enum(_enumerated value) : _value(value) { } \
  425. \
  426. BETTER_ENUMS_COPY_CONSTRUCTOR(Enum) \
  427. \
  428. BETTER_ENUMS_CONSTEXPR_ operator SwitchType(Enum)() const { return SwitchType(Enum)(_value); } \
  429. \
  430. BETTER_ENUMS_CONSTEXPR_ _integral _to_integral() const; \
  431. BETTER_ENUMS_IF_EXCEPTIONS(BETTER_ENUMS_CONSTEXPR_ static Enum _from_integral(_integral value);) \
  432. BETTER_ENUMS_CONSTEXPR_ static Enum _from_integral_unchecked(_integral value); \
  433. BETTER_ENUMS_CONSTEXPR_ static _optional _from_integral_nothrow(_integral value); \
  434. \
  435. BETTER_ENUMS_CONSTEXPR_ std::size_t _to_index() const; \
  436. BETTER_ENUMS_IF_EXCEPTIONS(BETTER_ENUMS_CONSTEXPR_ static Enum _from_index(std::size_t index);) \
  437. BETTER_ENUMS_CONSTEXPR_ static Enum _from_index_unchecked(std::size_t index); \
  438. BETTER_ENUMS_CONSTEXPR_ static _optional _from_index_nothrow(std::size_t index); \
  439. \
  440. ToStringConstexpr const char *_to_string() const; \
  441. BETTER_ENUMS_IF_EXCEPTIONS(BETTER_ENUMS_CONSTEXPR_ static Enum _from_string(const char *name);) \
  442. BETTER_ENUMS_CONSTEXPR_ static _optional _from_string_nothrow(const char *name); \
  443. \
  444. BETTER_ENUMS_IF_EXCEPTIONS(BETTER_ENUMS_CONSTEXPR_ static Enum _from_string_nocase(const char *name);) \
  445. BETTER_ENUMS_CONSTEXPR_ static _optional _from_string_nocase_nothrow(const char *name); \
  446. \
  447. BETTER_ENUMS_CONSTEXPR_ static bool _is_valid(_integral value); \
  448. BETTER_ENUMS_CONSTEXPR_ static bool _is_valid(const char *name); \
  449. BETTER_ENUMS_CONSTEXPR_ static bool _is_valid_nocase(const char *name); \
  450. \
  451. typedef ::better_enums::_iterable<Enum> _value_iterable; \
  452. typedef ::better_enums::_iterable<const char *> _name_iterable; \
  453. \
  454. typedef _value_iterable::iterator _value_iterator; \
  455. typedef _name_iterable::iterator _name_iterator; \
  456. \
  457. BETTER_ENUMS_CONSTEXPR_ static const std::size_t _size_constant = \
  458. BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT(__VA_ARGS__)); \
  459. BETTER_ENUMS_CONSTEXPR_ static std::size_t _size() { return _size_constant; } \
  460. \
  461. BETTER_ENUMS_CONSTEXPR_ static const char *_name(); \
  462. BETTER_ENUMS_CONSTEXPR_ static _value_iterable _values(); \
  463. ToStringConstexpr static _name_iterable _names(); \
  464. \
  465. _integral _value; \
  466. \
  467. BETTER_ENUMS_DEFAULT_CONSTRUCTOR(Enum) \
  468. \
  469. private: \
  470. explicit BETTER_ENUMS_CONSTEXPR_ Enum(const _integral &value) : _value(value) { } \
  471. \
  472. DeclareInitialize \
  473. \
  474. BETTER_ENUMS_CONSTEXPR_ static _optional_index \
  475. _from_value_loop(_integral value, std::size_t index = 0); \
  476. BETTER_ENUMS_CONSTEXPR_ static _optional_index _from_string_loop(const char *name, std::size_t index = 0); \
  477. BETTER_ENUMS_CONSTEXPR_ static _optional_index _from_string_nocase_loop(const char *name, \
  478. std::size_t index = 0); \
  479. \
  480. friend struct ::better_enums::_initialize_at_program_start<Enum>; \
  481. }; \
  482. \
  483. namespace better_enums_data_##Enum \
  484. { \
  485. \
  486. static ::better_enums::_initialize_at_program_start<Enum> _force_initialization; \
  487. \
  488. enum _putNamesInThisScopeAlso \
  489. { \
  490. __VA_ARGS__ \
  491. }; \
  492. \
  493. BETTER_ENUMS_IGNORE_OLD_CAST_HEADER \
  494. BETTER_ENUMS_IGNORE_OLD_CAST_BEGIN \
  495. BETTER_ENUMS_CONSTEXPR_ const Enum _value_array[] = { BETTER_ENUMS_ID( \
  496. BETTER_ENUMS_EAT_ASSIGN(Enum, __VA_ARGS__)) }; \
  497. BETTER_ENUMS_IGNORE_OLD_CAST_END \
  498. \
  499. BETTER_ENUMS_ID(GenerateStrings(Enum, __VA_ARGS__)) \
  500. } \
  501. \
  502. BETTER_ENUMS_IGNORE_ATTRIBUTES_HEADER \
  503. BETTER_ENUMS_IGNORE_ATTRIBUTES_BEGIN \
  504. BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ inline const Enum operator+(Enum::_enumerated enumerated) \
  505. { \
  506. return static_cast<Enum>(enumerated); \
  507. } \
  508. BETTER_ENUMS_IGNORE_ATTRIBUTES_END \
  509. \
  510. BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional_index Enum::_from_value_loop(Enum::_integral value, \
  511. std::size_t index) \
  512. { \
  513. return index == _size() \
  514. ? _optional_index() \
  515. : BETTER_ENUMS_NS(Enum)::_value_array[index]._value == value ? _optional_index(index) \
  516. : _from_value_loop(value, index + 1); \
  517. } \
  518. \
  519. BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional_index Enum::_from_string_loop(const char *name, \
  520. std::size_t index) \
  521. { \
  522. return index == _size() ? _optional_index() \
  523. : ::better_enums::_names_match(BETTER_ENUMS_NS(Enum)::_raw_names()[index], name) \
  524. ? _optional_index(index) \
  525. : _from_string_loop(name, index + 1); \
  526. } \
  527. \
  528. BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional_index Enum::_from_string_nocase_loop(const char *name, \
  529. std::size_t index) \
  530. { \
  531. return index == _size() \
  532. ? _optional_index() \
  533. : ::better_enums::_names_match_nocase(BETTER_ENUMS_NS(Enum)::_raw_names()[index], name) \
  534. ? _optional_index(index) \
  535. : _from_string_nocase_loop(name, index + 1); \
  536. } \
  537. \
  538. BETTER_ENUMS_CONSTEXPR_ inline Enum::_integral Enum::_to_integral() const { return _integral(_value); } \
  539. \
  540. BETTER_ENUMS_CONSTEXPR_ inline std::size_t Enum::_to_index() const { return *_from_value_loop(_value); } \
  541. \
  542. BETTER_ENUMS_CONSTEXPR_ inline Enum Enum::_from_index_unchecked(std::size_t index) \
  543. { \
  544. return ::better_enums::_or_zero(_from_index_nothrow(index)); \
  545. } \
  546. \
  547. BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional Enum::_from_index_nothrow(std::size_t index) \
  548. { \
  549. return index >= _size() ? _optional() : _optional(BETTER_ENUMS_NS(Enum)::_value_array[index]); \
  550. } \
  551. \
  552. BETTER_ENUMS_IF_EXCEPTIONS(BETTER_ENUMS_CONSTEXPR_ inline Enum Enum::_from_index(std::size_t index) { \
  553. return ::better_enums::_or_throw(_from_index_nothrow(index), #Enum "::_from_index: invalid argument"); \
  554. }) \
  555. \
  556. BETTER_ENUMS_CONSTEXPR_ inline Enum Enum::_from_integral_unchecked(_integral value) \
  557. { \
  558. return static_cast<_enumerated>(value); \
  559. } \
  560. \
  561. BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional Enum::_from_integral_nothrow(_integral value) \
  562. { \
  563. return ::better_enums::_map_index<Enum>(BETTER_ENUMS_NS(Enum)::_value_array, _from_value_loop(value)); \
  564. } \
  565. \
  566. BETTER_ENUMS_IF_EXCEPTIONS(BETTER_ENUMS_CONSTEXPR_ inline Enum Enum::_from_integral(_integral value) { \
  567. return ::better_enums::_or_throw(_from_integral_nothrow(value), \
  568. #Enum "::_from_integral: invalid argument"); \
  569. }) \
  570. \
  571. ToStringConstexpr inline const char *Enum::_to_string() const \
  572. { \
  573. return ::better_enums::_or_null(::better_enums::_map_index<const char *>( \
  574. BETTER_ENUMS_NS(Enum)::_name_array(), _from_value_loop(CallInitialize(_value)))); \
  575. } \
  576. \
  577. BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional Enum::_from_string_nothrow(const char *name) \
  578. { \
  579. return ::better_enums::_map_index<Enum>(BETTER_ENUMS_NS(Enum)::_value_array, _from_string_loop(name)); \
  580. } \
  581. \
  582. BETTER_ENUMS_IF_EXCEPTIONS(BETTER_ENUMS_CONSTEXPR_ inline Enum Enum::_from_string(const char *name) { \
  583. return ::better_enums::_or_throw(_from_string_nothrow(name), #Enum "::_from_string: invalid argument"); \
  584. }) \
  585. \
  586. BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional Enum::_from_string_nocase_nothrow(const char *name) \
  587. { \
  588. return ::better_enums::_map_index<Enum>(BETTER_ENUMS_NS(Enum)::_value_array, \
  589. _from_string_nocase_loop(name)); \
  590. } \
  591. \
  592. BETTER_ENUMS_IF_EXCEPTIONS(BETTER_ENUMS_CONSTEXPR_ inline Enum Enum::_from_string_nocase(const char *name) { \
  593. return ::better_enums::_or_throw(_from_string_nocase_nothrow(name), \
  594. #Enum "::_from_string_nocase: invalid argument"); \
  595. }) \
  596. \
  597. BETTER_ENUMS_CONSTEXPR_ inline bool Enum::_is_valid(_integral value) { return _from_value_loop(value); } \
  598. \
  599. BETTER_ENUMS_CONSTEXPR_ inline bool Enum::_is_valid(const char *name) { return _from_string_loop(name); } \
  600. \
  601. BETTER_ENUMS_CONSTEXPR_ inline bool Enum::_is_valid_nocase(const char *name) \
  602. { \
  603. return _from_string_nocase_loop(name); \
  604. } \
  605. \
  606. BETTER_ENUMS_CONSTEXPR_ inline const char *Enum::_name() { return #Enum; } \
  607. \
  608. BETTER_ENUMS_CONSTEXPR_ inline Enum::_value_iterable Enum::_values() \
  609. { \
  610. return _value_iterable(BETTER_ENUMS_NS(Enum)::_value_array, _size()); \
  611. } \
  612. \
  613. ToStringConstexpr inline Enum::_name_iterable Enum::_names() \
  614. { \
  615. return _name_iterable(BETTER_ENUMS_NS(Enum)::_name_array(), CallInitialize(_size())); \
  616. } \
  617. \
  618. DefineInitialize(Enum) \
  619. \
  620. BETTER_ENUMS_IGNORE_ATTRIBUTES_HEADER BETTER_ENUMS_IGNORE_ATTRIBUTES_BEGIN BETTER_ENUMS_UNUSED \
  621. BETTER_ENUMS_CONSTEXPR_ inline bool \
  622. operator==(const Enum &a, const Enum &b) \
  623. { \
  624. return a._to_integral() == b._to_integral(); \
  625. } \
  626. \
  627. BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ inline bool operator!=(const Enum &a, const Enum &b) \
  628. { \
  629. return a._to_integral() != b._to_integral(); \
  630. } \
  631. \
  632. BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ inline bool operator<(const Enum &a, const Enum &b) \
  633. { \
  634. return a._to_integral() < b._to_integral(); \
  635. } \
  636. \
  637. BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ inline bool operator<=(const Enum &a, const Enum &b) \
  638. { \
  639. return a._to_integral() <= b._to_integral(); \
  640. } \
  641. \
  642. BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ inline bool operator>(const Enum &a, const Enum &b) \
  643. { \
  644. return a._to_integral() > b._to_integral(); \
  645. } \
  646. \
  647. BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ inline bool operator>=(const Enum &a, const Enum &b) \
  648. { \
  649. return a._to_integral() >= b._to_integral(); \
  650. } \
  651. BETTER_ENUMS_IGNORE_ATTRIBUTES_END \
  652. \
  653. template<typename Char, typename Traits> \
  654. std::basic_ostream<Char, Traits> &operator<<(std::basic_ostream<Char, Traits> &stream, const Enum &value) \
  655. { \
  656. return stream << value._to_string(); \
  657. } \
  658. \
  659. template<typename Char, typename Traits> \
  660. std::basic_istream<Char, Traits> &operator>>(std::basic_istream<Char, Traits> &stream, Enum &value) \
  661. { \
  662. std::basic_string<Char, Traits> buffer; \
  663. \
  664. stream >> buffer; \
  665. ::better_enums::optional<Enum> converted = Enum::_from_string_nothrow(buffer.c_str()); \
  666. \
  667. if (converted) \
  668. value = *converted; \
  669. else \
  670. stream.setstate(std::basic_istream<Char, Traits>::failbit); \
  671. \
  672. return stream; \
  673. }
  674. // Enum feature options.
  675. // C++98, C++11
  676. #define BETTER_ENUMS_CXX98_UNDERLYING_TYPE(Underlying)
  677. // C++11
  678. #define BETTER_ENUMS_CXX11_UNDERLYING_TYPE(Underlying) \
  679. : Underlying
  680. #if defined(_MSC_VER) && _MSC_VER >= 1700
  681. // VS 2012 and above fully support strongly typed enums and will warn about
  682. // incorrect usage.
  683. #define BETTER_ENUMS_LEGACY_UNDERLYING_TYPE(Underlying) BETTER_ENUMS_CXX11_UNDERLYING_TYPE(Underlying)
  684. #else
  685. #define BETTER_ENUMS_LEGACY_UNDERLYING_TYPE(Underlying) BETTER_ENUMS_CXX98_UNDERLYING_TYPE(Underlying)
  686. #endif
  687. // C++98, C++11
  688. #define BETTER_ENUMS_REGULAR_ENUM_SWITCH_TYPE(Type) _enumerated
  689. // C++11
  690. #define BETTER_ENUMS_ENUM_CLASS_SWITCH_TYPE(Type) BETTER_ENUMS_NS(Type)::_enumClassForSwitchStatements
  691. // C++98, C++11
  692. #define BETTER_ENUMS_REGULAR_ENUM_SWITCH_TYPE_GENERATE(Underlying, ...)
  693. // C++11
  694. #define BETTER_ENUMS_ENUM_CLASS_SWITCH_TYPE_GENERATE(Underlying, ...) \
  695. enum class _enumClassForSwitchStatements : Underlying \
  696. { \
  697. __VA_ARGS__ \
  698. };
  699. // C++98
  700. #define BETTER_ENUMS_CXX98_TRIM_STRINGS_ARRAYS(Enum, ...) \
  701. inline const char **_raw_names() \
  702. { \
  703. static const char *value[] = { BETTER_ENUMS_ID(BETTER_ENUMS_STRINGIZE(__VA_ARGS__)) }; \
  704. return value; \
  705. } \
  706. \
  707. inline char *_name_storage() \
  708. { \
  709. static char storage[] = BETTER_ENUMS_ID(BETTER_ENUMS_RESERVE_STORAGE(__VA_ARGS__)); \
  710. return storage; \
  711. } \
  712. \
  713. inline const char **_name_array() \
  714. { \
  715. static const char *value[Enum::_size_constant]; \
  716. return value; \
  717. } \
  718. \
  719. inline bool &_initialized() \
  720. { \
  721. static bool value = false; \
  722. return value; \
  723. }
  724. // C++11 fast version
  725. #define BETTER_ENUMS_CXX11_PARTIAL_CONSTEXPR_TRIM_STRINGS_ARRAYS(Enum, ...) \
  726. constexpr const char *_the_raw_names[] = { BETTER_ENUMS_ID(BETTER_ENUMS_STRINGIZE(__VA_ARGS__)) }; \
  727. \
  728. constexpr const char *const *_raw_names() { return _the_raw_names; } \
  729. \
  730. inline char *_name_storage() \
  731. { \
  732. static char storage[] = BETTER_ENUMS_ID(BETTER_ENUMS_RESERVE_STORAGE(__VA_ARGS__)); \
  733. return storage; \
  734. } \
  735. \
  736. inline const char **_name_array() \
  737. { \
  738. static const char *value[Enum::_size_constant]; \
  739. return value; \
  740. } \
  741. \
  742. inline bool &_initialized() \
  743. { \
  744. static bool value = false; \
  745. return value; \
  746. }
  747. // C++11 slow all-constexpr version
  748. #define BETTER_ENUMS_CXX11_FULL_CONSTEXPR_TRIM_STRINGS_ARRAYS(Enum, ...) \
  749. BETTER_ENUMS_ID(BETTER_ENUMS_TRIM_STRINGS(__VA_ARGS__)) \
  750. \
  751. constexpr const char *const _the_name_array[] = { BETTER_ENUMS_ID( \
  752. BETTER_ENUMS_REFER_TO_STRINGS(__VA_ARGS__)) }; \
  753. \
  754. constexpr const char *const *_name_array() { return _the_name_array; } \
  755. \
  756. constexpr const char *const *_raw_names() { return _the_name_array; }
  757. // C++98, C++11 fast version
  758. #define BETTER_ENUMS_NO_CONSTEXPR_TO_STRING_KEYWORD
  759. // C++11 slow all-constexpr version
  760. #define BETTER_ENUMS_CONSTEXPR_TO_STRING_KEYWORD constexpr
  761. // C++98, C++11 fast version
  762. #define BETTER_ENUMS_DO_DECLARE_INITIALIZE static int initialize();
  763. // C++11 slow all-constexpr version
  764. #define BETTER_ENUMS_DECLARE_EMPTY_INITIALIZE \
  765. static int initialize() { return 0; }
  766. // C++98, C++11 fast version
  767. #define BETTER_ENUMS_DO_DEFINE_INITIALIZE(Enum) \
  768. inline int Enum::initialize() \
  769. { \
  770. if (BETTER_ENUMS_NS(Enum)::_initialized()) \
  771. return 0; \
  772. \
  773. ::better_enums::_trim_names(BETTER_ENUMS_NS(Enum)::_raw_names(), BETTER_ENUMS_NS(Enum)::_name_array(), \
  774. BETTER_ENUMS_NS(Enum)::_name_storage(), _size()); \
  775. \
  776. BETTER_ENUMS_NS(Enum)::_initialized() = true; \
  777. \
  778. return 0; \
  779. }
  780. // C++11 slow all-constexpr version
  781. #define BETTER_ENUMS_DO_NOT_DEFINE_INITIALIZE(Enum)
  782. // C++98, C++11 fast version
  783. #define BETTER_ENUMS_DO_CALL_INITIALIZE(value) ::better_enums::continue_with(initialize(), value)
  784. // C++11 slow all-constexpr version
  785. #define BETTER_ENUMS_DO_NOT_CALL_INITIALIZE(value) value
  786. // User feature selection.
  787. #ifdef BETTER_ENUMS_STRICT_CONVERSION
  788. #define BETTER_ENUMS_DEFAULT_SWITCH_TYPE BETTER_ENUMS_ENUM_CLASS_SWITCH_TYPE
  789. #define BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE BETTER_ENUMS_ENUM_CLASS_SWITCH_TYPE_GENERATE
  790. #else
  791. #define BETTER_ENUMS_DEFAULT_SWITCH_TYPE BETTER_ENUMS_REGULAR_ENUM_SWITCH_TYPE
  792. #define BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE BETTER_ENUMS_REGULAR_ENUM_SWITCH_TYPE_GENERATE
  793. #endif
  794. #ifndef BETTER_ENUMS_DEFAULT_CONSTRUCTOR
  795. #define BETTER_ENUMS_DEFAULT_CONSTRUCTOR(Enum) \
  796. private: \
  797. Enum() : _value(0) { }
  798. #endif
  799. #ifdef BETTER_ENUMS_HAVE_CONSTEXPR
  800. #ifdef BETTER_ENUMS_CONSTEXPR_TO_STRING
  801. #define BETTER_ENUMS_DEFAULT_TRIM_STRINGS_ARRAYS BETTER_ENUMS_CXX11_FULL_CONSTEXPR_TRIM_STRINGS_ARRAYS
  802. #define BETTER_ENUMS_DEFAULT_TO_STRING_KEYWORD BETTER_ENUMS_CONSTEXPR_TO_STRING_KEYWORD
  803. #define BETTER_ENUMS_DEFAULT_DECLARE_INITIALIZE BETTER_ENUMS_DECLARE_EMPTY_INITIALIZE
  804. #define BETTER_ENUMS_DEFAULT_DEFINE_INITIALIZE BETTER_ENUMS_DO_NOT_DEFINE_INITIALIZE
  805. #define BETTER_ENUMS_DEFAULT_CALL_INITIALIZE BETTER_ENUMS_DO_NOT_CALL_INITIALIZE
  806. #else
  807. #define BETTER_ENUMS_DEFAULT_TRIM_STRINGS_ARRAYS BETTER_ENUMS_CXX11_PARTIAL_CONSTEXPR_TRIM_STRINGS_ARRAYS
  808. #define BETTER_ENUMS_DEFAULT_TO_STRING_KEYWORD BETTER_ENUMS_NO_CONSTEXPR_TO_STRING_KEYWORD
  809. #define BETTER_ENUMS_DEFAULT_DECLARE_INITIALIZE BETTER_ENUMS_DO_DECLARE_INITIALIZE
  810. #define BETTER_ENUMS_DEFAULT_DEFINE_INITIALIZE BETTER_ENUMS_DO_DEFINE_INITIALIZE
  811. #define BETTER_ENUMS_DEFAULT_CALL_INITIALIZE BETTER_ENUMS_DO_CALL_INITIALIZE
  812. #endif
  813. // Top-level macros.
  814. #define BETTER_ENUM(Enum, Underlying, ...) \
  815. BETTER_ENUMS_ID(BETTER_ENUMS_TYPE( \
  816. BETTER_ENUMS_CXX11_UNDERLYING_TYPE, BETTER_ENUMS_DEFAULT_SWITCH_TYPE, \
  817. BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE, BETTER_ENUMS_DEFAULT_TRIM_STRINGS_ARRAYS, \
  818. BETTER_ENUMS_DEFAULT_TO_STRING_KEYWORD, BETTER_ENUMS_DEFAULT_DECLARE_INITIALIZE, \
  819. BETTER_ENUMS_DEFAULT_DEFINE_INITIALIZE, BETTER_ENUMS_DEFAULT_CALL_INITIALIZE, Enum, Underlying, \
  820. __VA_ARGS__))
  821. #define SLOW_ENUM(Enum, Underlying, ...) \
  822. BETTER_ENUMS_ID(BETTER_ENUMS_TYPE( \
  823. BETTER_ENUMS_CXX11_UNDERLYING_TYPE, BETTER_ENUMS_DEFAULT_SWITCH_TYPE, \
  824. BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE, BETTER_ENUMS_CXX11_FULL_CONSTEXPR_TRIM_STRINGS_ARRAYS, \
  825. BETTER_ENUMS_CONSTEXPR_TO_STRING_KEYWORD, BETTER_ENUMS_DECLARE_EMPTY_INITIALIZE, \
  826. BETTER_ENUMS_DO_NOT_DEFINE_INITIALIZE, BETTER_ENUMS_DO_NOT_CALL_INITIALIZE, Enum, Underlying, \
  827. __VA_ARGS__))
  828. #else
  829. #define BETTER_ENUM(Enum, Underlying, ...) \
  830. BETTER_ENUMS_ID(BETTER_ENUMS_TYPE(BETTER_ENUMS_LEGACY_UNDERLYING_TYPE, BETTER_ENUMS_DEFAULT_SWITCH_TYPE, \
  831. BETTER_ENUMS_DEFAULT_SWITCH_TYPE_GENERATE, \
  832. BETTER_ENUMS_CXX98_TRIM_STRINGS_ARRAYS, \
  833. BETTER_ENUMS_NO_CONSTEXPR_TO_STRING_KEYWORD, \
  834. BETTER_ENUMS_DO_DECLARE_INITIALIZE, BETTER_ENUMS_DO_DEFINE_INITIALIZE, \
  835. BETTER_ENUMS_DO_CALL_INITIALIZE, Enum, Underlying, __VA_ARGS__))
  836. #endif
  837. namespace better_enums
  838. {
  839. // Maps.
  840. template<typename T>
  841. struct map_compare
  842. {
  843. BETTER_ENUMS_CONSTEXPR_ static bool less(const T &a, const T &b) { return a < b; }
  844. };
  845. template<>
  846. struct map_compare<const char *>
  847. {
  848. BETTER_ENUMS_CONSTEXPR_ static bool less(const char *a, const char *b) { return less_loop(a, b); }
  849. private:
  850. BETTER_ENUMS_CONSTEXPR_ static bool less_loop(const char *a, const char *b, size_t index = 0)
  851. {
  852. return a[index] != b[index] ? a[index] < b[index] : a[index] == '\0' ? false : less_loop(a, b, index + 1);
  853. }
  854. };
  855. template<>
  856. struct map_compare<const wchar_t *>
  857. {
  858. BETTER_ENUMS_CONSTEXPR_ static bool less(const wchar_t *a, const wchar_t *b) { return less_loop(a, b); }
  859. private:
  860. BETTER_ENUMS_CONSTEXPR_ static bool less_loop(const wchar_t *a, const wchar_t *b, size_t index = 0)
  861. {
  862. return a[index] != b[index] ? a[index] < b[index] : a[index] == L'\0' ? false : less_loop(a, b, index + 1);
  863. }
  864. };
  865. template<typename Enum, typename T, typename Compare = map_compare<T>>
  866. struct map
  867. {
  868. typedef T (*function)(Enum);
  869. BETTER_ENUMS_CONSTEXPR_ explicit map(function f) : _f(f) { }
  870. BETTER_ENUMS_CONSTEXPR_ T from_enum(Enum value) const { return _f(value); }
  871. BETTER_ENUMS_CONSTEXPR_ T operator[](Enum value) const { return _f(value); }
  872. BETTER_ENUMS_CONSTEXPR_ Enum to_enum(T value) const
  873. {
  874. return _or_throw(to_enum_nothrow(value), "map::to_enum: invalid argument");
  875. }
  876. BETTER_ENUMS_CONSTEXPR_ optional<Enum> to_enum_nothrow(T value, size_t index = 0) const
  877. {
  878. return index >= Enum::_size() ? optional<Enum>()
  879. : Compare::less(_f(Enum::_values()[index]), value)
  880. || Compare::less(value, _f(Enum::_values()[index]))
  881. ? to_enum_nothrow(value, index + 1)
  882. : Enum::_values()[index];
  883. }
  884. private:
  885. const function _f;
  886. };
  887. template<typename Enum, typename T>
  888. BETTER_ENUMS_CONSTEXPR_ map<Enum, T> make_map(T (*f)(Enum))
  889. {
  890. return map<Enum, T>(f);
  891. }
  892. } // namespace better_enums
  893. #define BETTER_ENUMS_DECLARE_STD_HASH(type) \
  894. namespace std \
  895. { \
  896. template<> \
  897. struct hash<type> \
  898. { \
  899. size_t operator()(const type &x) const { return std::hash<size_t>()(x._to_integral()); } \
  900. }; \
  901. }
  902. #endif // #ifndef BETTER_ENUMS_ENUM_H