enum-inl.h 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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 <library/cpp/yt/exception/exception.h>
  8. #include <util/string/printf.h>
  9. namespace NYT {
  10. ////////////////////////////////////////////////////////////////////////////////
  11. namespace NDetail {
  12. [[noreturn]]
  13. void ThrowMalformedEnumValueException(
  14. TStringBuf typeName,
  15. TStringBuf value);
  16. void FormatUnknownEnumValue(
  17. TStringBuilderBase* builder,
  18. TStringBuf name,
  19. i64 value);
  20. } // namespace NDetail
  21. template <class T>
  22. std::optional<T> TryParseEnum(TStringBuf value)
  23. {
  24. auto tryFromString = [] (TStringBuf value) -> std::optional<T> {
  25. if (auto decodedValue = TryDecodeEnumValue(value)) {
  26. auto enumValue = TEnumTraits<T>::FindValueByLiteral(*decodedValue);
  27. return enumValue ? enumValue : TEnumTraits<T>::FindValueByLiteral(value);
  28. }
  29. auto reportError = [value] () {
  30. throw TSimpleException(Format("Enum value %Qv is neither in a proper underscore case nor in a format \"%v(123)\"",
  31. value,
  32. TEnumTraits<T>::GetTypeName()));
  33. };
  34. TStringBuf typeName;
  35. auto isTypeNameCorrect = value.NextTok('(', typeName) && typeName == TEnumTraits<T>::GetTypeName();
  36. if (!isTypeNameCorrect) {
  37. reportError();
  38. }
  39. TStringBuf enumValue;
  40. std::underlying_type_t<T> underlyingValue = 0;
  41. auto isEnumValueCorrect = value.NextTok(')', enumValue) && TryFromString(enumValue, underlyingValue);
  42. if (!isEnumValueCorrect) {
  43. reportError();
  44. }
  45. auto isParsingComplete = value.empty();
  46. if (!isParsingComplete) {
  47. reportError();
  48. }
  49. return static_cast<T>(underlyingValue);
  50. };
  51. if constexpr (TEnumTraits<T>::IsBitEnum) {
  52. T result{};
  53. TStringBuf token;
  54. while (value.NextTok('|', token)) {
  55. if (auto scalar = tryFromString(StripString(token))) {
  56. result |= *scalar;
  57. } else {
  58. return {};
  59. }
  60. }
  61. return result;
  62. } else {
  63. return tryFromString(value);
  64. }
  65. }
  66. template <class T>
  67. T ParseEnum(TStringBuf value)
  68. {
  69. if (auto optionalResult = TryParseEnum<T>(value)) {
  70. return *optionalResult;
  71. }
  72. NYT::NDetail::ThrowMalformedEnumValueException(TEnumTraits<T>::GetTypeName(), value);
  73. }
  74. template <class T>
  75. void FormatEnum(TStringBuilderBase* builder, T value, bool lowerCase)
  76. {
  77. auto formatScalarValue = [builder, lowerCase] (T value) {
  78. auto optionalLiteral = TEnumTraits<T>::FindLiteralByValue(value);
  79. if (!optionalLiteral) {
  80. NYT::NDetail::FormatUnknownEnumValue(
  81. builder,
  82. TEnumTraits<T>::GetTypeName(),
  83. ToUnderlying(value));
  84. return;
  85. }
  86. if (lowerCase) {
  87. CamelCaseToUnderscoreCase(builder, *optionalLiteral);
  88. } else {
  89. builder->AppendString(*optionalLiteral);
  90. }
  91. };
  92. if constexpr (TEnumTraits<T>::IsBitEnum) {
  93. if (TEnumTraits<T>::FindLiteralByValue(value)) {
  94. formatScalarValue(value);
  95. return;
  96. }
  97. auto first = true;
  98. for (auto scalarValue : TEnumTraits<T>::GetDomainValues()) {
  99. if (Any(value & scalarValue)) {
  100. if (!first) {
  101. builder->AppendString(TStringBuf(" | "));
  102. }
  103. first = false;
  104. formatScalarValue(scalarValue);
  105. }
  106. }
  107. } else {
  108. formatScalarValue(value);
  109. }
  110. }
  111. template <class T>
  112. TString FormatEnum(T value)
  113. {
  114. TStringBuilder builder;
  115. FormatEnum(&builder, value, /*lowerCase*/ true);
  116. return builder.Flush();
  117. }
  118. ////////////////////////////////////////////////////////////////////////////////
  119. } // namespace NYT