traits.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. #pragma once
  2. #include <util/generic/typetraits.h>
  3. #include <google/protobuf/descriptor.h>
  4. #include <google/protobuf/message.h>
  5. namespace NProtoBuf {
  6. // this nasty windows.h macro interfers with protobuf::Reflection::GetMessage()
  7. #if defined(GetMessage)
  8. #undef GetMessage
  9. #endif
  10. struct TCppTypeTraitsBase {
  11. static inline bool Has(const Message& msg, const FieldDescriptor* field) { // non-repeated
  12. return msg.GetReflection()->HasField(msg, field);
  13. }
  14. static inline size_t Size(const Message& msg, const FieldDescriptor* field) { // repeated
  15. return msg.GetReflection()->FieldSize(msg, field);
  16. }
  17. static inline void Clear(Message& msg, const FieldDescriptor* field) {
  18. msg.GetReflection()->ClearField(&msg, field);
  19. }
  20. static inline void RemoveLast(Message& msg, const FieldDescriptor* field) {
  21. msg.GetReflection()->RemoveLast(&msg, field);
  22. }
  23. static inline void SwapElements(Message& msg, const FieldDescriptor* field, int index1, int index2) {
  24. msg.GetReflection()->SwapElements(&msg, field, index1, index2);
  25. }
  26. };
  27. // default value accessor
  28. template <FieldDescriptor::CppType cpptype>
  29. struct TCppTypeTraitsDefault;
  30. #define DECLARE_CPPTYPE_DEFAULT(cpptype, method) \
  31. template <> \
  32. struct TCppTypeTraitsDefault<cpptype> { \
  33. static auto GetDefault(const FieldDescriptor* fd) \
  34. -> decltype(fd->default_value_##method()) { \
  35. Y_ASSERT(fd); \
  36. return fd->default_value_##method(); \
  37. } \
  38. }
  39. DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_INT32, int32);
  40. DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_INT64, int64);
  41. DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_UINT32, uint32);
  42. DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_UINT64, uint64);
  43. DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_FLOAT, float);
  44. DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_DOUBLE, double);
  45. DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_BOOL, bool);
  46. DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_ENUM, enum);
  47. DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_STRING, string);
  48. #undef DECLARE_CPPTYPE_DEFAULT
  49. // getters/setters of field with specified CppType
  50. template <FieldDescriptor::CppType cpptype>
  51. struct TCppTypeTraits : TCppTypeTraitsBase {
  52. static const FieldDescriptor::CppType CppType = cpptype;
  53. struct T {};
  54. static T Get(const Message& msg, const FieldDescriptor* field);
  55. static T GetRepeated(const Message& msg, const FieldDescriptor* field, int index);
  56. static T GetDefault(const FieldDescriptor* field);
  57. static void Set(Message& msg, const FieldDescriptor* field, T value);
  58. static void AddRepeated(Message& msg, const FieldDescriptor* field, T value);
  59. static void SetRepeated(Message& msg, const FieldDescriptor* field, int index, T value);
  60. };
  61. // any type T -> CppType
  62. template <typename T>
  63. struct TSelectCppType {
  64. //static const FieldDescriptor::CppType Result = FieldDescriptor::MAX_CPPTYPE;
  65. };
  66. #define DECLARE_CPPTYPE_TRAITS(cpptype, type, method) \
  67. template <> \
  68. struct TCppTypeTraits<cpptype>: public TCppTypeTraitsBase { \
  69. typedef type T; \
  70. static const FieldDescriptor::CppType CppType = cpptype; \
  71. \
  72. static inline T Get(const Message& msg, const FieldDescriptor* field) { \
  73. return msg.GetReflection()->Get##method(msg, field); \
  74. } \
  75. static inline T GetRepeated(const Message& msg, const FieldDescriptor* field, int index) { \
  76. return msg.GetReflection()->GetRepeated##method(msg, field, index); \
  77. } \
  78. static inline T GetDefault(const FieldDescriptor* field) { \
  79. return TCppTypeTraitsDefault<cpptype>::GetDefault(field); \
  80. } \
  81. static inline void Set(Message& msg, const FieldDescriptor* field, T value) { \
  82. msg.GetReflection()->Set##method(&msg, field, value); \
  83. } \
  84. static inline void AddRepeated(Message& msg, const FieldDescriptor* field, T value) { \
  85. msg.GetReflection()->Add##method(&msg, field, value); \
  86. } \
  87. static inline void SetRepeated(Message& msg, const FieldDescriptor* field, int index, T value) { \
  88. msg.GetReflection()->SetRepeated##method(&msg, field, index, value); \
  89. } \
  90. }; \
  91. template <> \
  92. struct TSelectCppType<type> { \
  93. static const FieldDescriptor::CppType Result = cpptype; \
  94. typedef type T; \
  95. }
  96. DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_INT32, i32, Int32);
  97. DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_INT64, i64, Int64);
  98. DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_UINT32, ui32, UInt32);
  99. DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_UINT64, ui64, UInt64);
  100. DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_DOUBLE, double, Double);
  101. DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_FLOAT, float, Float);
  102. DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_BOOL, bool, Bool);
  103. DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_ENUM, const EnumValueDescriptor*, Enum);
  104. DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_STRING, TString, String);
  105. //DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_MESSAGE, const Message&, Message);
  106. #undef DECLARE_CPPTYPE_TRAITS
  107. // specialization for message pointer
  108. template <>
  109. struct TCppTypeTraits<FieldDescriptor::CPPTYPE_MESSAGE>: public TCppTypeTraitsBase {
  110. typedef const Message* T;
  111. static const FieldDescriptor::CppType CppType = FieldDescriptor::CPPTYPE_MESSAGE;
  112. static inline T Get(const Message& msg, const FieldDescriptor* field) {
  113. return &(msg.GetReflection()->GetMessage(msg, field));
  114. }
  115. static inline T GetRepeated(const Message& msg, const FieldDescriptor* field, int index) {
  116. return &(msg.GetReflection()->GetRepeatedMessage(msg, field, index));
  117. }
  118. static inline Message* Set(Message& msg, const FieldDescriptor* field, const Message* value) {
  119. Message* ret = msg.GetReflection()->MutableMessage(&msg, field);
  120. ret->CopyFrom(*value);
  121. return ret;
  122. }
  123. static inline Message* AddRepeated(Message& msg, const FieldDescriptor* field, const Message* value) {
  124. Message* ret = msg.GetReflection()->AddMessage(&msg, field);
  125. ret->CopyFrom(*value);
  126. return ret;
  127. }
  128. static inline Message* SetRepeated(Message& msg, const FieldDescriptor* field, int index, const Message* value) {
  129. Message* ret = msg.GetReflection()->MutableRepeatedMessage(&msg, field, index);
  130. ret->CopyFrom(*value);
  131. return ret;
  132. }
  133. };
  134. template <>
  135. struct TSelectCppType<const Message*> {
  136. static const FieldDescriptor::CppType Result = FieldDescriptor::CPPTYPE_MESSAGE;
  137. typedef const Message* T;
  138. };
  139. template <>
  140. struct TSelectCppType<Message> {
  141. static const FieldDescriptor::CppType Result = FieldDescriptor::CPPTYPE_MESSAGE;
  142. typedef const Message* T;
  143. };
  144. template <FieldDescriptor::CppType CppType, bool Repeated>
  145. struct TFieldTraits {
  146. typedef TCppTypeTraits<CppType> TBaseTraits;
  147. typedef typename TBaseTraits::T T;
  148. static inline T Get(const Message& msg, const FieldDescriptor* field, size_t index = 0) {
  149. Y_ASSERT(index == 0);
  150. return TBaseTraits::Get(msg, field);
  151. }
  152. static inline T GetDefault(const FieldDescriptor* field) {
  153. return TBaseTraits::GetDefault(field);
  154. }
  155. static inline bool Has(const Message& msg, const FieldDescriptor* field) {
  156. return TBaseTraits::Has(msg, field);
  157. }
  158. static inline size_t Size(const Message& msg, const FieldDescriptor* field) {
  159. return Has(msg, field);
  160. }
  161. static inline void Set(Message& msg, const FieldDescriptor* field, T value, size_t index = 0) {
  162. Y_ASSERT(index == 0);
  163. TBaseTraits::Set(msg, field, value);
  164. }
  165. static inline void Add(Message& msg, const FieldDescriptor* field, T value) {
  166. TBaseTraits::Set(msg, field, value);
  167. }
  168. };
  169. template <FieldDescriptor::CppType CppType>
  170. struct TFieldTraits<CppType, true> {
  171. typedef TCppTypeTraits<CppType> TBaseTraits;
  172. typedef typename TBaseTraits::T T;
  173. static inline T Get(const Message& msg, const FieldDescriptor* field, size_t index = 0) {
  174. return TBaseTraits::GetRepeated(msg, field, index);
  175. }
  176. static inline T GetDefault(const FieldDescriptor* field) {
  177. return TBaseTraits::GetDefault(field);
  178. }
  179. static inline size_t Size(const Message& msg, const FieldDescriptor* field) {
  180. return TBaseTraits::Size(msg, field);
  181. }
  182. static inline bool Has(const Message& msg, const FieldDescriptor* field) {
  183. return Size(msg, field) > 0;
  184. }
  185. static inline void Set(Message& msg, const FieldDescriptor* field, T value, size_t index = 0) {
  186. TBaseTraits::SetRepeated(msg, field, index, value);
  187. }
  188. static inline void Add(Message& msg, const FieldDescriptor* field, T value) {
  189. TBaseTraits::AddRepeated(msg, field, value);
  190. }
  191. };
  192. // Simpler interface at the cost of checking is_repeated() on each call
  193. template <FieldDescriptor::CppType CppType>
  194. struct TSimpleFieldTraits {
  195. typedef TFieldTraits<CppType, true> TRepeated;
  196. typedef TFieldTraits<CppType, false> TSingle;
  197. typedef typename TRepeated::T T;
  198. static inline size_t Size(const Message& msg, const FieldDescriptor* field) {
  199. if (field->is_repeated())
  200. return TRepeated::Size(msg, field);
  201. else
  202. return TSingle::Size(msg, field);
  203. }
  204. static inline bool Has(const Message& msg, const FieldDescriptor* field) {
  205. if (field->is_repeated())
  206. return TRepeated::Has(msg, field);
  207. else
  208. return TSingle::Has(msg, field);
  209. }
  210. static inline T Get(const Message& msg, const FieldDescriptor* field, size_t index = 0) {
  211. Y_ASSERT(index < Size(msg, field) || !field->is_repeated() && index == 0); // Get for single fields is always allowed because of default values
  212. if (field->is_repeated())
  213. return TRepeated::Get(msg, field, index);
  214. else
  215. return TSingle::Get(msg, field, index);
  216. }
  217. static inline T GetDefault(const FieldDescriptor* field) {
  218. return TSingle::GetDefault(field);
  219. }
  220. static inline void Set(Message& msg, const FieldDescriptor* field, T value, size_t index = 0) {
  221. Y_ASSERT(!field->is_repeated() && index == 0 || index < Size(msg, field));
  222. if (field->is_repeated())
  223. TRepeated::Set(msg, field, value, index);
  224. else
  225. TSingle::Set(msg, field, value, index);
  226. }
  227. static inline void Add(Message& msg, const FieldDescriptor* field, T value) {
  228. if (field->is_repeated())
  229. TRepeated::Add(msg, field, value);
  230. else
  231. TSingle::Add(msg, field, value);
  232. }
  233. };
  234. // some cpp-type groups
  235. template <FieldDescriptor::CppType CppType>
  236. struct TIsIntegerCppType {
  237. enum {
  238. Result = CppType == FieldDescriptor::CPPTYPE_INT32 ||
  239. CppType == FieldDescriptor::CPPTYPE_INT64 ||
  240. CppType == FieldDescriptor::CPPTYPE_UINT32 ||
  241. CppType == FieldDescriptor::CPPTYPE_UINT64
  242. };
  243. };
  244. template <FieldDescriptor::CppType CppType>
  245. struct TIsFloatCppType {
  246. enum {
  247. Result = CppType == FieldDescriptor::CPPTYPE_FLOAT ||
  248. CppType == FieldDescriptor::CPPTYPE_DOUBLE
  249. };
  250. };
  251. template <FieldDescriptor::CppType CppType>
  252. struct TIsNumericCppType {
  253. enum {
  254. Result = CppType == FieldDescriptor::CPPTYPE_BOOL ||
  255. TIsIntegerCppType<CppType>::Result ||
  256. TIsFloatCppType<CppType>::Result
  257. };
  258. };
  259. // a helper macro for splitting flow by cpp-type (e.g. in a switch)
  260. #define APPLY_TMP_MACRO_FOR_ALL_CPPTYPES() \
  261. TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_INT32) \
  262. TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_INT64) \
  263. TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_UINT32) \
  264. TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_UINT64) \
  265. TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_DOUBLE) \
  266. TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_FLOAT) \
  267. TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_BOOL) \
  268. TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_ENUM) \
  269. TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_STRING) \
  270. TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_MESSAGE)
  271. }