Enum.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // Copyright (C) 2009-2021, 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. namespace anki {
  8. /// @privatesection
  9. /// @{
  10. /// This is a template where the Type will be I64 if the T is any unsigned integer and U64 otherwise
  11. template<typename T, bool = std::is_unsigned<T>::value>
  12. class EnumSafeIntegerType
  13. {
  14. public:
  15. using Type = I64;
  16. };
  17. template<typename T>
  18. class EnumSafeIntegerType<T, true>
  19. {
  20. public:
  21. using Type = U64;
  22. };
  23. /// This macro will do an operation between 2 values. It will be used in constexpr functions. There is also an assertion
  24. /// which makes sure that the result will fit in an enum. Despite the fact that the assertion contains non-constexpr
  25. /// elements it will work on constexpr expressions. The compiler will compile-time ignore the non-constexpr part if the
  26. /// 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, \
  39. const std::underlying_type<enumType>::type b) \
  40. { \
  41. _ANKI_ENUM_OPERATION_BODY(enumType, regularOperator, a, b); \
  42. } \
  43. constexpr qualifier enumType operator regularOperator(const std::underlying_type<enumType>::type a, \
  44. const enumType b) \
  45. { \
  46. _ANKI_ENUM_OPERATION_BODY(enumType, regularOperator, a, b); \
  47. } \
  48. qualifier enumType& operator assignmentOperator(enumType& a, const enumType b) \
  49. { \
  50. a = a regularOperator b; \
  51. return a; \
  52. } \
  53. qualifier enumType& operator assignmentOperator(enumType& a, const std::underlying_type<enumType>::type b) \
  54. { \
  55. a = a regularOperator b; \
  56. return a; \
  57. } \
  58. qualifier std::underlying_type<enumType>::type& operator assignmentOperator( \
  59. std::underlying_type<enumType>::type& a, const enumType b) \
  60. { \
  61. using EnumInt = std::underlying_type<enumType>::type; \
  62. a = EnumInt(a regularOperator b); \
  63. return a; \
  64. }
  65. #define _ANKI_ENUM_UNARAY_OPERATOR(enumType, qualifier, regularOperator) \
  66. constexpr qualifier enumType operator regularOperator(const enumType a) \
  67. { \
  68. using EnumInt = std::underlying_type<enumType>::type; \
  69. return enumType(regularOperator EnumInt(a)); \
  70. }
  71. #define _ANKI_ENUM_INCREMENT_DECREMENT(enumType, qualifier) \
  72. qualifier enumType& operator++(enumType& a) \
  73. { \
  74. a = a + 1; \
  75. return a; \
  76. } \
  77. qualifier enumType& operator--(enumType& a) \
  78. { \
  79. a = a - 1; \
  80. return a; \
  81. } \
  82. qualifier enumType operator++(enumType& a, int) \
  83. { \
  84. const enumType old = a; \
  85. ++a; \
  86. return old; \
  87. } \
  88. qualifier enumType operator--(enumType& a, int) \
  89. { \
  90. const enumType old = a; \
  91. --a; \
  92. return old; \
  93. }
  94. #define _ANKI_ENUM_NEGATIVE_OPERATOR(enumType, qualifier) \
  95. constexpr qualifier Bool operator!(const enumType a) \
  96. { \
  97. using EnumInt = std::underlying_type<enumType>::type; \
  98. return EnumInt(a) == 0; \
  99. }
  100. #define _ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(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_OPERATOR(enumType, qualifier, /, /=) \
  108. _ANKI_ENUM_OPERATOR(enumType, qualifier, <<, <<=) \
  109. _ANKI_ENUM_OPERATOR(enumType, qualifier, >>, >>=) \
  110. _ANKI_ENUM_UNARAY_OPERATOR(enumType, qualifier, ~) \
  111. _ANKI_ENUM_INCREMENT_DECREMENT(enumType, qualifier) \
  112. _ANKI_ENUM_NEGATIVE_OPERATOR(enumType, qualifier)
  113. /// @}
  114. /// @addtogroup util_other
  115. /// @{
  116. /// Implement all those functions that will make a stronly typed enum behave like the old type of enums.
  117. #define ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(enumType) _ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(enumType, inline)
  118. /// Same as ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS but for enums that are defined in a class.
  119. #define ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS_FRIEND(enumType) _ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(enumType, friend)
  120. /// @memberof EnumIterable
  121. template<typename TEnum>
  122. class EnumIterableIterator
  123. {
  124. public:
  125. using Type = typename std::underlying_type<TEnum>::type;
  126. EnumIterableIterator(TEnum val)
  127. : m_val(static_cast<Type>(val))
  128. {
  129. }
  130. TEnum operator*() const
  131. {
  132. return static_cast<TEnum>(m_val);
  133. }
  134. void operator++()
  135. {
  136. ++m_val;
  137. }
  138. bool operator!=(EnumIterableIterator b) const
  139. {
  140. return m_val != b.m_val;
  141. }
  142. private:
  143. Type m_val;
  144. };
  145. /// Allow an enum to be used in a for range loop.
  146. /// @code
  147. /// for(SomeEnum type : EnumIterable<SomeEnum>())
  148. /// {
  149. /// ...
  150. /// }
  151. /// @endcode
  152. template<typename TEnum>
  153. class EnumIterable
  154. {
  155. public:
  156. using Iterator = EnumIterableIterator<TEnum>;
  157. static Iterator begin()
  158. {
  159. return Iterator(TEnum::FIRST);
  160. }
  161. static Iterator end()
  162. {
  163. return Iterator(TEnum::COUNT);
  164. }
  165. };
  166. /// @}
  167. } // end namespace anki