aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbabenko <babenko@yandex-team.com>2023-03-14 09:33:31 +0300
committerbabenko <babenko@yandex-team.com>2023-03-14 09:33:31 +0300
commite10767756146ca0d8e890326e20671aed5182e2b (patch)
tree0d15dded16242ddb4d7b64f5e1d21d425742234e
parent9aa65dc165f24925a281f89c975cc5117823934f (diff)
downloadydb-e10767756146ca0d8e890326e20671aed5182e2b.tar.gz
YT-18571: Refactor YT enums to make them Arcadia-friendly
-rw-r--r--library/cpp/yt/misc/enum-inl.h261
-rw-r--r--library/cpp/yt/misc/enum.h183
-rw-r--r--library/cpp/yt/misc/unittests/enum_ut.cpp18
-rw-r--r--library/cpp/yt/string/enum-inl.h25
-rw-r--r--library/cpp/yt/string/enum.h5
5 files changed, 258 insertions, 234 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)
diff --git a/library/cpp/yt/string/enum-inl.h b/library/cpp/yt/string/enum-inl.h
index 7ce7d2a350..7e6785efb4 100644
--- a/library/cpp/yt/string/enum-inl.h
+++ b/library/cpp/yt/string/enum-inl.h
@@ -27,14 +27,8 @@ void FormatUnknownEnumValue(
template <class T>
std::optional<T> TryParseEnum(TStringBuf value)
{
- static_assert(TEnumTraits<T>::IsEnum);
-
auto tryFromString = [] (TStringBuf value) -> std::optional<T> {
- T result;
- if (auto ok = TEnumTraits<T>::FindValueByLiteral(DecodeEnumValue(value), &result)) {
- return result;
- }
- return {};
+ return TEnumTraits<T>::FindValueByLiteral(DecodeEnumValue(value));
};
if constexpr (TEnumTraits<T>::IsBitEnum) {
@@ -65,28 +59,25 @@ T ParseEnum(TStringBuf value)
template <class T>
void FormatEnum(TStringBuilderBase* builder, T value, bool lowerCase)
{
- static_assert(TEnumTraits<T>::IsEnum);
-
auto formatScalarValue = [builder, lowerCase] (T value) {
- auto* literal = TEnumTraits<T>::FindLiteralByValue(value);
- if (!literal) {
- YT_VERIFY(!TEnumTraits<T>::IsBitEnum);
+ auto optionalLiteral = TEnumTraits<T>::FindLiteralByValue(value);
+ if (!optionalLiteral) {
NYT::NDetail::FormatUnknownEnumValue(
builder,
TEnumTraits<T>::GetTypeName(),
- static_cast<typename TEnumTraits<T>::TUnderlying>(value));
+ ToUnderlying(value));
return;
}
if (lowerCase) {
- CamelCaseToUnderscoreCase(builder, *literal);
+ CamelCaseToUnderscoreCase(builder, *optionalLiteral);
} else {
- builder->AppendString(*literal);
+ builder->AppendString(*optionalLiteral);
}
};
if constexpr (TEnumTraits<T>::IsBitEnum) {
- if (auto* literal = TEnumTraits<T>::FindLiteralByValue(value)) {
+ if (TEnumTraits<T>::FindLiteralByValue(value)) {
formatScalarValue(value);
return;
}
@@ -106,7 +97,7 @@ void FormatEnum(TStringBuilderBase* builder, T value, bool lowerCase)
}
template <class T>
-TString FormatEnum(T value, typename TEnumTraits<T>::TType*)
+TString FormatEnum(T value)
{
TStringBuilder builder;
FormatEnum(&builder, value, /*lowerCase*/ true);
diff --git a/library/cpp/yt/string/enum.h b/library/cpp/yt/string/enum.h
index 10dc02610f..caad6f2064 100644
--- a/library/cpp/yt/string/enum.h
+++ b/library/cpp/yt/string/enum.h
@@ -14,13 +14,16 @@ TString DecodeEnumValue(TStringBuf value);
TString EncodeEnumValue(TStringBuf value);
template <class T>
+std::optional<T> TryParseEnum(TStringBuf value);
+
+template <class T>
T ParseEnum(TStringBuf value);
template <class T>
void FormatEnum(TStringBuilderBase* builder, T value, bool lowerCase);
template <class T>
-TString FormatEnum(T value, typename TEnumTraits<T>::TType* = nullptr);
+TString FormatEnum(T value);
////////////////////////////////////////////////////////////////////////////////