aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/yt/string/enum-inl.h
diff options
context:
space:
mode:
authorbabenko <babenko@yandex-team.com>2024-10-26 23:13:30 +0300
committerbabenko <babenko@yandex-team.com>2024-10-26 23:30:14 +0300
commit41d598c624442bf6918407466dac3316b8277347 (patch)
tree5895b8823d4f887e1e5ab4f99cbac991dca5ca17 /library/cpp/yt/string/enum-inl.h
parentddabd4ddff87ac13bfc87ef02af352216a0f4e13 (diff)
downloadydb-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.h112
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);
}
}