enum.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. #pragma once
  2. #include <bitset>
  3. #include <util/generic/strbuf.h>
  4. #include <util/stream/str.h>
  5. #include <util/string/cast.h>
  6. #include <util/string/split.h>
  7. #include <utility>
  8. class TEnumNotFoundException: public yexception {
  9. };
  10. #define EnumFromString(key, entries) EnumFromStringImpl(key, entries, Y_ARRAY_SIZE(entries))
  11. #define EnumFromStringWithSize(key, entries, size) EnumFromStringImpl(key, entries, size)
  12. #define FindEnumFromString(key, entries) FindEnumFromStringImpl(key, entries, Y_ARRAY_SIZE(entries))
  13. #define FindEnumFromStringWithSize(key, entries, size) FindEnumFromStringImpl(key, entries, size)
  14. #define EnumToString(key, entries) EnumToStringImpl(key, entries, Y_ARRAY_SIZE(entries))
  15. #define EnumToStringWithSize(key, entries, size) EnumToStringImpl(key, entries, size)
  16. #define PrintEnumItems(entries) PrintEnumItemsImpl(entries, Y_ARRAY_SIZE(entries))
  17. template <class K1, class K2, class V>
  18. const V* FindEnumFromStringImpl(K1 key, const std::pair<K2, V>* entries, size_t arraySize) {
  19. for (size_t i = 0; i < arraySize; i++) {
  20. if (entries[i].first == key) {
  21. return &entries[i].second;
  22. }
  23. }
  24. return nullptr;
  25. }
  26. // special version for const char*
  27. template <class V>
  28. const V* FindEnumFromStringImpl(const char* key, const std::pair<const char*, V>* entries, size_t arraySize) {
  29. for (size_t i = 0; i < arraySize; i++) {
  30. if (entries[i].first && key && !strcmp(entries[i].first, key)) {
  31. return &entries[i].second;
  32. }
  33. }
  34. return nullptr;
  35. }
  36. template <class K, class V>
  37. TString PrintEnumItemsImpl(const std::pair<K, V>* entries, size_t arraySize) {
  38. TString result;
  39. TStringOutput out(result);
  40. for (size_t i = 0; i < arraySize; i++) {
  41. out << (i ? ", " : "") << "'" << entries[i].first << "'";
  42. }
  43. return result;
  44. }
  45. // special version for const char*
  46. template <class V>
  47. TString PrintEnumItemsImpl(const std::pair<const char*, V>* entries, size_t arraySize) {
  48. TString result;
  49. TStringOutput out(result);
  50. for (size_t i = 0; i < arraySize; i++) {
  51. out << (i ? ", " : "") << "'" << (entries[i].first ? entries[i].first : "<null>") << "'";
  52. }
  53. return result;
  54. }
  55. template <class K1, class K2, class V>
  56. const V* EnumFromStringImpl(K1 key, const std::pair<K2, V>* entries, size_t arraySize) {
  57. const V* res = FindEnumFromStringImpl(key, entries, arraySize);
  58. if (res) {
  59. return res;
  60. }
  61. ythrow TEnumNotFoundException() << "Key '" << key << "' not found in enum. Valid options are: " << PrintEnumItemsImpl(entries, arraySize) << ". ";
  62. }
  63. template <class K, class V>
  64. const K* EnumToStringImpl(V value, const std::pair<K, V>* entries, size_t arraySize) {
  65. for (size_t i = 0; i < arraySize; i++) {
  66. if (entries[i].second == value) {
  67. return &entries[i].first;
  68. }
  69. }
  70. TEnumNotFoundException exc;
  71. exc << "Value '" << int(value) << "' not found in enum. Valid values are: ";
  72. for (size_t i = 0; i < arraySize; i++) {
  73. exc << (i ? ", " : "") << int(entries[i].second);
  74. }
  75. exc << ". ";
  76. ythrow exc;
  77. }
  78. ///////////////////////////////////
  79. template <class B>
  80. inline void SetEnumFlagsForEmptySpec(B& flags, bool allIfEmpty) {
  81. if (allIfEmpty) {
  82. flags.set();
  83. } else {
  84. flags.reset();
  85. }
  86. }
  87. // all set by default
  88. template <class E, size_t N, size_t B>
  89. inline void SetEnumFlags(const std::pair<const char*, E> (&str2Enum)[N], TStringBuf optSpec,
  90. std::bitset<B>& flags, bool allIfEmpty = true) {
  91. if (optSpec.empty()) {
  92. SetEnumFlagsForEmptySpec(flags, allIfEmpty);
  93. } else {
  94. flags.reset();
  95. for (const auto& it : StringSplitter(optSpec).Split(',')) {
  96. E e = *EnumFromStringImpl(ToString(it.Token()).data(), str2Enum, N);
  97. flags.set(e);
  98. }
  99. }
  100. }
  101. template <class E, size_t B>
  102. inline void SetEnumFlags(const std::pair<const char*, E>* str2Enum, TStringBuf optSpec,
  103. std::bitset<B>& flags, const size_t size,
  104. bool allIfEmpty = true) {
  105. if (optSpec.empty()) {
  106. SetEnumFlagsForEmptySpec(flags, allIfEmpty);
  107. } else {
  108. flags.reset();
  109. for (const auto& it : StringSplitter(optSpec).Split(',')) {
  110. E e = *EnumFromStringImpl(ToString(it.Token()).data(), str2Enum, size);
  111. flags.set(e);
  112. }
  113. }
  114. }
  115. // for enums generated with GENERATE_ENUM_SERIALIZATION
  116. template <class E, size_t B>
  117. inline void SetEnumFlags(TStringBuf optSpec, std::bitset<B>& flags, bool allIfEmpty = true) {
  118. if (optSpec.empty()) {
  119. SetEnumFlagsForEmptySpec(flags, allIfEmpty);
  120. } else {
  121. flags.reset();
  122. for (const auto& it : StringSplitter(optSpec).Split(',')) {
  123. E e;
  124. if (!TryFromString(it.Token(), e)) {
  125. ythrow yexception() << "Unknown enum value '" << it.Token() << "'";
  126. }
  127. flags.set((size_t)e);
  128. }
  129. }
  130. }