#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 "format.h" #include "string.h" #include "string_builder.h" #include #include #include namespace NYT { //////////////////////////////////////////////////////////////////////////////// namespace NDetail { [[noreturn]] void ThrowMalformedEnumValueException( TStringBuf typeName, TStringBuf value); void FormatUnknownEnumValue( auto* builder, TStringBuf name, auto value) { builder->AppendFormat("%v::unknown-%v", name, ToUnderlying(value)); } } // namespace NDetail template std::optional TryParseEnum(TStringBuf str, bool enableUnknown) { auto tryParseToken = [&] (TStringBuf token) -> std::optional { if (auto optionalValue = TEnumTraits::FindValueByLiteral(token)) { return *optionalValue; } if (auto optionalDecodedValue = TryDecodeEnumValue(token)) { if (auto optionalValue = TEnumTraits::FindValueByLiteral(*optionalDecodedValue)) { return *optionalValue; } } if (enableUnknown) { if constexpr (constexpr auto optionalUnknownValue = TEnumTraits::TryGetUnknownValue()) { return *optionalUnknownValue; } } return std::nullopt; }; if constexpr (TEnumTraits::IsBitEnum) { T result{}; TStringBuf token; while (str.NextTok('|', token)) { if (auto optionalValue = tryParseToken(StripString(token))) { result |= *optionalValue; } else { return {}; } } return result; } else { return tryParseToken(str); } } template T ParseEnum(TStringBuf str) { if (auto optionalResult = TryParseEnum(str, /*enableUnkown*/ true)) { return *optionalResult; } NYT::NDetail::ThrowMalformedEnumValueException(TEnumTraits::GetTypeName(), str); } template void FormatEnum(TStringBuilderBase* builder, T value, bool lowerCase) { auto formatLiteral = [&] (auto* builder, TStringBuf literal) { if (lowerCase) { CamelCaseToUnderscoreCase(builder, literal); } else { builder->AppendString(literal); } }; if constexpr (TEnumTraits::IsBitEnum) { if (None(value)) { // Avoid empty string if possible. if (auto optionalLiteral = TEnumTraits::FindLiteralByValue(value)) { formatLiteral(builder, *optionalLiteral); } return; } TDelimitedStringBuilderWrapper delimitedBuilder(builder, " | "); T printedValue{}; for (auto currentValue : TEnumTraits::GetDomainValues()) { // Check if currentValue is viable and non-redunant. if ((value & currentValue) == currentValue && (printedValue | currentValue) != printedValue) { formatLiteral(&delimitedBuilder, *TEnumTraits::FindLiteralByValue(currentValue)); printedValue |= currentValue; } } // Handle the remainder. if (printedValue != value) { NYT::NDetail::FormatUnknownEnumValue(&delimitedBuilder, TEnumTraits::GetTypeName(), value & ~printedValue); } } else { if (auto optionalLiteral = TEnumTraits::FindLiteralByValue(value)) { formatLiteral(builder, *optionalLiteral); return; } NYT::NDetail::FormatUnknownEnumValue(builder, TEnumTraits::GetTypeName(), value); } } template TString FormatEnum(T value) { TStringBuilder builder; FormatEnum(&builder, value, /*lowerCase*/ true); return builder.Flush(); } //////////////////////////////////////////////////////////////////////////////// } // namespace NYT