enum-inl.h 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #ifndef ENUM_INL_H_
  2. #error "Direct inclusion of this file is not allowed, include enum.h"
  3. // For the sake of sane code completion.
  4. #include "enum.h"
  5. #endif
  6. #include "format.h"
  7. #include "string.h"
  8. #include "string_builder.h"
  9. #include <library/cpp/yt/exception/exception.h>
  10. #include <util/string/printf.h>
  11. #include <util/string/strip.h>
  12. namespace NYT {
  13. ////////////////////////////////////////////////////////////////////////////////
  14. namespace NDetail {
  15. [[noreturn]]
  16. void ThrowMalformedEnumValueException(
  17. TStringBuf typeName,
  18. TStringBuf value);
  19. void FormatUnknownEnumValue(
  20. auto* builder,
  21. TStringBuf name,
  22. auto value)
  23. {
  24. builder->AppendFormat("%v::unknown-%v", name, ToUnderlying(value));
  25. }
  26. } // namespace NDetail
  27. template <class T>
  28. std::optional<T> TryParseEnum(TStringBuf str, bool enableUnknown)
  29. {
  30. auto tryParseToken = [&] (TStringBuf token) -> std::optional<T> {
  31. if (auto optionalValue = TEnumTraits<T>::FindValueByLiteral(token)) {
  32. return *optionalValue;
  33. }
  34. if (auto optionalDecodedValue = TryDecodeEnumValue(token)) {
  35. if (auto optionalValue = TEnumTraits<T>::FindValueByLiteral(*optionalDecodedValue)) {
  36. return *optionalValue;
  37. }
  38. }
  39. if (enableUnknown) {
  40. if constexpr (constexpr auto optionalUnknownValue = TEnumTraits<T>::TryGetUnknownValue()) {
  41. return *optionalUnknownValue;
  42. }
  43. }
  44. return std::nullopt;
  45. };
  46. if constexpr (TEnumTraits<T>::IsBitEnum) {
  47. T result{};
  48. TStringBuf token;
  49. while (str.NextTok('|', token)) {
  50. if (auto optionalValue = tryParseToken(StripString(token))) {
  51. result |= *optionalValue;
  52. } else {
  53. return {};
  54. }
  55. }
  56. return result;
  57. } else {
  58. return tryParseToken(str);
  59. }
  60. }
  61. template <class T>
  62. T ParseEnum(TStringBuf str)
  63. {
  64. if (auto optionalResult = TryParseEnum<T>(str, /*enableUnkown*/ true)) {
  65. return *optionalResult;
  66. }
  67. NYT::NDetail::ThrowMalformedEnumValueException(TEnumTraits<T>::GetTypeName(), str);
  68. }
  69. template <class T>
  70. void FormatEnum(TStringBuilderBase* builder, T value, bool lowerCase)
  71. {
  72. auto formatLiteral = [&] (auto* builder, TStringBuf literal) {
  73. if (lowerCase) {
  74. CamelCaseToUnderscoreCase(builder, literal);
  75. } else {
  76. builder->AppendString(literal);
  77. }
  78. };
  79. if constexpr (TEnumTraits<T>::IsBitEnum) {
  80. if (None(value)) {
  81. // Avoid empty string if possible.
  82. if (auto optionalLiteral = TEnumTraits<T>::FindLiteralByValue(value)) {
  83. formatLiteral(builder, *optionalLiteral);
  84. }
  85. return;
  86. }
  87. TDelimitedStringBuilderWrapper delimitedBuilder(builder, " | ");
  88. T printedValue{};
  89. for (auto currentValue : TEnumTraits<T>::GetDomainValues()) {
  90. // Check if currentValue is viable and non-redunant.
  91. if ((value & currentValue) == currentValue && (printedValue | currentValue) != printedValue) {
  92. formatLiteral(&delimitedBuilder, *TEnumTraits<T>::FindLiteralByValue(currentValue));
  93. printedValue |= currentValue;
  94. }
  95. }
  96. // Handle the remainder.
  97. if (printedValue != value) {
  98. NYT::NDetail::FormatUnknownEnumValue(&delimitedBuilder, TEnumTraits<T>::GetTypeName(), value & ~printedValue);
  99. }
  100. } else {
  101. if (auto optionalLiteral = TEnumTraits<T>::FindLiteralByValue(value)) {
  102. formatLiteral(builder, *optionalLiteral);
  103. return;
  104. }
  105. NYT::NDetail::FormatUnknownEnumValue(builder, TEnumTraits<T>::GetTypeName(), value);
  106. }
  107. }
  108. template <class T>
  109. TString FormatEnum(T value)
  110. {
  111. TStringBuilder builder;
  112. FormatEnum(&builder, value, /*lowerCase*/ true);
  113. return builder.Flush();
  114. }
  115. ////////////////////////////////////////////////////////////////////////////////
  116. } // namespace NYT