diff options
author | babenko <babenko@yandex-team.com> | 2024-10-26 23:13:30 +0300 |
---|---|---|
committer | babenko <babenko@yandex-team.com> | 2024-10-26 23:30:14 +0300 |
commit | 41d598c624442bf6918407466dac3316b8277347 (patch) | |
tree | 5895b8823d4f887e1e5ab4f99cbac991dca5ca17 /library/cpp/yt/string/enum-inl.h | |
parent | ddabd4ddff87ac13bfc87ef02af352216a0f4e13 (diff) | |
download | ydb-41d598c624442bf6918407466dac3316b8277347.tar.gz |
YT-22885: DEFINE_ENUM_UNKNOWN_VALUE, string-related conversions
commit_hash:14c7e42422af750383f04855b4a7ea6b267b92d2
Diffstat (limited to 'library/cpp/yt/string/enum-inl.h')
-rw-r--r-- | library/cpp/yt/string/enum-inl.h | 112 |
1 files changed, 55 insertions, 57 deletions
diff --git a/library/cpp/yt/string/enum-inl.h b/library/cpp/yt/string/enum-inl.h index 41f7197d15..84b0941d15 100644 --- a/library/cpp/yt/string/enum-inl.h +++ b/library/cpp/yt/string/enum-inl.h @@ -5,6 +5,8 @@ #endif #include "format.h" +#include "string.h" +#include "string_builder.h" #include <library/cpp/yt/exception/exception.h> @@ -23,110 +25,106 @@ void ThrowMalformedEnumValueException( TStringBuf value); void FormatUnknownEnumValue( - TStringBuilderBase* builder, + auto* builder, TStringBuf name, - i64 value); + auto value) +{ + builder->AppendFormat("%v::unknown-%v", name, ToUnderlying(value)); +} } // namespace NDetail template <class T> -std::optional<T> TryParseEnum(TStringBuf value) +std::optional<T> TryParseEnum(TStringBuf str, bool enableUnknown) { - auto tryFromString = [] (TStringBuf value) -> std::optional<T> { - if (auto decodedValue = TryDecodeEnumValue(value)) { - auto enumValue = TEnumTraits<T>::FindValueByLiteral(*decodedValue); - return enumValue ? enumValue : TEnumTraits<T>::FindValueByLiteral(value); - } + auto tryParseToken = [&] (TStringBuf token) -> std::optional<T> { + if (auto optionalValue = TEnumTraits<T>::FindValueByLiteral(token)) { + return *optionalValue; - auto reportError = [value] () { - throw TSimpleException(Format("Enum value %Qv is neither in a proper underscore case nor in a format \"%v(123)\"", - value, - TEnumTraits<T>::GetTypeName())); - }; - - TStringBuf typeName; - auto isTypeNameCorrect = value.NextTok('(', typeName) && typeName == TEnumTraits<T>::GetTypeName(); - if (!isTypeNameCorrect) { - reportError(); } - TStringBuf enumValue; - std::underlying_type_t<T> underlyingValue = 0; - auto isEnumValueCorrect = value.NextTok(')', enumValue) && TryFromString(enumValue, underlyingValue); - if (!isEnumValueCorrect) { - reportError(); + if (auto optionalDecodedValue = TryDecodeEnumValue(token)) { + if (auto optionalValue = TEnumTraits<T>::FindValueByLiteral(*optionalDecodedValue)) { + return *optionalValue; + } } - auto isParsingComplete = value.empty(); - if (!isParsingComplete) { - reportError(); + if (enableUnknown) { + if constexpr (constexpr auto optionalUnknownValue = TEnumTraits<T>::TryGetUnknownValue()) { + return *optionalUnknownValue; + } } - return static_cast<T>(underlyingValue); + return std::nullopt; }; if constexpr (TEnumTraits<T>::IsBitEnum) { T result{}; TStringBuf token; - while (value.NextTok('|', token)) { - if (auto scalar = tryFromString(StripString(token))) { - result |= *scalar; + while (str.NextTok('|', token)) { + if (auto optionalValue = tryParseToken(StripString(token))) { + result |= *optionalValue; } else { return {}; } } return result; } else { - return tryFromString(value); + return tryParseToken(str); } } template <class T> -T ParseEnum(TStringBuf value) +T ParseEnum(TStringBuf str) { - if (auto optionalResult = TryParseEnum<T>(value)) { + if (auto optionalResult = TryParseEnum<T>(str, /*enableUnkown*/ true)) { return *optionalResult; } - NYT::NDetail::ThrowMalformedEnumValueException(TEnumTraits<T>::GetTypeName(), value); + NYT::NDetail::ThrowMalformedEnumValueException(TEnumTraits<T>::GetTypeName(), str); } template <class T> void FormatEnum(TStringBuilderBase* builder, T value, bool lowerCase) { - auto formatScalarValue = [builder, lowerCase] (T value) { - auto optionalLiteral = TEnumTraits<T>::FindLiteralByValue(value); - if (!optionalLiteral) { - NYT::NDetail::FormatUnknownEnumValue( - builder, - TEnumTraits<T>::GetTypeName(), - ToUnderlying(value)); - return; - } - + auto formatLiteral = [&] (auto* builder, TStringBuf literal) { if (lowerCase) { - CamelCaseToUnderscoreCase(builder, *optionalLiteral); + CamelCaseToUnderscoreCase(builder, literal); } else { - builder->AppendString(*optionalLiteral); + builder->AppendString(literal); } }; if constexpr (TEnumTraits<T>::IsBitEnum) { - if (TEnumTraits<T>::FindLiteralByValue(value)) { - formatScalarValue(value); + if (None(value)) { + // Avoid empty string if possible. + if (auto optionalLiteral = TEnumTraits<T>::FindLiteralByValue(value)) { + formatLiteral(builder, *optionalLiteral); + } return; } - auto first = true; - for (auto scalarValue : TEnumTraits<T>::GetDomainValues()) { - if (Any(value & scalarValue)) { - if (!first) { - builder->AppendString(TStringBuf(" | ")); - } - first = false; - formatScalarValue(scalarValue); + + TDelimitedStringBuilderWrapper delimitedBuilder(builder, " | "); + + T printedValue{}; + for (auto currentValue : TEnumTraits<T>::GetDomainValues()) { + // Check if currentValue is viable and non-redunant. + if ((value & currentValue) == currentValue && (printedValue | currentValue) != printedValue) { + formatLiteral(&delimitedBuilder, *TEnumTraits<T>::FindLiteralByValue(currentValue)); + printedValue |= currentValue; } } + + // Handle the remainder. + if (printedValue != value) { + NYT::NDetail::FormatUnknownEnumValue(&delimitedBuilder, TEnumTraits<T>::GetTypeName(), value & ~printedValue); + } } else { - formatScalarValue(value); + if (auto optionalLiteral = TEnumTraits<T>::FindLiteralByValue(value)) { + formatLiteral(builder, *optionalLiteral); + return; + } + + NYT::NDetail::FormatUnknownEnumValue(builder, TEnumTraits<T>::GetTypeName(), value); } } |