123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- #pragma once
- #ifndef ENUM_INL_H_
- #error "Direct inclusion of this file is not allowed, include enum.h"
- // For the sake of sane code completion.
- #include "enum.h"
- #endif
- #include <util/string/printf.h>
- #include <util/string/cast.h>
- #include <util/generic/cast.h>
- #include <algorithm>
- #include <stdexcept>
- namespace NYT {
- ////////////////////////////////////////////////////////////////////////////////
- #define ENUM__CLASS(enumType, underlyingType, seq) \
- enum class enumType : underlyingType \
- { \
- PP_FOR_EACH(ENUM__DOMAIN_ITEM, seq) \
- };
- #define ENUM__DOMAIN_ITEM(item) \
- PP_IF( \
- PP_IS_SEQUENCE(item), \
- ENUM__DOMAIN_ITEM_SEQ, \
- ENUM__DOMAIN_ITEM_ATOMIC \
- )(item)()
- #define ENUM__DOMAIN_ITEM_ATOMIC(item) \
- item PP_COMMA
- #define ENUM__DOMAIN_ITEM_SEQ(seq) \
- PP_ELEMENT(seq, 0) = PP_ELEMENT(seq, 1) PP_COMMA
- ////////////////////////////////////////////////////////////////////////////////
- namespace NDetail {
- template <typename TValues>
- constexpr bool CheckValuesMonotonic(const TValues& values)
- {
- return std::adjacent_find(values.begin(), values.end(), std::greater_equal<>()) == values.end();
- }
- template <typename TValues>
- constexpr bool CheckValuesUnique(const TValues& values)
- {
- for (size_t i = 0; i < std::size(values); ++i) {
- for (size_t j = i + 1; j < std::size(values); ++j) {
- if (values[i] == values[j]) {
- return false;
- }
- }
- }
- return true;
- }
- template <typename TNames>
- constexpr bool CheckDomainNames(const TNames& names)
- {
- for (size_t i = 0; i < std::size(names); ++i) {
- if (std::size(names[i]) == 0) {
- return false;
- }
- for (size_t j = 1; j < std::size(names[i]); ++j) {
- // If name does not start with a capital letter, all the others must be in lowercase.
- if (('A' <= names[i][j] && names[i][j] <= 'Z') && ('A' > names[i][0] || names[i][0] > 'Z')) {
- return false;
- }
- }
- }
- return true;
- }
- } // namespace NDetail
- ////////////////////////////////////////////////////////////////////////////////
- #define ENUM__BEGIN_TRAITS(enumType, underlyingType, isBit, isStringSerializable, seq) \
- struct TEnumTraitsImpl_##enumType \
- { \
- using T = enumType; \
- \
- [[maybe_unused]] static constexpr bool IsBitEnum = isBit; \
- [[maybe_unused]] static constexpr bool IsStringSerializableEnum = isStringSerializable; \
- static constexpr int DomainSize = PP_COUNT(seq); \
- \
- static constexpr int GetDomainSize() \
- { \
- return DomainSize; \
- } \
- \
- static constexpr std::array<TStringBuf, DomainSize> Names{{ \
- PP_FOR_EACH(ENUM__GET_DOMAIN_NAMES_ITEM, seq) \
- }}; \
- static_assert(::NYT::NDetail::CheckDomainNames(Names), \
- "Enumeration " #enumType " contains names in wrong format"); \
- static constexpr std::array<T, DomainSize> Values{{ \
- PP_FOR_EACH(ENUM__GET_DOMAIN_VALUES_ITEM, seq) \
- }}; \
- \
- [[maybe_unused]] static constexpr bool IsMonotonic = \
- ::NYT::NDetail::CheckValuesMonotonic(Values); \
- \
- static TStringBuf GetTypeName() \
- { \
- static constexpr TStringBuf Result = PP_STRINGIZE(enumType); \
- return Result; \
- } \
- \
- static const std::optional<TStringBuf> FindLiteralByValue(T value) \
- { \
- for (int i = 0; i < GetDomainSize(); ++i) { \
- if (Values[i] == value) { \
- return Names[i]; \
- } \
- } \
- return std::nullopt; \
- } \
- \
- static std::optional<T> FindValueByLiteral(TStringBuf literal) \
- { \
- for (int i = 0; i < GetDomainSize(); ++i) { \
- if (Names[i] == literal) { \
- return Values[i]; \
- } \
- } \
- return std::nullopt; \
- } \
- \
- static constexpr const std::array<TStringBuf, DomainSize>& GetDomainNames() \
- { \
- return Names; \
- } \
- \
- static constexpr const std::array<T, DomainSize>& GetDomainValues() \
- { \
- return Values; \
- }
- #define ENUM__GET_DOMAIN_VALUES_ITEM(item) \
- PP_IF( \
- PP_IS_SEQUENCE(item), \
- ENUM__GET_DOMAIN_VALUES_ITEM_SEQ, \
- ENUM__GET_DOMAIN_VALUES_ITEM_ATOMIC \
- )(item)
- #define ENUM__GET_DOMAIN_VALUES_ITEM_SEQ(seq) \
- ENUM__GET_DOMAIN_VALUES_ITEM_ATOMIC(PP_ELEMENT(seq, 0))
- #define ENUM__GET_DOMAIN_VALUES_ITEM_ATOMIC(item) \
- T::item,
- #define ENUM__GET_DOMAIN_NAMES_ITEM(item) \
- PP_IF( \
- PP_IS_SEQUENCE(item), \
- ENUM__GET_DOMAIN_NAMES_ITEM_SEQ, \
- ENUM__GET_DOMAIN_NAMES_ITEM_ATOMIC \
- )(item)
- #define ENUM__GET_DOMAIN_NAMES_ITEM_SEQ(seq) \
- PP_IF( \
- ENUM__ITEM_SEQ_HAS_DOMAIN_NAME(seq), \
- ENUM__GET_DOMAIN_NAMES_ITEM_SEQ_CUSTOM, \
- ENUM__GET_DOMAIN_NAMES_ITEM_SEQ_AUTO \
- )(seq)
- #define ENUM__ITEM_SEQ_HAS_DOMAIN_NAME(seq) \
- PP_CONCAT(ENUM__ITEM_SEQ_HAS_DOMAIN_NAME_, PP_COUNT(seq))
- #define ENUM__ITEM_SEQ_HAS_DOMAIN_NAME_2 PP_FALSE
- #define ENUM__ITEM_SEQ_HAS_DOMAIN_NAME_3 PP_TRUE
- #define ENUM__GET_DOMAIN_NAMES_ITEM_SEQ_CUSTOM(seq) \
- TStringBuf(PP_ELEMENT(seq, 2)),
- #define ENUM__GET_DOMAIN_NAMES_ITEM_SEQ_AUTO(seq) \
- ENUM__GET_DOMAIN_NAMES_ITEM_ATOMIC(PP_ELEMENT(seq, 0))
- #define ENUM__GET_DOMAIN_NAMES_ITEM_ATOMIC(item) \
- TStringBuf(PP_STRINGIZE(item)),
- #define ENUM__VALIDATE_UNIQUE(enumType) \
- static_assert(IsMonotonic || ::NYT::NDetail::CheckValuesUnique(Values), \
- "Enumeration " #enumType " contains duplicate values");
- #define ENUM__END_TRAITS(enumType) \
- }; \
- \
- [[maybe_unused]] inline TEnumTraitsImpl_##enumType GetEnumTraitsImpl(enumType) \
- { \
- return {}; \
- } \
- \
- using ::ToString; \
- [[maybe_unused]] inline TString ToString(enumType value) \
- { \
- return ::NYT::TEnumTraits<enumType>::ToString(value); \
- }
- ////////////////////////////////////////////////////////////////////////////////
- template <class T>
- constexpr int TEnumTraitsWithKnownDomain<T, true>::GetDomainSize()
- {
- return TEnumTraitsImpl<T>::GetDomainSize();
- }
- template <class T>
- constexpr auto TEnumTraitsWithKnownDomain<T, true>::GetDomainNames() -> const std::array<TStringBuf, GetDomainSize()>&
- {
- return TEnumTraitsImpl<T>::GetDomainNames();
- }
- template <class T>
- constexpr auto TEnumTraitsWithKnownDomain<T, true>::GetDomainValues() -> const std::array<T, GetDomainSize()>&
- {
- return TEnumTraitsImpl<T>::GetDomainValues();
- }
- template <class T>
- constexpr T TEnumTraitsWithKnownDomain<T, true>::GetMinValue()
- requires (!TEnumTraitsImpl<T>::IsBitEnum)
- {
- const auto& values = GetDomainValues();
- static_assert(!values.empty()); \
- return *std::min_element(std::begin(values), std::end(values));
- }
- template <class T>
- constexpr T TEnumTraitsWithKnownDomain<T, true>::GetMaxValue()
- requires (!TEnumTraitsImpl<T>::IsBitEnum)
- {
- const auto& values = GetDomainValues();
- static_assert(!values.empty()); \
- return *std::max_element(std::begin(values), std::end(values));
- }
- template <class T>
- std::vector<T> TEnumTraitsWithKnownDomain<T, true>::Decompose(T value)
- requires (TEnumTraitsImpl<T>::IsBitEnum)
- {
- std::vector<T> result;
- for (auto domainValue : GetDomainValues()) {
- if (Any(value & domainValue)) {
- result.push_back(domainValue);
- }
- }
- return result;
- }
- ////////////////////////////////////////////////////////////////////////////////
- template <class T>
- TStringBuf TEnumTraits<T, true>::GetTypeName()
- {
- return TEnumTraitsImpl<T>::GetTypeName();
- }
- template <class T>
- std::optional<T> TEnumTraits<T, true>::FindValueByLiteral(TStringBuf literal)
- {
- return TEnumTraitsImpl<T>::FindValueByLiteral(literal);
- }
- template <class T>
- std::optional<TStringBuf> TEnumTraits<T, true>::FindLiteralByValue(T value)
- {
- return TEnumTraitsImpl<T>::FindLiteralByValue(value);
- }
- template <class T>
- TString TEnumTraits<T, true>::ToString(T value)
- {
- using ::ToString;
- if (auto optionalLiteral = TEnumTraits<T>::FindLiteralByValue(value)) {
- return ToString(*optionalLiteral);
- }
- TString result;
- result = TEnumTraits<T>::GetTypeName();
- result += "(";
- result += ToString(ToUnderlying(value));
- result += ")";
- return result;
- }
- template <class T>
- T TEnumTraits<T, true>::FromString(TStringBuf literal)
- {
- auto optionalValue = FindValueByLiteral(literal);
- if (!optionalValue) {
- throw ::NYT::TSimpleException(Sprintf("Error parsing %s value %s",
- GetTypeName().data(),
- TString(literal).Quote().c_str()).c_str());
- }
- return *optionalValue;
- }
- ////////////////////////////////////////////////////////////////////////////////
- #define ENUM__BINARY_BITWISE_OPERATOR(T, assignOp, op) \
- [[maybe_unused]] inline constexpr T operator op (T lhs, T rhs) \
- { \
- return T(ToUnderlying(lhs) op ToUnderlying(rhs)); \
- } \
- \
- [[maybe_unused]] inline T& operator assignOp (T& lhs, T rhs) \
- { \
- lhs = T(ToUnderlying(lhs) op ToUnderlying(rhs)); \
- return lhs; \
- }
- #define ENUM__UNARY_BITWISE_OPERATOR(T, op) \
- [[maybe_unused]] inline constexpr T operator op (T value) \
- { \
- return T(op ToUnderlying(value)); \
- }
- #define ENUM__BIT_SHIFT_OPERATOR(T, assignOp, op) \
- [[maybe_unused]] inline constexpr T operator op (T lhs, size_t rhs) \
- { \
- return T(ToUnderlying(lhs) op rhs); \
- } \
- \
- [[maybe_unused]] inline T& operator assignOp (T& lhs, size_t rhs) \
- { \
- lhs = T(ToUnderlying(lhs) op rhs); \
- return lhs; \
- }
- #define ENUM__BITWISE_OPS(enumType) \
- ENUM__BINARY_BITWISE_OPERATOR(enumType, &=, &) \
- ENUM__BINARY_BITWISE_OPERATOR(enumType, |=, | ) \
- ENUM__BINARY_BITWISE_OPERATOR(enumType, ^=, ^) \
- ENUM__UNARY_BITWISE_OPERATOR(enumType, ~) \
- ENUM__BIT_SHIFT_OPERATOR(enumType, <<=, << ) \
- ENUM__BIT_SHIFT_OPERATOR(enumType, >>=, >> )
- ////////////////////////////////////////////////////////////////////////////////
- template <typename E>
- requires TEnumTraits<E>::IsBitEnum
- constexpr bool Any(E value) noexcept
- {
- return ToUnderlying(value) != 0;
- }
- template <typename E>
- requires TEnumTraits<E>::IsBitEnum
- constexpr bool None(E value) noexcept
- {
- return ToUnderlying(value) == 0;
- }
- ////////////////////////////////////////////////////////////////////////////////
- } // namespace NYT
|