diff options
author | babenko <babenko@yandex-team.com> | 2023-03-14 09:33:31 +0300 |
---|---|---|
committer | babenko <babenko@yandex-team.com> | 2023-03-14 09:33:31 +0300 |
commit | e10767756146ca0d8e890326e20671aed5182e2b (patch) | |
tree | 0d15dded16242ddb4d7b64f5e1d21d425742234e /library/cpp/yt/misc | |
parent | 9aa65dc165f24925a281f89c975cc5117823934f (diff) | |
download | ydb-e10767756146ca0d8e890326e20671aed5182e2b.tar.gz |
YT-18571: Refactor YT enums to make them Arcadia-friendly
Diffstat (limited to 'library/cpp/yt/misc')
-rw-r--r-- | library/cpp/yt/misc/enum-inl.h | 261 | ||||
-rw-r--r-- | library/cpp/yt/misc/enum.h | 183 | ||||
-rw-r--r-- | library/cpp/yt/misc/unittests/enum_ut.cpp | 18 |
3 files changed, 246 insertions, 216 deletions
diff --git a/library/cpp/yt/misc/enum-inl.h b/library/cpp/yt/misc/enum-inl.h index 18a78621a9..ba33290e79 100644 --- a/library/cpp/yt/misc/enum-inl.h +++ b/library/cpp/yt/misc/enum-inl.h @@ -15,8 +15,8 @@ namespace NYT { //////////////////////////////////////////////////////////////////////////////// -#define ENUM__CLASS(name, underlyingType, seq) \ - enum class name : underlyingType \ +#define ENUM__CLASS(enumType, underlyingType, seq) \ + enum class enumType : underlyingType \ { \ PP_FOR_EACH(ENUM__DOMAIN_ITEM, seq) \ }; @@ -39,10 +39,27 @@ namespace NYT { namespace NDetail { template <typename TValues> -static constexpr bool AreValuesDistinct(const TValues& values) +constexpr bool CheckValuesMonotonic(const TValues& values) { - for (int i = 0; i < static_cast<int>(values.size()); ++i) { - for (int j = i + 1; j < static_cast<int>(values.size()); ++j) { + if (std::size(values) <= 1) { + return true; + } + for (size_t i = 0; i < std::size(values) - 1; ++i) { + if (values[i] > values[i + 1]) { + return false; + } + } + return true; +} + +template <typename TValues> +constexpr bool CheckValuesUnique(const TValues& values) +{ + if (CheckValuesMonotonic(values)) { + return true; + } + 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; } @@ -55,68 +72,61 @@ static constexpr bool AreValuesDistinct(const TValues& values) //////////////////////////////////////////////////////////////////////////////// -#define ENUM__BEGIN_TRAITS(name, underlyingType, isBit, isStringSerializable, seq) \ - struct TEnumTraitsImpl_##name \ +#define ENUM__BEGIN_TRAITS(enumType, underlyingType, isBit, isStringSerializable, seq) \ + struct TEnumTraitsImpl_##enumType \ { \ - using TType = name; \ - using TUnderlying = underlyingType; \ + using T = enumType; \ + \ [[maybe_unused]] static constexpr bool IsBitEnum = isBit; \ [[maybe_unused]] static constexpr bool IsStringSerializableEnum = isStringSerializable; \ - [[maybe_unused]] static constexpr int DomainSize = PP_COUNT(seq); \ + 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 constexpr std::array<TType, DomainSize> Values{{ \ + static constexpr std::array<T, DomainSize> Values{{ \ PP_FOR_EACH(ENUM__GET_DOMAIN_VALUES_ITEM, seq) \ }}; \ \ static TStringBuf GetTypeName() \ { \ - static constexpr TStringBuf typeName = PP_STRINGIZE(name); \ - return typeName; \ + static constexpr TStringBuf Result = PP_STRINGIZE(enumType); \ + return Result; \ } \ \ - static const TStringBuf* FindLiteralByValue(TType value) \ + static const std::optional<TStringBuf> FindLiteralByValue(T value) \ { \ - for (int i = 0; i < DomainSize; ++i) { \ + for (int i = 0; i < GetDomainSize(); ++i) { \ if (Values[i] == value) { \ - return &Names[i]; \ + return Names[i]; \ } \ } \ - return nullptr; \ + return std::nullopt; \ } \ \ - static bool FindValueByLiteral(TStringBuf literal, TType* result) \ + static std::optional<T> FindValueByLiteral(TStringBuf literal) \ { \ - for (int i = 0; i < DomainSize; ++i) { \ + for (int i = 0; i < GetDomainSize(); ++i) { \ if (Names[i] == literal) { \ - *result = Values[i]; \ - return true; \ + return Values[i]; \ } \ } \ - return false; \ + return std::nullopt; \ } \ \ - static const std::array<TStringBuf, DomainSize>& GetDomainNames() \ + static constexpr const std::array<TStringBuf, DomainSize>& GetDomainNames() \ { \ return Names; \ } \ \ - static const std::array<TType, DomainSize>& GetDomainValues() \ + static constexpr const std::array<T, DomainSize>& GetDomainValues() \ { \ return Values; \ - } \ - \ - static TType FromString(TStringBuf str) \ - { \ - TType value; \ - if (!FindValueByLiteral(str, &value)) { \ - throw ::NYT::TSimpleException(Sprintf("Error parsing %s value %s", \ - PP_STRINGIZE(name), \ - TString(str).Quote().c_str()).c_str()); \ - } \ - return value; \ } #define ENUM__GET_DOMAIN_VALUES_ITEM(item) \ @@ -130,7 +140,7 @@ static constexpr bool AreValuesDistinct(const TValues& values) ENUM__GET_DOMAIN_VALUES_ITEM_ATOMIC(PP_ELEMENT(seq, 0)) #define ENUM__GET_DOMAIN_VALUES_ITEM_ATOMIC(item) \ - TType::item, + T::item, #define ENUM__GET_DOMAIN_NAMES_ITEM(item) \ PP_IF( \ @@ -161,119 +171,120 @@ static constexpr bool AreValuesDistinct(const TValues& values) #define ENUM__GET_DOMAIN_NAMES_ITEM_ATOMIC(item) \ TStringBuf(PP_STRINGIZE(item)), -#define ENUM__DECOMPOSE \ - static std::vector<TType> Decompose(TType value) \ - { \ - std::vector<TType> result; \ - for (int i = 0; i < DomainSize; ++i) { \ - if (static_cast<TUnderlying>(value) & static_cast<TUnderlying>(Values[i])) { \ - result.push_back(Values[i]); \ - } \ - } \ - return result; \ - } +#define ENUM__VALIDATE_UNIQUE(enumType) \ + static_assert(::NYT::NDetail::CheckValuesUnique(Values), \ + "Enumeration " #enumType " contains duplicate values"); -#define ENUM__MINMAX \ - static constexpr TType GetMinValue() \ - { \ - static_assert(!Values.empty()); \ - return *std::min_element(std::begin(Values), std::end(Values)); \ - } \ - \ - static constexpr TType GetMaxValue() \ - { \ - static_assert(!Values.empty()); \ - return *std::max_element(std::begin(Values), std::end(Values)); \ - } - -#define ENUM__VALIDATE_UNIQUE(name) \ - static_assert(::NYT::NDetail::AreValuesDistinct(Values), \ - "Enumeration " #name " contains duplicate values"); - -#define ENUM__END_TRAITS(name) \ +#define ENUM__END_TRAITS(enumType) \ }; \ \ - [[maybe_unused]] inline TEnumTraitsImpl_##name GetEnumTraitsImpl(name) \ + [[maybe_unused]] inline TEnumTraitsImpl_##enumType GetEnumTraitsImpl(enumType) \ { \ - return TEnumTraitsImpl_##name(); \ + return {}; \ } \ \ using ::ToString; \ - [[maybe_unused]] inline TString ToString(name value) \ + [[maybe_unused]] inline TString ToString(enumType value) \ { \ - return ::NYT::TEnumTraits<name>::ToString(value); \ + return ::NYT::TEnumTraits<enumType>::ToString(value); \ } //////////////////////////////////////////////////////////////////////////////// template <class T> -std::vector<T> TEnumTraits<T, true>::Decompose(T value) +constexpr int TEnumTraitsWithKnownDomain<T, true>::GetDomainSize() { - return TImpl::Decompose(value); + return TEnumTraitsImpl<T>::GetDomainSize(); } template <class T> -T TEnumTraits<T, true>::FromString(TStringBuf str) +constexpr auto TEnumTraitsWithKnownDomain<T, true>::GetDomainNames() -> const std::array<TStringBuf, GetDomainSize()>& { - return TImpl::FromString(str); + return TEnumTraitsImpl<T>::GetDomainNames(); } template <class T> -TString TEnumTraits<T, true>::ToString(TType value) +constexpr auto TEnumTraitsWithKnownDomain<T, true>::GetDomainValues() -> const std::array<T, GetDomainSize()>& { - TString result; - const auto* literal = FindLiteralByValue(value); - if (literal) { - result = *literal; - } else { - result = GetTypeName(); - result += "("; - result += ::ToString(static_cast<TUnderlying>(value)); - result += ")"; - } - return result; + return TEnumTraitsImpl<T>::GetDomainValues(); } template <class T> -auto TEnumTraits<T, true>::GetDomainValues() -> const std::array<T, DomainSize>& +constexpr T TEnumTraitsWithKnownDomain<T, true>::GetMinValue() + requires (!TEnumTraitsImpl<T>::IsBitEnum) { - return TImpl::GetDomainValues(); + const auto& values = GetDomainValues(); + static_assert(!values.empty()); \ + return *std::min_element(std::begin(values), std::end(values)); } template <class T> -auto TEnumTraits<T, true>::GetDomainNames() -> const std::array<TStringBuf, DomainSize>& +constexpr T TEnumTraitsWithKnownDomain<T, true>::GetMaxValue() + requires (!TEnumTraitsImpl<T>::IsBitEnum) { - return TImpl::GetDomainNames(); + 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> -constexpr T TEnumTraits<T, true>::GetMaxValue() +TStringBuf TEnumTraits<T, true>::GetTypeName() { - return TImpl::GetMaxValue(); + return TEnumTraitsImpl<T>::GetTypeName(); } template <class T> -constexpr T TEnumTraits<T, true>::GetMinValue() +std::optional<T> TEnumTraits<T, true>::FindValueByLiteral(TStringBuf literal) { - return TImpl::GetMinValue(); + return TEnumTraitsImpl<T>::FindValueByLiteral(literal); } template <class T> -bool TEnumTraits<T, true>::FindValueByLiteral(TStringBuf literal, TType* result) +std::optional<TStringBuf> TEnumTraits<T, true>::FindLiteralByValue(T value) { - return TImpl::FindValueByLiteral(literal, result); + return TEnumTraitsImpl<T>::FindLiteralByValue(value); } template <class T> -const TStringBuf* TEnumTraits<T, true>::FindLiteralByValue(TType value) +TString TEnumTraits<T, true>::ToString(T value) { - return TImpl::FindLiteralByValue(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> -TStringBuf TEnumTraits<T, true>::GetTypeName() +T TEnumTraits<T, true>::FromString(TStringBuf literal) { - return TImpl::GetTypeName(); + 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; } //////////////////////////////////////////////////////////////////////////////// @@ -298,7 +309,7 @@ template <class E, class T, E Min, E Max> T& TEnumIndexedVector<E, T, Min, Max>::operator[] (E index) { Y_ASSERT(index >= Min && index <= Max); - return Items_[static_cast<TUnderlying>(index) - static_cast<TUnderlying>(Min)]; + return Items_[ToUnderlying(index) - ToUnderlying(Min)]; } template <class E, class T, E Min, E Max> @@ -342,58 +353,62 @@ bool TEnumIndexedVector<E, T, Min, Max>::IsDomainValue(E value) #define ENUM__BINARY_BITWISE_OPERATOR(T, assignOp, op) \ [[maybe_unused]] inline constexpr T operator op (T lhs, T rhs) \ { \ - using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ - return T(static_cast<TUnderlying>(lhs) op static_cast<TUnderlying>(rhs)); \ + return T(ToUnderlying(lhs) op ToUnderlying(rhs)); \ } \ \ [[maybe_unused]] inline T& operator assignOp (T& lhs, T rhs) \ { \ - using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ - lhs = T(static_cast<TUnderlying>(lhs) op static_cast<TUnderlying>(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) \ { \ - using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ - return T(op static_cast<TUnderlying>(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) \ { \ - using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ - return T(static_cast<TUnderlying>(lhs) op rhs); \ + return T(ToUnderlying(lhs) op rhs); \ } \ \ [[maybe_unused]] inline T& operator assignOp (T& lhs, size_t rhs) \ { \ - using TUnderlying = typename TEnumTraits<T>::TUnderlying; \ - lhs = T(static_cast<TUnderlying>(lhs) op rhs); \ + lhs = T(ToUnderlying(lhs) op rhs); \ return lhs; \ } -#define ENUM__BITWISE_OPS(name) \ - ENUM__BINARY_BITWISE_OPERATOR(name, &=, &) \ - ENUM__BINARY_BITWISE_OPERATOR(name, |=, | ) \ - ENUM__BINARY_BITWISE_OPERATOR(name, ^=, ^) \ - ENUM__UNARY_BITWISE_OPERATOR(name, ~) \ - ENUM__BIT_SHIFT_OPERATOR(name, <<=, << ) \ - ENUM__BIT_SHIFT_OPERATOR(name, >>=, >> ) +#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, typename> -bool Any(E value) +template <typename E> + requires std::is_enum_v<E> +constexpr std::underlying_type_t<E> ToUnderlying(E value) noexcept +{ + return static_cast<std::underlying_type_t<E>>(value); +} + +template <typename E> + requires TEnumTraits<E>::IsBitEnum +constexpr bool Any(E value) noexcept { - return static_cast<typename TEnumTraits<E>::TUnderlying>(value) != 0; + return ToUnderlying(value) != 0; } -template <class E, typename> -bool None(E value) +template <typename E> + requires TEnumTraits<E>::IsBitEnum +constexpr bool None(E value) noexcept { - return static_cast<typename TEnumTraits<E>::TUnderlying>(value) == 0; + return ToUnderlying(value) == 0; } //////////////////////////////////////////////////////////////////////////////// diff --git a/library/cpp/yt/misc/enum.h b/library/cpp/yt/misc/enum.h index 1353900996..773e1ac4ed 100644 --- a/library/cpp/yt/misc/enum.h +++ b/library/cpp/yt/misc/enum.h @@ -4,9 +4,9 @@ #include <util/generic/strbuf.h> -#include <stdexcept> -#include <type_traits> #include <array> +#include <optional> +#include <type_traits> #include <vector> #include <library/cpp/yt/exception/exception.h> @@ -22,15 +22,33 @@ namespace NYT { * (unittests/enum_ut.cpp). */ -// Actual overload must be provided with defines DEFINE_ENUM_XXX (see below). +// The actual overload must be provided with DEFINE_ENUM* (see below). template <class T> void GetEnumTraitsImpl(T); +template <class T> +using TEnumTraitsImpl = decltype(GetEnumTraitsImpl(T())); + +template <class T> +constexpr bool IsEnumDomainSizeKnown() +{ + if constexpr(requires{ TEnumTraitsImpl<T>::DomainSize; }) { + return true; + } else { + return false; + } +} + template < class T, - bool = std::is_enum<T>::value && - !std::is_convertible<T, int>::value && - !std::is_same<void, decltype(GetEnumTraitsImpl(T()))>::value + bool = IsEnumDomainSizeKnown<T>() +> +struct TEnumTraitsWithKnownDomain +{ }; + +template < + class T, + bool = std::is_enum_v<T> && !std::is_same_v<TEnumTraitsImpl<T>, void> > struct TEnumTraits { @@ -40,124 +58,122 @@ struct TEnumTraits }; template <class T> -struct TEnumTraits<T, true> +struct TEnumTraitsWithKnownDomain<T, true> { - using TImpl = decltype(GetEnumTraitsImpl(T())); - using TType = T; - using TUnderlying = typename TImpl::TUnderlying; - - static constexpr bool IsEnum = true; - static constexpr bool IsBitEnum = TImpl::IsBitEnum; - static constexpr bool IsStringSerializableEnum = TImpl::IsStringSerializableEnum; + static constexpr int GetDomainSize(); - static constexpr int DomainSize = TImpl::DomainSize; + static constexpr const std::array<TStringBuf, GetDomainSize()>& GetDomainNames(); + static constexpr const std::array<T, GetDomainSize()>& GetDomainValues(); - static TStringBuf GetTypeName(); + // For non-bit enums only. + static constexpr T GetMinValue() + requires (!TEnumTraitsImpl<T>::IsBitEnum); + static constexpr T GetMaxValue() + requires (!TEnumTraitsImpl<T>::IsBitEnum); - static const TStringBuf* FindLiteralByValue(TType value); - static bool FindValueByLiteral(TStringBuf literal, TType* result); + // For bit enums only. + static std::vector<T> Decompose(T value) + requires (TEnumTraitsImpl<T>::IsBitEnum); +}; - static const std::array<TStringBuf, DomainSize>& GetDomainNames(); - static const std::array<TType, DomainSize>& GetDomainValues(); +template <class T> +struct TEnumTraits<T, true> + : public TEnumTraitsWithKnownDomain<T> +{ + static constexpr bool IsEnum = true; + static constexpr bool IsBitEnum = TEnumTraitsImpl<T>::IsBitEnum; + static constexpr bool IsStringSerializableEnum = TEnumTraitsImpl<T>::IsStringSerializableEnum; - static TType FromString(TStringBuf str); - static TString ToString(TType value); + static TStringBuf GetTypeName(); - // For non-bit enums only. - static constexpr TType GetMinValue(); - static constexpr TType GetMaxValue(); + static std::optional<TStringBuf> FindLiteralByValue(T value); + static std::optional<T> FindValueByLiteral(TStringBuf literal); - // For bit enums only. - static std::vector<TType> Decompose(TType value); + static TString ToString(T value); + static T FromString(TStringBuf literal); }; //////////////////////////////////////////////////////////////////////////////// //! Defines a smart enumeration with a specific underlying type. /*! - * \param name Enumeration name. + * \param enumType Enumeration enumType. * \param seq Enumeration domain encoded as a <em>sequence</em>. * \param underlyingType Underlying type. */ -#define DEFINE_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \ - ENUM__CLASS(name, underlyingType, seq) \ - ENUM__BEGIN_TRAITS(name, underlyingType, false, false, seq) \ - ENUM__MINMAX \ - ENUM__VALIDATE_UNIQUE(name) \ - ENUM__END_TRAITS(name) +#define DEFINE_ENUM_WITH_UNDERLYING_TYPE(enumType, underlyingType, seq) \ + ENUM__CLASS(enumType, underlyingType, seq) \ + ENUM__BEGIN_TRAITS(enumType, underlyingType, false, false, seq) \ + ENUM__VALIDATE_UNIQUE(enumType) \ + ENUM__END_TRAITS(enumType) //! Defines a smart enumeration with a specific underlying type. //! Duplicate enumeration values are allowed. -#define DEFINE_AMBIGUOUS_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \ - ENUM__CLASS(name, underlyingType, seq) \ - ENUM__BEGIN_TRAITS(name, underlyingType, false, false, seq) \ - ENUM__MINMAX \ - ENUM__END_TRAITS(name) +#define DEFINE_AMBIGUOUS_ENUM_WITH_UNDERLYING_TYPE(enumType, underlyingType, seq) \ + ENUM__CLASS(enumType, underlyingType, seq) \ + ENUM__BEGIN_TRAITS(enumType, underlyingType, false, false, seq) \ + ENUM__END_TRAITS(enumType) //! Defines a smart enumeration with the default |int| underlying type. -#define DEFINE_ENUM(name, seq) \ - DEFINE_ENUM_WITH_UNDERLYING_TYPE(name, int, seq) +#define DEFINE_ENUM(enumType, seq) \ + DEFINE_ENUM_WITH_UNDERLYING_TYPE(enumType, int, seq) //! Defines a smart enumeration with a specific underlying type. /*! - * \param name Enumeration name. + * \param enumType Enumeration enumType. * \param seq Enumeration domain encoded as a <em>sequence</em>. * \param underlyingType Underlying type. */ -#define DEFINE_BIT_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \ - ENUM__CLASS(name, underlyingType, seq) \ - ENUM__BEGIN_TRAITS(name, underlyingType, true, false, seq) \ - ENUM__DECOMPOSE \ - ENUM__VALIDATE_UNIQUE(name) \ - ENUM__END_TRAITS(name) \ - ENUM__BITWISE_OPS(name) +#define DEFINE_BIT_ENUM_WITH_UNDERLYING_TYPE(enumType, underlyingType, seq) \ + ENUM__CLASS(enumType, underlyingType, seq) \ + ENUM__BEGIN_TRAITS(enumType, underlyingType, true, false, seq) \ + ENUM__VALIDATE_UNIQUE(enumType) \ + ENUM__END_TRAITS(enumType) \ + ENUM__BITWISE_OPS(enumType) //! Defines a smart enumeration with a specific underlying type. //! Duplicate enumeration values are allowed. /*! - * \param name Enumeration name. + * \param enumType Enumeration enumType. * \param seq Enumeration domain encoded as a <em>sequence</em>. * \param underlyingType Underlying type. */ -#define DEFINE_AMBIGUOUS_BIT_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \ - ENUM__CLASS(name, underlyingType, seq) \ - ENUM__BEGIN_TRAITS(name, underlyingType, true, false, seq) \ - ENUM__DECOMPOSE \ - ENUM__END_TRAITS(name) \ - ENUM__BITWISE_OPS(name) - -//! Defines a smart enumeration with the default |unsigned| underlying type. +#define DEFINE_AMBIGUOUS_BIT_ENUM_WITH_UNDERLYING_TYPE(enumType, underlyingType, seq) \ + ENUM__CLASS(enumType, underlyingType, seq) \ + ENUM__BEGIN_TRAITS(enumType, underlyingType, true, false, seq) \ + ENUM__END_TRAITS(enumType) \ + ENUM__BITWISE_OPS(enumType) + +//! Defines a smart enumeration with the default |unsigned int| underlying type. /*! - * \param name Enumeration name. + * \param enumType Enumeration enumType. * \param seq Enumeration domain encoded as a <em>sequence</em>. */ -#define DEFINE_BIT_ENUM(name, seq) \ - DEFINE_BIT_ENUM_WITH_UNDERLYING_TYPE(name, unsigned, seq) +#define DEFINE_BIT_ENUM(enumType, seq) \ + DEFINE_BIT_ENUM_WITH_UNDERLYING_TYPE(enumType, unsigned int, seq) //! Defines a smart enumeration with a specific underlying type and IsStringSerializable attribute. /*! - * \param name Enumeration name. + * \param enumType Enumeration enumType. * \param seq Enumeration domain encoded as a <em>sequence</em>. * \param underlyingType Underlying type. */ -#define DEFINE_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \ - ENUM__CLASS(name, underlyingType, seq) \ - ENUM__BEGIN_TRAITS(name, underlyingType, false, true, seq) \ - ENUM__MINMAX \ - ENUM__VALIDATE_UNIQUE(name) \ - ENUM__END_TRAITS(name) \ +#define DEFINE_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(enumType, underlyingType, seq) \ + ENUM__CLASS(enumType, underlyingType, seq) \ + ENUM__BEGIN_TRAITS(enumType, underlyingType, false, true, seq) \ + ENUM__VALIDATE_UNIQUE(enumType) \ + ENUM__END_TRAITS(enumType) \ //! Defines a smart enumeration with a specific underlying type and IsStringSerializable attribute. //! Duplicate enumeration values are allowed. -#define DEFINE_AMBIGUOUS_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \ - ENUM__CLASS(name, underlyingType, seq) \ - ENUM__BEGIN_TRAITS(name, underlyingType, false, true, seq) \ - ENUM__MINMAX \ - ENUM__END_TRAITS(name) +#define DEFINE_AMBIGUOUS_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(enumType, underlyingType, seq) \ + ENUM__CLASS(enumType, underlyingType, seq) \ + ENUM__BEGIN_TRAITS(enumType, underlyingType, false, true, seq) \ + ENUM__END_TRAITS(enumType) //! Defines a smart enumeration with the default |int| underlying type and IsStringSerializable attribute. -#define DEFINE_STRING_SERIALIZABLE_ENUM(name, seq) \ - DEFINE_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(name, int, seq) +#define DEFINE_STRING_SERIALIZABLE_ENUM(enumType, seq) \ + DEFINE_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(enumType, int, seq) //////////////////////////////////////////////////////////////////////////////// @@ -199,20 +215,27 @@ public: static bool IsDomainValue(E value); private: - using TUnderlying = typename TEnumTraits<E>::TUnderlying; + using TUnderlying = std::underlying_type_t<E>; static constexpr int N = static_cast<TUnderlying>(Max) - static_cast<TUnderlying>(Min) + 1; std::array<T, N> Items_; }; //////////////////////////////////////////////////////////////////////////////// +//! Replace with |std::to_underlying| in C++23. +template <typename E> + requires std::is_enum_v<E> +constexpr std::underlying_type_t<E> ToUnderlying(E value) noexcept; + //! Returns |true| iff the enumeration value is not bitwise zero. -template <typename E, typename = std::enable_if_t<NYT::TEnumTraits<E>::IsBitEnum, E>> -bool Any(E value); +template <typename E> + requires TEnumTraits<E>::IsBitEnum +constexpr bool Any(E value) noexcept; //! Returns |true| iff the enumeration value is bitwise zero. -template <typename E, typename = std::enable_if_t<NYT::TEnumTraits<E>::IsBitEnum, E>> -bool None(E value); +template <typename E> + requires TEnumTraits<E>::IsBitEnum +constexpr bool None(E value) noexcept; //////////////////////////////////////////////////////////////////////////////// diff --git a/library/cpp/yt/misc/unittests/enum_ut.cpp b/library/cpp/yt/misc/unittests/enum_ut.cpp index 2a024be228..1b1b6d0be2 100644 --- a/library/cpp/yt/misc/unittests/enum_ut.cpp +++ b/library/cpp/yt/misc/unittests/enum_ut.cpp @@ -52,7 +52,7 @@ std::vector<T> ToVector(std::array<T, N> array) TEST(TEnumTest, Domain) { - EXPECT_EQ(3, TEnumTraits<ESimple>::DomainSize); + EXPECT_EQ(3, TEnumTraits<ESimple>::GetDomainSize()); std::vector<ESimple> v { ESimple::X, ESimple::Y, @@ -101,16 +101,8 @@ TEST(TEnumTest, FromString) EXPECT_THROW(TEnumTraits<EColor>::FromString("Pink"), std::exception); - EColor color; - bool returnValue; - - returnValue = TEnumTraits<EColor>::FindValueByLiteral("Red", &color); - EXPECT_EQ(EColor::Red, color); - EXPECT_TRUE(returnValue); - - returnValue = TEnumTraits<EColor>::FindValueByLiteral("Pink", &color); - EXPECT_EQ(EColor::Red, color); - EXPECT_FALSE(returnValue); + EXPECT_EQ(EColor::Red, TEnumTraits<EColor>::FindValueByLiteral("Red")); + EXPECT_EQ(std::nullopt, TEnumTraits<EColor>::FindValueByLiteral("Pink")); } TEST(TEnumTest, Ordering) @@ -182,8 +174,8 @@ TEST(TEnumTest, OrderingWithDomainValues) TEST(TEnumTest, DomainSize) { - EXPECT_EQ(3, TEnumTraits<ESimple>::DomainSize); - EXPECT_EQ(5, TEnumTraits<EColor>::DomainSize); + EXPECT_EQ(3, TEnumTraits<ESimple>::GetDomainSize()); + EXPECT_EQ(5, TEnumTraits<EColor>::GetDomainSize()); } TEST(TEnumTest, DomainValues) |