enum.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. #pragma once
  2. #include "preprocessor.h"
  3. #include <util/generic/strbuf.h>
  4. #include <array>
  5. #include <optional>
  6. #include <type_traits>
  7. #include <vector>
  8. #include <library/cpp/yt/exception/exception.h>
  9. namespace NYT {
  10. ////////////////////////////////////////////////////////////////////////////////
  11. /*
  12. * Smart enumerations augment C++ enum classes with a bunch of reflection
  13. * capabilities accessible via TEnumTraits class specialization.
  14. *
  15. * Please refer to the unit test for an actual example of usage
  16. * (unittests/enum_ut.cpp).
  17. */
  18. // The actual overload must be provided with DEFINE_ENUM* (see below).
  19. template <class T>
  20. void GetEnumTraitsImpl(T);
  21. template <class T, class S>
  22. constexpr bool CanFitSubtype();
  23. template <class T>
  24. using TEnumTraitsImpl = decltype(GetEnumTraitsImpl(T()));
  25. template <class T>
  26. constexpr std::optional<T> TryGetEnumUnknownValueImpl(T);
  27. template <
  28. class T,
  29. bool DomainSizeKnown = requires{ TEnumTraitsImpl<T>::DomainSize; }
  30. >
  31. struct TEnumTraitsWithKnownDomain
  32. { };
  33. template <
  34. class T,
  35. bool = std::is_enum_v<T> && !std::is_same_v<TEnumTraitsImpl<T>, void>
  36. >
  37. struct TEnumTraits
  38. {
  39. static constexpr bool IsEnum = false;
  40. static constexpr bool IsBitEnum = false;
  41. static constexpr bool IsStringSerializableEnum = false;
  42. static constexpr bool IsMonotonic = false;
  43. };
  44. template <class T>
  45. struct TEnumTraitsWithKnownDomain<T, /*DomainSizeKnown*/ true>
  46. {
  47. static constexpr int GetDomainSize();
  48. static constexpr const std::array<TStringBuf, GetDomainSize()>& GetDomainNames();
  49. static constexpr const std::array<T, GetDomainSize()>& GetDomainValues();
  50. // For non-bit enums only.
  51. static constexpr T GetMinValue()
  52. requires (!TEnumTraitsImpl<T>::IsBitEnum);
  53. static constexpr T GetMaxValue()
  54. requires (!TEnumTraitsImpl<T>::IsBitEnum);
  55. // For bit enums only.
  56. static constexpr T GetAllSetValue()
  57. requires (TEnumTraitsImpl<T>::IsBitEnum);
  58. static std::vector<T> Decompose(T value)
  59. requires (TEnumTraitsImpl<T>::IsBitEnum);
  60. };
  61. template <class T>
  62. struct TEnumTraits<T, true>
  63. : public TEnumTraitsWithKnownDomain<T>
  64. {
  65. static constexpr bool IsEnum = true;
  66. static constexpr bool IsBitEnum = TEnumTraitsImpl<T>::IsBitEnum;
  67. static constexpr bool IsStringSerializableEnum = TEnumTraitsImpl<T>::IsStringSerializableEnum;
  68. static constexpr bool IsMonotonic = TEnumTraitsImpl<T>::IsMonotonic;
  69. static TStringBuf GetTypeName();
  70. static constexpr std::optional<T> TryGetUnknownValue();
  71. static std::optional<TStringBuf> FindLiteralByValue(T value);
  72. static std::optional<T> FindValueByLiteral(TStringBuf literal);
  73. static constexpr bool IsKnownValue(T value)
  74. requires (!TEnumTraitsImpl<T>::IsBitEnum);
  75. static constexpr bool IsValidValue(T value);
  76. static TString ToString(T value);
  77. static T FromString(TStringBuf literal);
  78. };
  79. ////////////////////////////////////////////////////////////////////////////////
  80. //! Defines a smart enumeration with a specific underlying type.
  81. /*!
  82. * \param enumType Enumeration type.
  83. * \param seq Enumeration domain encoded as a <em>sequence</em>.
  84. * \param underlyingType Underlying type.
  85. */
  86. #define DEFINE_ENUM_WITH_UNDERLYING_TYPE(enumType, underlyingType, seq) \
  87. ENUM__CLASS(enumType, underlyingType, seq) \
  88. ENUM__BEGIN_TRAITS(enumType, underlyingType, false, false, seq) \
  89. ENUM__VALIDATE_UNIQUE(enumType) \
  90. ENUM__END_TRAITS(enumType) \
  91. static_assert(true)
  92. //! Defines a smart enumeration with a specific underlying type.
  93. //! Duplicate enumeration values are allowed.
  94. #define DEFINE_AMBIGUOUS_ENUM_WITH_UNDERLYING_TYPE(enumType, underlyingType, seq) \
  95. ENUM__CLASS(enumType, underlyingType, seq) \
  96. ENUM__BEGIN_TRAITS(enumType, underlyingType, false, false, seq) \
  97. ENUM__END_TRAITS(enumType) \
  98. static_assert(true)
  99. //! Defines a smart enumeration with the default |int| underlying type.
  100. #define DEFINE_ENUM(enumType, seq) \
  101. DEFINE_ENUM_WITH_UNDERLYING_TYPE(enumType, int, seq)
  102. //! Defines a smart enumeration with a specific underlying type.
  103. /*!
  104. * \param enumType Enumeration type.
  105. * \param seq Enumeration domain encoded as a <em>sequence</em>.
  106. * \param underlyingType Underlying type.
  107. */
  108. #define DEFINE_BIT_ENUM_WITH_UNDERLYING_TYPE(enumType, underlyingType, seq) \
  109. ENUM__CLASS(enumType, underlyingType, seq) \
  110. ENUM__BITWISE_OPS(enumType) \
  111. ENUM__BEGIN_TRAITS(enumType, underlyingType, true, false, seq) \
  112. ENUM__VALIDATE_UNIQUE(enumType) \
  113. ENUM__ALL_SET_VALUE(enumType, seq) \
  114. ENUM__END_TRAITS(enumType) \
  115. static_assert(true)
  116. //! Defines a smart enumeration with a specific underlying type.
  117. //! Duplicate enumeration values are allowed.
  118. /*!
  119. * \param enumType Enumeration type.
  120. * \param seq Enumeration domain encoded as a <em>sequence</em>.
  121. * \param underlyingType Underlying type.
  122. */
  123. #define DEFINE_AMBIGUOUS_BIT_ENUM_WITH_UNDERLYING_TYPE(enumType, underlyingType, seq) \
  124. ENUM__CLASS(enumType, underlyingType, seq) \
  125. ENUM__BITWISE_OPS(enumType) \
  126. ENUM__BEGIN_TRAITS(enumType, underlyingType, true, false, seq) \
  127. ENUM__ALL_SET_VALUE(enumType, seq) \
  128. ENUM__END_TRAITS(enumType) \
  129. static_assert(true)
  130. //! Defines a smart enumeration with the default |unsigned int| underlying type.
  131. /*!
  132. * \param enumType Enumeration type.
  133. * \param seq Enumeration domain encoded as a <em>sequence</em>.
  134. */
  135. #define DEFINE_BIT_ENUM(enumType, seq) \
  136. DEFINE_BIT_ENUM_WITH_UNDERLYING_TYPE(enumType, unsigned int, seq)
  137. //! Defines a smart enumeration with a specific underlying type and IsStringSerializable attribute.
  138. /*!
  139. * \param enumType Enumeration type.
  140. * \param seq Enumeration domain encoded as a <em>sequence</em>.
  141. * \param underlyingType Underlying type.
  142. */
  143. #define DEFINE_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(enumType, underlyingType, seq) \
  144. ENUM__CLASS(enumType, underlyingType, seq) \
  145. ENUM__BEGIN_TRAITS(enumType, underlyingType, false, true, seq) \
  146. ENUM__VALIDATE_UNIQUE(enumType) \
  147. ENUM__END_TRAITS(enumType) \
  148. static_assert(true)
  149. //! Defines a smart enumeration with a specific underlying type and IsStringSerializable attribute.
  150. //! Duplicate enumeration values are allowed.
  151. #define DEFINE_AMBIGUOUS_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(enumType, underlyingType, seq) \
  152. ENUM__CLASS(enumType, underlyingType, seq) \
  153. ENUM__BEGIN_TRAITS(enumType, underlyingType, false, true, seq) \
  154. ENUM__END_TRAITS(enumType) \
  155. static_assert(true)
  156. //! Defines a smart enumeration with the default |int| underlying type and IsStringSerializable attribute.
  157. #define DEFINE_STRING_SERIALIZABLE_ENUM(enumType, seq) \
  158. DEFINE_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(enumType, int, seq)
  159. //! When enum from another representation (e.g. string or protobuf integer),
  160. //! instructs the parser to treat undeclared values as |unknownValue|.
  161. /*!
  162. * \param enumType Enumeration type.
  163. * \param unknownValue A sentinel value of #enumType.
  164. */
  165. #define DEFINE_ENUM_UNKNOWN_VALUE(enumType, unknownValue) \
  166. [[maybe_unused]] constexpr std::optional<enumType> TryGetEnumUnknownValueImpl(enumType) \
  167. { \
  168. return enumType::unknownValue; \
  169. }
  170. ////////////////////////////////////////////////////////////////////////////////
  171. //! Returns |true| iff the enumeration value is not bitwise zero.
  172. template <typename E>
  173. requires TEnumTraits<E>::IsBitEnum
  174. constexpr bool Any(E value) noexcept;
  175. //! Returns |true| iff the enumeration value is bitwise zero.
  176. template <typename E>
  177. requires TEnumTraits<E>::IsBitEnum
  178. constexpr bool None(E value) noexcept;
  179. ////////////////////////////////////////////////////////////////////////////////
  180. } // namespace NYT
  181. #define ENUM_INL_H_
  182. #include "enum-inl.h"
  183. #undef ENUM_INL_H_