serialized_enum.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. #pragma once
  2. #include <util/generic/fwd.h>
  3. #include <util/generic/vector.h>
  4. #include <util/generic/map.h>
  5. #include <cstddef>
  6. #include <type_traits>
  7. /*
  8. A file with declarations of enumeration-related functions.
  9. It doesn't contains definitions. To generate them you have to add
  10. GENERATE_ENUM_SERIALIZATION_WITH_HEADER(your_header_with_your_enum.h)
  11. or
  12. GENERATE_ENUM_SERIALIZATION(your_header_with_your_enum.h)
  13. in your ya.make
  14. @see https://st.yandex-team.ru/IGNIETFERRO-333
  15. @see https://wiki.yandex-team.ru/PoiskovajaPlatforma/Build/WritingCmakefiles/#generate-enum-with-header
  16. */
  17. /**
  18. * Returns number of distinct items in enum or enum class
  19. *
  20. * @tparam EnumT enum type
  21. */
  22. template <typename EnumT>
  23. Y_CONST_FUNCTION constexpr size_t GetEnumItemsCount();
  24. namespace NEnumSerializationRuntime {
  25. namespace NDetail {
  26. template <typename EEnum>
  27. struct TSelectEnumRepresentationType;
  28. template <typename TEnumType, typename TRepresentationType, class TStorage = TVector<TRepresentationType>>
  29. class TMappedArrayView;
  30. template <typename TEnumType, typename TRepresentationType, typename TValueType, class TStorage = TMap<TRepresentationType, TValueType>>
  31. class TMappedDictView;
  32. } // namespace NDetail
  33. /// Class with behaviour similar to TMap<EnumT, TValueType>
  34. template <typename EnumT, typename TValueType>
  35. using TMappedDictView = NDetail::TMappedDictView<EnumT, typename NDetail::TSelectEnumRepresentationType<EnumT>::TType, TValueType>;
  36. /// Class with behaviour similar to TVector<EnumT>
  37. template <typename EnumT>
  38. using TMappedArrayView = NDetail::TMappedArrayView<EnumT, typename NDetail::TSelectEnumRepresentationType<EnumT>::TType>;
  39. /**
  40. * Returns names for items in enum or enum class
  41. *
  42. * @tparam EnumT enum type
  43. */
  44. template <typename EnumT>
  45. TMappedDictView<EnumT, TString> GetEnumNamesImpl();
  46. /**
  47. * Returns unique items in enum or enum class
  48. *
  49. * @tparam EnumT enum type
  50. */
  51. template <typename EnumT>
  52. ::NEnumSerializationRuntime::TMappedArrayView<EnumT> GetEnumAllValuesImpl();
  53. /**
  54. * Returns human-readable comma-separated list of names in enum or enum class
  55. *
  56. * @tparam EnumT enum type
  57. */
  58. template <typename EnumT>
  59. const TString& GetEnumAllNamesImpl();
  60. /**
  61. * Returns C++ identifiers for items in enum or enum class
  62. *
  63. * @tparam EnumT enum type
  64. */
  65. template <typename EnumT>
  66. const TVector<TString>& GetEnumAllCppNamesImpl();
  67. /**
  68. * Converts @c e to a string. Works like @c ToString(e) function, but returns @c TStringBuf instead of @c TString.
  69. * Thus works slightly faster and usually avoids any dynamic memory allocation.
  70. * @throw yexception is case of unknown enum value
  71. */
  72. template <typename EnumT>
  73. TStringBuf ToStringBuf(EnumT e);
  74. } // namespace NEnumSerializationRuntime
  75. /**
  76. * Returns names for items in enum or enum class
  77. *
  78. * @tparam EnumT enum type
  79. */
  80. template <typename EnumT>
  81. Y_CONST_FUNCTION ::NEnumSerializationRuntime::TMappedDictView<EnumT, TString> GetEnumNames() {
  82. return ::NEnumSerializationRuntime::GetEnumNamesImpl<EnumT>();
  83. }
  84. /**
  85. * Returns unique items in enum or enum class
  86. *
  87. * @tparam EnumT enum type
  88. */
  89. template <typename EnumT>
  90. Y_CONST_FUNCTION ::NEnumSerializationRuntime::TMappedArrayView<EnumT> GetEnumAllValues() {
  91. return ::NEnumSerializationRuntime::GetEnumAllValuesImpl<EnumT>();
  92. }
  93. /**
  94. * Returns human-readable comma-separated list of names in enum or enum class
  95. *
  96. * @tparam EnumT enum type
  97. */
  98. template <typename EnumT>
  99. Y_CONST_FUNCTION const TString& GetEnumAllNames() {
  100. return ::NEnumSerializationRuntime::GetEnumAllNamesImpl<EnumT>();
  101. }
  102. /**
  103. * Returns C++ identifiers for items in enum or enum class
  104. *
  105. * @tparam EnumT enum type
  106. */
  107. template <typename EnumT>
  108. Y_CONST_FUNCTION const TVector<TString>& GetEnumAllCppNames() {
  109. return ::NEnumSerializationRuntime::GetEnumAllCppNamesImpl<EnumT>();
  110. }
  111. namespace NEnumSerializationRuntime {
  112. namespace NDetail {
  113. /// Checks that the `From` type can be promoted up to the `To` type without losses
  114. template <typename From, typename To>
  115. struct TIsPromotable: public std::is_same<std::common_type_t<From, To>, To> {
  116. static_assert(std::is_integral<From>::value, "`From` type has to be an integer");
  117. static_assert(std::is_integral<To>::value, "`To` type has to be an integer");
  118. };
  119. /// Selects enum representation type. Works like std::underlying_type_t<>, but promotes small types up to `int`
  120. template <typename EEnum>
  121. struct TSelectEnumRepresentationType {
  122. using TUnderlyingType = std::underlying_type_t<EEnum>;
  123. using TIsSigned = std::is_signed<TUnderlyingType>;
  124. using TRepresentationType = std::conditional_t<
  125. TIsSigned::value,
  126. std::conditional_t<
  127. TIsPromotable<TUnderlyingType, int>::value,
  128. int,
  129. long long>,
  130. std::conditional_t<
  131. TIsPromotable<TUnderlyingType, unsigned>::value,
  132. unsigned,
  133. unsigned long long>>;
  134. using TType = TRepresentationType;
  135. static_assert(sizeof(TUnderlyingType) <= sizeof(TType), "size of `TType` is not smaller than the size of `TUnderlyingType`");
  136. };
  137. template <typename TEnumType, typename TRepresentationType>
  138. class TMappedViewBase {
  139. static_assert(sizeof(std::underlying_type_t<TEnumType>) <= sizeof(TRepresentationType), "Internal type is probably too small to represent all possible values");
  140. public:
  141. static constexpr TEnumType CastFromRepresentationType(const TRepresentationType key) noexcept {
  142. return static_cast<TEnumType>(key);
  143. }
  144. static constexpr TRepresentationType CastToRepresentationType(const TEnumType key) noexcept {
  145. return static_cast<TRepresentationType>(key);
  146. }
  147. };
  148. /// Wrapper class with behaviour similar to TVector<EnumT>
  149. ///
  150. /// @tparam TEnumType enum type at the external interface
  151. /// @tparam TRepresentationType designated underlying type of enum
  152. /// @tparam TStorage internal container type
  153. template <typename TEnumType, typename TRepresentationType, class TStorage>
  154. class TMappedArrayView: public TMappedViewBase<TEnumType, TRepresentationType> {
  155. public:
  156. using value_type = TEnumType;
  157. public:
  158. TMappedArrayView(const TStorage& a) noexcept
  159. : Ref(a)
  160. {
  161. }
  162. class TIterator {
  163. public:
  164. using TSlaveIteratorType = typename TStorage::const_iterator;
  165. using difference_type = std::ptrdiff_t;
  166. using value_type = TEnumType;
  167. using pointer = const TEnumType*;
  168. using reference = const TEnumType&;
  169. using iterator_category = std::bidirectional_iterator_tag;
  170. public:
  171. TIterator(TSlaveIteratorType it)
  172. : Slave(std::move(it))
  173. {
  174. }
  175. bool operator==(const TIterator& it) const {
  176. return Slave == it.Slave;
  177. }
  178. bool operator!=(const TIterator& it) const {
  179. return !(*this == it);
  180. }
  181. TEnumType operator*() const {
  182. return TMappedArrayView::CastFromRepresentationType(*Slave);
  183. }
  184. TIterator& operator++() {
  185. ++Slave;
  186. return *this;
  187. }
  188. TIterator& operator--() {
  189. --Slave;
  190. return *this;
  191. }
  192. TIterator operator++(int) {
  193. auto temp = Slave;
  194. ++Slave;
  195. return temp;
  196. }
  197. TIterator operator--(int) {
  198. auto temp = Slave;
  199. --Slave;
  200. return temp;
  201. }
  202. private:
  203. TSlaveIteratorType Slave;
  204. };
  205. TIterator begin() const {
  206. return Ref.begin();
  207. }
  208. TIterator end() const {
  209. return Ref.end();
  210. }
  211. size_t size() const {
  212. return Ref.size();
  213. }
  214. Y_PURE_FUNCTION bool empty() const {
  215. return Ref.empty();
  216. }
  217. TEnumType at(size_t index) const {
  218. return this->CastFromRepresentationType(Ref.at(index));
  219. }
  220. TEnumType operator[](size_t index) const {
  221. return this->CastFromRepresentationType(Ref[index]);
  222. }
  223. // Allocate container and copy view's content into it
  224. template <template <class...> class TContainer = TVector>
  225. TContainer<TEnumType> Materialize() const {
  226. return {begin(), end()};
  227. }
  228. private:
  229. const TStorage& Ref;
  230. };
  231. /// Wrapper class with behaviour similar to TMap<EnumT, TValueType>
  232. ///
  233. /// @tparam TEnumType enum type at the external interface
  234. /// @tparam TRepresentationType designated underlying type of enum
  235. /// @tparam TValueType mapped value
  236. /// @tparam TStorage internal container type
  237. template <typename TEnumType, typename TRepresentationType, typename TValueType, class TStorage>
  238. class TMappedDictView: public TMappedViewBase<TEnumType, TRepresentationType> {
  239. public:
  240. using TMappedItemType = std::pair<const TEnumType, const TValueType&>;
  241. class TDereferenceResultHolder {
  242. public:
  243. TDereferenceResultHolder(const TRepresentationType enumValue, const TValueType& payload) noexcept
  244. : Data(TMappedDictView::CastFromRepresentationType(enumValue), payload)
  245. {
  246. }
  247. const TMappedItemType* operator->() const noexcept {
  248. return &Data;
  249. }
  250. private:
  251. TMappedItemType Data;
  252. };
  253. TMappedDictView(const TStorage& m) noexcept
  254. : Ref(m)
  255. {
  256. }
  257. class TIterator {
  258. public:
  259. using TSlaveIteratorType = typename TStorage::const_iterator;
  260. using difference_type = std::ptrdiff_t;
  261. using value_type = TMappedItemType;
  262. using pointer = const TMappedItemType*;
  263. using reference = const TMappedItemType&;
  264. using iterator_category = std::bidirectional_iterator_tag;
  265. public:
  266. TIterator(TSlaveIteratorType it)
  267. : Slave(std::move(it))
  268. {
  269. }
  270. bool operator==(const TIterator& it) const {
  271. return Slave == it.Slave;
  272. }
  273. bool operator!=(const TIterator& it) const {
  274. return !(*this == it);
  275. }
  276. TDereferenceResultHolder operator->() const {
  277. return {Slave->first, Slave->second};
  278. }
  279. TMappedItemType operator*() const {
  280. return {TMappedDictView::CastFromRepresentationType(Slave->first), Slave->second};
  281. }
  282. TIterator& operator++() {
  283. ++Slave;
  284. return *this;
  285. }
  286. TIterator& operator--() {
  287. --Slave;
  288. return *this;
  289. }
  290. TIterator operator++(int) {
  291. auto temp = Slave;
  292. ++Slave;
  293. return temp;
  294. }
  295. TIterator operator--(int) {
  296. auto temp = Slave;
  297. --Slave;
  298. return temp;
  299. }
  300. private:
  301. TSlaveIteratorType Slave;
  302. };
  303. TIterator begin() const {
  304. return Ref.begin();
  305. }
  306. TIterator end() const {
  307. return Ref.end();
  308. }
  309. size_t size() const {
  310. return Ref.size();
  311. }
  312. Y_PURE_FUNCTION bool empty() const {
  313. return Ref.empty();
  314. }
  315. bool contains(const TEnumType key) const {
  316. return Ref.contains(this->CastToRepresentationType(key));
  317. }
  318. TIterator find(const TEnumType key) const {
  319. return Ref.find(this->CastToRepresentationType(key));
  320. }
  321. const TValueType& at(const TEnumType key) const {
  322. return Ref.at(this->CastToRepresentationType(key));
  323. }
  324. // Allocate container and copy view's content into it
  325. template <template <class...> class TContainer = TMap>
  326. TContainer<TEnumType, TValueType> Materialize() const {
  327. return {begin(), end()};
  328. }
  329. private:
  330. const TStorage& Ref;
  331. };
  332. } // namespace NDetail
  333. } // namespace NEnumSerializationRuntime