Enum.h 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <AnKi/Util/Assert.h>
  7. #include <bit>
  8. namespace anki {
  9. /// @privatesection
  10. /// @{
  11. /// This is a template where the Type will be I64 if the T is any unsigned integer and U64 otherwise
  12. template<typename T, bool = std::is_unsigned<T>::value>
  13. class EnumSafeIntegerType
  14. {
  15. public:
  16. using Type = I64;
  17. };
  18. template<typename T>
  19. class EnumSafeIntegerType<T, true>
  20. {
  21. public:
  22. using Type = U64;
  23. };
  24. /// This macro will do an operation between 2 values. It will be used in constexpr functions. There is also an assertion which makes sure that the
  25. /// result will fit in an enum. Despite the fact that the assertion contains non-constexpr elements it will work on constexpr expressions. The
  26. /// compiler will compile-time ignore the non-constexpr part if the assert if the assertion expression is true.
  27. #define _ANKI_ENUM_OPERATION_BODY(enumType, regularOperator, a, b) \
  28. using EnumInt = std::underlying_type<enumType>::type; \
  29. using SafeInt = EnumSafeIntegerType<EnumInt>::Type; \
  30. const SafeInt c = SafeInt(a) regularOperator SafeInt(b); \
  31. ANKI_ASSERT(c <= SafeInt(std::numeric_limits<EnumInt>::max())); \
  32. return enumType(c)
  33. #define _ANKI_ENUM_OPERATOR(enumType, qualifier, regularOperator, assignmentOperator) \
  34. constexpr qualifier enumType operator regularOperator(const enumType a, const enumType b) \
  35. { \
  36. _ANKI_ENUM_OPERATION_BODY(enumType, regularOperator, a, b); \
  37. } \
  38. constexpr qualifier enumType operator regularOperator(const enumType a, const std::underlying_type<enumType>::type b) \
  39. { \
  40. _ANKI_ENUM_OPERATION_BODY(enumType, regularOperator, a, b); \
  41. } \
  42. constexpr qualifier enumType operator regularOperator(const std::underlying_type<enumType>::type a, const enumType b) \
  43. { \
  44. _ANKI_ENUM_OPERATION_BODY(enumType, regularOperator, a, b); \
  45. } \
  46. qualifier enumType& operator assignmentOperator(enumType& a, const enumType b) \
  47. { \
  48. a = a regularOperator b; \
  49. return a; \
  50. } \
  51. qualifier enumType& operator assignmentOperator(enumType& a, const std::underlying_type<enumType>::type b) \
  52. { \
  53. a = a regularOperator b; \
  54. return a; \
  55. } \
  56. qualifier std::underlying_type<enumType>::type& operator assignmentOperator(std::underlying_type<enumType>::type& a, const enumType b) \
  57. { \
  58. using EnumInt = std::underlying_type<enumType>::type; \
  59. a = EnumInt(a regularOperator b); \
  60. return a; \
  61. }
  62. #define _ANKI_ENUM_UNARAY_OPERATOR(enumType, qualifier, regularOperator) \
  63. constexpr qualifier enumType operator regularOperator(const enumType a) \
  64. { \
  65. using EnumInt = std::underlying_type<enumType>::type; \
  66. return enumType(regularOperator EnumInt(a)); \
  67. }
  68. #define _ANKI_ENUM_INCREMENT_DECREMENT(enumType, qualifier) \
  69. qualifier enumType& operator++(enumType& a) \
  70. { \
  71. a = a + 1; \
  72. return a; \
  73. } \
  74. qualifier enumType& operator--(enumType& a) \
  75. { \
  76. a = a - 1; \
  77. return a; \
  78. } \
  79. qualifier enumType operator++(enumType& a, int) \
  80. { \
  81. const enumType old = a; \
  82. ++a; \
  83. return old; \
  84. } \
  85. qualifier enumType operator--(enumType& a, int) \
  86. { \
  87. const enumType old = a; \
  88. --a; \
  89. return old; \
  90. }
  91. #define _ANKI_ENUM_NEGATIVE_OPERATOR(enumType, qualifier) \
  92. constexpr qualifier Bool operator!(const enumType a) \
  93. { \
  94. using EnumInt = std::underlying_type<enumType>::type; \
  95. return EnumInt(a) == 0; \
  96. }
  97. #define _ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(enumType, qualifier) \
  98. _ANKI_ENUM_OPERATOR(enumType, qualifier, |, |=) \
  99. _ANKI_ENUM_OPERATOR(enumType, qualifier, &, &=) \
  100. _ANKI_ENUM_OPERATOR(enumType, qualifier, ^, ^=) \
  101. _ANKI_ENUM_OPERATOR(enumType, qualifier, +, +=) \
  102. _ANKI_ENUM_OPERATOR(enumType, qualifier, -, -=) \
  103. _ANKI_ENUM_OPERATOR(enumType, qualifier, *, *=) \
  104. _ANKI_ENUM_OPERATOR(enumType, qualifier, /, /=) \
  105. _ANKI_ENUM_OPERATOR(enumType, qualifier, <<, <<=) \
  106. _ANKI_ENUM_OPERATOR(enumType, qualifier, >>, >>=) \
  107. _ANKI_ENUM_UNARAY_OPERATOR(enumType, qualifier, ~) \
  108. _ANKI_ENUM_INCREMENT_DECREMENT(enumType, qualifier) \
  109. _ANKI_ENUM_NEGATIVE_OPERATOR(enumType, qualifier)
  110. /// @}
  111. /// @addtogroup util_other
  112. /// @{
  113. /// Implement all those functions that will make a stronly typed enum behave like the old type of enums.
  114. #define ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(enumType) _ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(enumType, inline)
  115. /// Same as ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS but for enums that are defined in a class.
  116. #define ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS_FRIEND(enumType) _ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(enumType, friend)
  117. /// @memberof EnumIterable
  118. template<typename TEnum>
  119. class EnumIterableIterator
  120. {
  121. public:
  122. using Type = typename std::underlying_type<TEnum>::type;
  123. constexpr EnumIterableIterator(TEnum val)
  124. : m_val(static_cast<Type>(val))
  125. {
  126. }
  127. TEnum operator*() const
  128. {
  129. return static_cast<TEnum>(m_val);
  130. }
  131. void operator++()
  132. {
  133. ++m_val;
  134. }
  135. bool operator!=(EnumIterableIterator b) const
  136. {
  137. return m_val != b.m_val;
  138. }
  139. private:
  140. Type m_val;
  141. };
  142. /// Allow an enum to be used in a for range loop.
  143. /// @code
  144. /// for(SomeEnum type : EnumIterable<SomeEnum>())
  145. /// {
  146. /// ...
  147. /// }
  148. /// @endcode
  149. template<typename TEnum>
  150. class EnumIterable
  151. {
  152. public:
  153. using Iterator = EnumIterableIterator<TEnum>;
  154. constexpr EnumIterable()
  155. : m_begin(TEnum::kFirst)
  156. , m_end(TEnum::kCount)
  157. {
  158. ANKI_ASSERT(m_begin <= m_end);
  159. }
  160. constexpr EnumIterable(TEnum begin, TEnum end)
  161. : m_begin(begin)
  162. , m_end(end)
  163. {
  164. ANKI_ASSERT(m_begin <= m_end);
  165. }
  166. Iterator begin() const
  167. {
  168. return Iterator(m_begin);
  169. }
  170. Iterator end() const
  171. {
  172. return Iterator(m_end);
  173. }
  174. public:
  175. TEnum m_begin;
  176. TEnum m_end;
  177. };
  178. /// @memberof EnumBitsIterable
  179. template<typename TEnum, typename TBitEnum>
  180. class EnumBitsIterableIterator
  181. {
  182. public:
  183. using Type = typename std::underlying_type<TBitEnum>::type;
  184. constexpr EnumBitsIterableIterator(TBitEnum val)
  185. : m_val(Type(val))
  186. {
  187. }
  188. TEnum operator*() const
  189. {
  190. ANKI_ASSERT(m_val);
  191. const TEnum out = TEnum(std::countr_zero(m_val));
  192. ANKI_ASSERT(out >= TEnum::kFirst && out < TEnum::kCount);
  193. return out;
  194. }
  195. void operator++()
  196. {
  197. ANKI_ASSERT(m_val);
  198. m_val ^= Type(1_U64 << std::countr_zero<U64>(m_val));
  199. }
  200. bool operator!=(EnumBitsIterableIterator b) const
  201. {
  202. return m_val != b.m_val;
  203. }
  204. private:
  205. Type m_val;
  206. };
  207. /// Allow a mask to be used in a for range loop of a compatible enum.
  208. /// @code
  209. /// for(SomeEnum type : EnumBitsIterable<SomeEnum, SomeCompatibleBitEnum>(bitmask))
  210. /// {
  211. /// ...
  212. /// }
  213. /// @endcode
  214. template<typename TEnum, typename TBitEnum>
  215. class EnumBitsIterable
  216. {
  217. public:
  218. using Iterator = EnumBitsIterableIterator<TEnum, TBitEnum>;
  219. constexpr EnumBitsIterable(TBitEnum bits)
  220. : m_bits(bits)
  221. {
  222. }
  223. Iterator begin() const
  224. {
  225. return Iterator(m_bits);
  226. }
  227. Iterator end() const
  228. {
  229. return Iterator(TBitEnum(0));
  230. }
  231. public:
  232. TBitEnum m_bits;
  233. };
  234. /// @}
  235. } // end namespace anki