enum_runtime.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. #include "enum_runtime.h"
  2. #include <util/generic/algorithm.h>
  3. #include <util/generic/map.h>
  4. #include <util/generic/yexception.h>
  5. #include <util/stream/output.h>
  6. namespace NEnumSerializationRuntime {
  7. template <typename TEnumRepresentationType>
  8. [[noreturn]] static void ThrowUndefinedValueException(const TEnumRepresentationType key, const TStringBuf className) {
  9. throw yexception() << "Undefined value " << key << " in " << className << ". ";
  10. }
  11. template <typename TEnumRepresentationType>
  12. const TString& TEnumDescriptionBase<TEnumRepresentationType>::ToString(TRepresentationType key) const {
  13. const auto it = Names.find(key);
  14. if (Y_LIKELY(it != Names.end())) {
  15. return it->second;
  16. }
  17. ThrowUndefinedValueException(key, ClassName);
  18. }
  19. template <typename TEnumRepresentationType>
  20. std::pair<bool, TEnumRepresentationType> TEnumDescriptionBase<TEnumRepresentationType>::TryFromString(const TStringBuf name) const {
  21. const auto it = Values.find(name);
  22. if (it != Values.end()) {
  23. return {true, it->second};
  24. }
  25. return {false, TRepresentationType()};
  26. }
  27. template <class TContainer, class TNeedle, class TGetKey>
  28. static typename TContainer::value_type const* FindPtrInSortedContainer(const TContainer& vec, const TNeedle& needle, TGetKey&& getKey) {
  29. const auto it = LowerBoundBy(vec.begin(), vec.end(), needle, getKey);
  30. if (it == vec.end()) {
  31. return nullptr;
  32. }
  33. if (getKey(*it) != needle) {
  34. return nullptr;
  35. }
  36. return std::addressof(*it);
  37. }
  38. template <typename TEnumRepresentationType>
  39. std::pair<bool, TEnumRepresentationType> TEnumDescriptionBase<TEnumRepresentationType>::TryFromStringSorted(const TStringBuf name, const TInitializationData& enumInitData) {
  40. const auto& vec = enumInitData.ValuesInitializer;
  41. const auto* ptr = FindPtrInSortedContainer(vec, name, std::mem_fn(&TEnumStringPair::Name));
  42. if (ptr) {
  43. return {true, ptr->Key};
  44. }
  45. return {false, TRepresentationType()};
  46. }
  47. template <typename TEnumRepresentationType>
  48. std::pair<bool, TEnumRepresentationType> TEnumDescriptionBase<TEnumRepresentationType>::TryFromStringFullScan(const TStringBuf name, const TInitializationData& enumInitData) {
  49. const auto& vec = enumInitData.ValuesInitializer;
  50. const auto* ptr = FindIfPtr(vec, [&](const auto& item) { return item.Name == name; });
  51. if (ptr) {
  52. return {true, ptr->Key};
  53. }
  54. return {false, TRepresentationType()};
  55. }
  56. [[noreturn]] static void ThrowUndefinedNameException(const TStringBuf name, const TStringBuf className, const TStringBuf allEnumNames) {
  57. ythrow yexception() << "Key '" << name << "' not found in enum " << className << ". Valid options are: " << allEnumNames << ". ";
  58. }
  59. template <typename TEnumRepresentationType>
  60. [[noreturn]] static void ThrowUndefinedNameException(const TStringBuf name, const typename TEnumDescriptionBase<TEnumRepresentationType>::TInitializationData& enumInitData) {
  61. auto exc = __LOCATION__ + yexception() << "Key '" << name << "' not found in enum " << enumInitData.ClassName << ". Valid options are: ";
  62. const auto& vec = enumInitData.NamesInitializer;
  63. for (size_t i = 0; i < vec.size(); ++i) {
  64. if (i != 0) {
  65. exc << ", ";
  66. }
  67. exc << '\'' << vec[i].Name << '\'';
  68. }
  69. exc << ". ";
  70. throw exc;
  71. }
  72. template <typename TEnumRepresentationType>
  73. auto TEnumDescriptionBase<TEnumRepresentationType>::FromString(const TStringBuf name) const -> TRepresentationType {
  74. const auto findResult = TryFromString(name);
  75. if (Y_LIKELY(findResult.first)) {
  76. return findResult.second;
  77. }
  78. ThrowUndefinedNameException(name, ClassName, AllEnumNames());
  79. }
  80. template <typename TEnumRepresentationType>
  81. TEnumRepresentationType TEnumDescriptionBase<TEnumRepresentationType>::FromStringFullScan(const TStringBuf name, const TInitializationData& enumInitData) {
  82. const auto findResult = TryFromStringFullScan(name, enumInitData);
  83. if (Y_LIKELY(findResult.first)) {
  84. return findResult.second;
  85. }
  86. ThrowUndefinedNameException<TEnumRepresentationType>(name, enumInitData);
  87. }
  88. template <typename TEnumRepresentationType>
  89. TEnumRepresentationType TEnumDescriptionBase<TEnumRepresentationType>::FromStringSorted(const TStringBuf name, const TInitializationData& enumInitData) {
  90. const auto findResult = TryFromStringSorted(name, enumInitData);
  91. if (Y_LIKELY(findResult.first)) {
  92. return findResult.second;
  93. }
  94. ThrowUndefinedNameException<TEnumRepresentationType>(name, enumInitData);
  95. }
  96. template <typename TEnumRepresentationType>
  97. TStringBuf TEnumDescriptionBase<TEnumRepresentationType>::ToStringBuf(TRepresentationType key) const {
  98. return this->ToString(key);
  99. }
  100. template <typename TEnumRepresentationType>
  101. TStringBuf TEnumDescriptionBase<TEnumRepresentationType>::ToStringBufFullScan(const TRepresentationType key, const TInitializationData& enumInitData) {
  102. const auto& vec = enumInitData.NamesInitializer;
  103. const auto* ptr = FindIfPtr(vec, [&](const auto& item) { return item.Key == key; });
  104. if (Y_UNLIKELY(!ptr)) {
  105. ThrowUndefinedValueException(key, enumInitData.ClassName);
  106. }
  107. return ptr->Name;
  108. }
  109. template <typename TEnumRepresentationType>
  110. TStringBuf TEnumDescriptionBase<TEnumRepresentationType>::ToStringBufSorted(const TRepresentationType key, const TInitializationData& enumInitData) {
  111. const auto& vec = enumInitData.NamesInitializer;
  112. const auto* ptr = FindPtrInSortedContainer(vec, key, std::mem_fn(&TEnumStringPair::Key));
  113. if (Y_UNLIKELY(!ptr)) {
  114. ThrowUndefinedValueException(key, enumInitData.ClassName);
  115. }
  116. return ptr->Name;
  117. }
  118. template <typename TEnumRepresentationType>
  119. TStringBuf TEnumDescriptionBase<TEnumRepresentationType>::ToStringBufDirect(const TRepresentationType key, const TInitializationData& enumInitData) {
  120. const auto& vec = enumInitData.NamesInitializer;
  121. if (Y_UNLIKELY(vec.empty() || key < vec.front().Key)) {
  122. ThrowUndefinedValueException(key, enumInitData.ClassName);
  123. }
  124. const size_t index = static_cast<size_t>(key - vec.front().Key);
  125. if (Y_UNLIKELY(index >= vec.size())) {
  126. ThrowUndefinedValueException(key, enumInitData.ClassName);
  127. }
  128. return vec[index].Name;
  129. }
  130. template <typename TEnumRepresentationType>
  131. void TEnumDescriptionBase<TEnumRepresentationType>::Out(IOutputStream* os, const TRepresentationType key) const {
  132. (*os) << this->ToStringBuf(key);
  133. }
  134. template <typename TEnumRepresentationType>
  135. void TEnumDescriptionBase<TEnumRepresentationType>::OutFullScan(IOutputStream* os, const TRepresentationType key, const TInitializationData& enumInitData) {
  136. (*os) << ToStringBufFullScan(key, enumInitData);
  137. }
  138. template <typename TEnumRepresentationType>
  139. void TEnumDescriptionBase<TEnumRepresentationType>::OutSorted(IOutputStream* os, const TRepresentationType key, const TInitializationData& enumInitData) {
  140. (*os) << ToStringBufSorted(key, enumInitData);
  141. }
  142. template <typename TEnumRepresentationType>
  143. void TEnumDescriptionBase<TEnumRepresentationType>::OutDirect(IOutputStream* os, const TRepresentationType key, const TInitializationData& enumInitData) {
  144. (*os) << ToStringBufDirect(key, enumInitData);
  145. }
  146. template <typename TEnumRepresentationType>
  147. TEnumDescriptionBase<TEnumRepresentationType>::TEnumDescriptionBase(const TInitializationData& enumInitData)
  148. : ClassName(enumInitData.ClassName)
  149. {
  150. const TArrayRef<const TEnumStringPair>& namesInitializer = enumInitData.NamesInitializer;
  151. const TArrayRef<const TEnumStringPair>& valuesInitializer = enumInitData.ValuesInitializer;
  152. const TArrayRef<const TStringBuf>& cppNamesInitializer = enumInitData.CppNamesInitializer;
  153. TMap<TRepresentationType, TString> mapValueToName;
  154. TMap<TStringBuf, TRepresentationType> mapNameToValue;
  155. for (const TEnumStringPair& it : namesInitializer) {
  156. mapValueToName.emplace(it.Key, TString(it.Name));
  157. }
  158. for (const TEnumStringPair& it : valuesInitializer) {
  159. mapNameToValue.emplace(it.Name, it.Key);
  160. }
  161. Names = std::move(mapValueToName);
  162. Values = std::move(mapNameToValue);
  163. AllValues.reserve(Names.size());
  164. for (const auto& it : Names) {
  165. if (!AllNames.empty()) {
  166. AllNames += ", ";
  167. }
  168. AllNames += TString::Join('\'', it.second, '\'');
  169. AllValues.push_back(it.first);
  170. }
  171. AllCppNames.reserve(cppNamesInitializer.size());
  172. for (const auto& cn : cppNamesInitializer) {
  173. AllCppNames.push_back(TString::Join(enumInitData.CppNamesPrefix, cn));
  174. }
  175. }
  176. template <typename TEnumRepresentationType>
  177. TEnumDescriptionBase<TEnumRepresentationType>::~TEnumDescriptionBase() = default;
  178. // explicit instantiation
  179. template class TEnumDescriptionBase<int>;
  180. template class TEnumDescriptionBase<unsigned>;
  181. template class TEnumDescriptionBase<long long>;
  182. template class TEnumDescriptionBase<unsigned long long>;
  183. }