xdecoder.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /*
  2. * Copyright (C) 2021 Duowan Inc. All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing,
  11. * software distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #ifndef __X_PACK_DECODER_H
  17. #define __X_PACK_DECODER_H
  18. #include <stdexcept>
  19. #include <map>
  20. #include <set>
  21. #include <vector>
  22. #include <list>
  23. #include "extend.h"
  24. #include "traits.h"
  25. #include "xtype.h"
  26. #include "string.h"
  27. #ifdef XPACK_SUPPORT_QT
  28. #include <QString>
  29. #include <QList>
  30. #include <QMap>
  31. #include <QVector>
  32. #endif
  33. #ifdef X_PACK_SUPPORT_CXX0X
  34. #include <memory>
  35. #include <unordered_map>
  36. #endif
  37. namespace xpack {
  38. /*
  39. DOC need implement:
  40. const char *Type() const; "json/bson/...."
  41. Iterator;
  42. Begin(); return iter;
  43. End(); iter next;
  44. operator bool;
  45. size_t Size() const; if doc is array, return array size;
  46. */
  47. template<class DOC>
  48. class XDecoder {
  49. protected:
  50. typedef DOC doc_type;
  51. typedef XDecoder<DOC> xdoc_type;
  52. struct KeyConverter{
  53. static inline bool toString(const char *key, std::string &k) {
  54. k = key;
  55. return true;
  56. }
  57. #ifdef XPACK_SUPPORT_QT
  58. static inline bool toQString(const char*key, QString &k) {
  59. k = key;
  60. return true;
  61. }
  62. #endif
  63. };
  64. public:
  65. // only c++0x support reference initialize, so use pointer
  66. XDecoder(const doc_type *parent, const char* key) {
  67. init_base(parent, key);
  68. }
  69. XDecoder(const doc_type *parent, size_t index) {
  70. init_base(parent, index);
  71. }
  72. ~XDecoder(){}
  73. public:
  74. // for array
  75. template <class T, size_t N>
  76. inline bool decode(const char*key, T (&val)[N], const Extend *ext) {
  77. return this->decode(key, val, N, ext);
  78. }
  79. template <class T>
  80. bool decode(const char *key, T *val, size_t N, const Extend *ext) {
  81. doc_type tmp;
  82. doc_type *obj = find(key, &tmp, ext);
  83. if (NULL == obj) {
  84. return false;
  85. }
  86. size_t mx = obj->Size();
  87. mx = mx>N?N:mx;
  88. doc_type sub;
  89. for (size_t i=0; i<mx; ++i) {
  90. obj->member(i, sub).decode(NULL, val[i], ext);
  91. }
  92. return true;
  93. }
  94. // char[] is special
  95. bool decode(const char*key, char* val, size_t N, const Extend *ext) {
  96. std::string str;
  97. bool ret = ((doc_type*)this)->decode(key, str, ext);
  98. if (ret) {
  99. size_t mx = str.length();
  100. mx = mx>N-1?N-1:mx;
  101. strncpy(val, str.data(), mx);
  102. val[mx] = '\0';
  103. }
  104. return ret;
  105. }
  106. // vector
  107. template <class T>
  108. inline bool decode(const char*key, std::vector<T> &val, const Extend *ext) {
  109. return this->decode_vector(key, val, ext);
  110. }
  111. // list
  112. template <class T>
  113. bool decode(const char*key, std::list<T> &val, const Extend *ext) {
  114. return this->decode_list<std::list<T>, T>(key, val, ext);
  115. }
  116. // set
  117. template <class T>
  118. bool decode(const char*key, std::set<T> &val, const Extend *ext) {
  119. doc_type tmp;
  120. doc_type *obj = find(key, &tmp, ext);
  121. if (NULL == obj) {
  122. return false;
  123. }
  124. doc_type sub;
  125. size_t s = obj->Size();
  126. for (size_t i=0; i<s; ++i) {
  127. T _t;
  128. obj->member(i, sub).decode(NULL, _t, ext);
  129. val.insert(_t);
  130. }
  131. return true;
  132. }
  133. // map
  134. template <class T>
  135. bool decode(const char*key, std::map<std::string,T> &val, const Extend *ext) {
  136. return decode_map<std::map<std::string,T>, std::string, T>(key, val, ext, KeyConverter::toString);
  137. }
  138. // class/struct that defined macro XPACK, !is_xpack_out to avoid inherit __x_pack_value
  139. template <class T>
  140. typename x_enable_if<T::__x_pack_value&&!is_xpack_out<T>::value, bool>::type decode(const char*key, T& val, const Extend *ext) {
  141. doc_type tmp;
  142. doc_type *obj = find(key, &tmp, ext);
  143. if (NULL == obj) {
  144. return false;
  145. }
  146. val.__x_pack_decode(*obj, val, ext);
  147. return true;
  148. }
  149. // class/struct that defined macro XPACK_OUT
  150. template <class T>
  151. typename x_enable_if<is_xpack_out<T>::value, bool>::type decode(const char*key, T& val, const Extend *ext) {
  152. doc_type tmp;
  153. doc_type *obj = find(key, &tmp, ext);
  154. if (NULL == obj) {
  155. return false;
  156. }
  157. __x_pack_decode_out(*obj, val, ext);
  158. return true;
  159. }
  160. // XType. add && !is_xpack_out<T>::value to fix SFINAE bug of vs2005
  161. template <class T>
  162. inline typename x_enable_if<is_xpack_xtype<T>::value && !is_xpack_out<T>::value, bool>::type decode(const char*key, T& val, const Extend *ext) {
  163. return xpack_xtype_decode(*(doc_type*)this, key, val, ext);
  164. }
  165. #ifdef X_PACK_SUPPORT_CXX0X
  166. // unordered_map
  167. template <class T>
  168. inline bool decode(const char*key, std::unordered_map<std::string, T> &val, const Extend *ext) {
  169. return decode_map<std::unordered_map<std::string,T>, std::string, T>(key, val, ext, KeyConverter::toString);
  170. }
  171. // shared_ptr
  172. template <class T>
  173. bool decode(const char*key, std::shared_ptr<T>& val, const Extend *ext) {
  174. if (NULL == val.get()) {
  175. val.reset(new T);
  176. }
  177. bool ret = ((doc_type*)this)->decode(key, *val, ext);
  178. if (!ret) {
  179. val.reset();
  180. }
  181. return ret;
  182. }
  183. // enum is_enum implementation is too complicated, so in c++03, we use macro E
  184. template <class T>
  185. inline typename x_enable_if<std::is_enum<T>::value, bool>::type decode(const char*key, T& val, const Extend *ext) {
  186. return ((doc_type*)this)->decode(key, *((int*)&val), ext);
  187. }
  188. #endif
  189. #ifdef XPACK_SUPPORT_QT
  190. bool decode(const char*key, QString &val, const Extend *ext) {
  191. std::string str;
  192. bool ret = ((doc_type*)this)->decode(key, str, ext);
  193. if (ret) {
  194. val = QString::fromStdString(str);
  195. }
  196. return ret;
  197. }
  198. template<typename T>
  199. inline bool decode(const char*key, QList<T> &val, const Extend *ext) {
  200. return this->decode_list<QList<T>, T>(key, val, ext);
  201. }
  202. template<typename T>
  203. inline bool decode(const char*key, QVector<T> &val, const Extend *ext) {
  204. return this->decode_vector(key, val, ext);
  205. }
  206. template<typename T>
  207. inline bool decode(const char*key, QMap<std::string, T> &val, const Extend *ext) {
  208. return decode_map<QMap<std::string,T>, std::string, T>(key, val, ext, KeyConverter::toString);
  209. }
  210. template<typename T>
  211. inline bool decode(const char*key, QMap<QString, T> &val, const Extend *ext) {
  212. return decode_map<QMap<QString,T>, QString, T>(key, val, ext, KeyConverter::toQString);
  213. }
  214. #endif
  215. protected:
  216. // vector
  217. template <class Vector>
  218. bool decode_vector(const char*key, Vector &val, const Extend *ext) {
  219. doc_type tmp;
  220. doc_type *obj = find(key, &tmp, ext);
  221. if (NULL == obj) {
  222. return false;
  223. }
  224. doc_type sub;
  225. size_t s = obj->Size();
  226. val.resize(s);
  227. for (size_t i=0; i<s; ++i) {
  228. obj->member(i, sub).decode(NULL, val[i], ext);
  229. }
  230. return true;
  231. }
  232. // list
  233. template <class List, class Elem>
  234. bool decode_list(const char*key, List &val, const Extend *ext) {
  235. doc_type tmp;
  236. doc_type *obj = find(key, &tmp, ext);
  237. if (NULL == obj) {
  238. return false;
  239. }
  240. doc_type sub;
  241. size_t s = obj->Size();
  242. for (size_t i=0; i<s; ++i) {
  243. Elem _t;
  244. obj->member(i, sub).decode(NULL, _t, ext);
  245. val.push_back(_t);
  246. }
  247. return true;
  248. }
  249. // map
  250. template <class Map, class Key, class Value>
  251. bool decode_map(const char*key, Map &val, const Extend *ext, bool (*convert)(const char*, Key&)) {
  252. doc_type tmp;
  253. doc_type *obj = find(key, &tmp, ext);
  254. if (NULL == obj) {
  255. return false;
  256. }
  257. doc_type sub;
  258. for (typename doc_type::Iterator d=obj->Begin(); d!=obj->End(); ++d) {
  259. Key _k;
  260. Value _t;
  261. if (convert(d.Key(), _k) && obj->member(d, sub).decode(NULL, _t, ext)) {
  262. val[_k] = _t;
  263. }
  264. }
  265. return true;
  266. }
  267. protected:
  268. doc_type* find(const char *key, doc_type *tmp, const Extend *ext) {
  269. doc_type *obj = static_cast<doc_type*>(this);
  270. if (NULL != key) {
  271. if (!obj->member(key, *tmp)) {
  272. if (Extend::Mandatory(ext)) {
  273. decode_exception("mandatory key not found", key);
  274. } else {
  275. return NULL;
  276. }
  277. } else {
  278. return tmp;
  279. }
  280. } else {
  281. return obj;
  282. }
  283. return NULL; // for remove warning
  284. }
  285. std::string path() const {
  286. std::vector<std::string> nodes;
  287. const doc_type* tmp = static_cast<const doc_type*>(this);
  288. while (tmp) {
  289. std::string k;
  290. k.reserve(32);
  291. if (NULL != tmp->_key) {
  292. if (NULL!=tmp->_parent && NULL!=tmp->_parent->_parent) {
  293. k.append(".");
  294. }
  295. k.append(tmp->_key);
  296. } else {
  297. k.append("[").append(Util::itoa(tmp->_index)).append("]");
  298. }
  299. nodes.push_back(k);
  300. tmp = tmp->_parent;
  301. }
  302. std::string p;
  303. p.reserve(64);
  304. for (int i=(int)nodes.size()-1; i>=0; --i) {
  305. p.append(nodes[i]);
  306. }
  307. return p;
  308. }
  309. void decode_exception(const char* what, const char *key) const {
  310. std::string err;
  311. err.reserve(128);
  312. if (NULL != what) {
  313. err.append(what);
  314. }
  315. err.append("[");
  316. std::string p = path();
  317. if (!p.empty()) {
  318. err.append(p).append(".");
  319. }
  320. if (NULL != key) {
  321. err.append(key);
  322. }
  323. err.append("]");
  324. throw std::runtime_error(err);
  325. }
  326. doc_type* alloc() {
  327. doc_type *d = new doc_type();
  328. _collector.push_back(d);
  329. return d;
  330. }
  331. void init_base(const doc_type *parent, const char* key) {
  332. _parent = parent;
  333. _key = key;
  334. _index = -1;
  335. }
  336. void init_base(const doc_type *parent, size_t index) {
  337. _parent = parent;
  338. _index = (int)index;
  339. _key = NULL;
  340. }
  341. const doc_type* _parent;
  342. const char* _key;
  343. int _index;
  344. std::vector<doc_type*> _collector;
  345. };
  346. }
  347. #endif