1
0

reflection.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /*
  2. * Copyright 2015 Google 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, software
  11. * 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 FLATBUFFERS_REFLECTION_H_
  17. #define FLATBUFFERS_REFLECTION_H_
  18. // This is somewhat of a circular dependency because flatc (and thus this
  19. // file) is needed to generate this header in the first place.
  20. // Should normally not be a problem since it can be generated by the
  21. // previous version of flatc whenever this code needs to change.
  22. // See reflection/generate_code.sh
  23. #include "flatbuffers/reflection_generated.h"
  24. // Helper functionality for reflection.
  25. namespace flatbuffers {
  26. // ------------------------- GETTERS -------------------------
  27. // Size of a basic type, don't use with structs.
  28. inline size_t GetTypeSize(reflection::BaseType base_type) {
  29. // This needs to correspond to the BaseType enum.
  30. static size_t sizes[] = { 0, 1, 1, 1, 1, 2, 2, 4, 4, 8, 8, 4, 8, 4, 4, 4, 4 };
  31. return sizes[base_type];
  32. }
  33. // Same as above, but now correctly returns the size of a struct if
  34. // the field (or vector element) is a struct.
  35. inline size_t GetTypeSizeInline(reflection::BaseType base_type,
  36. int type_index,
  37. const reflection::Schema &schema) {
  38. if (base_type == reflection::Obj &&
  39. schema.objects()->Get(type_index)->is_struct()) {
  40. return schema.objects()->Get(type_index)->bytesize();
  41. } else {
  42. return GetTypeSize(base_type);
  43. }
  44. }
  45. // Get the root, regardless of what type it is.
  46. inline Table *GetAnyRoot(uint8_t *flatbuf) {
  47. return GetMutableRoot<Table>(flatbuf);
  48. }
  49. inline const Table *GetAnyRoot(const uint8_t *flatbuf) {
  50. return GetRoot<Table>(flatbuf);
  51. }
  52. // Get a field, if you know it's an integer, and its exact type.
  53. template<typename T> T GetFieldI(const Table &table,
  54. const reflection::Field &field) {
  55. assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
  56. return table.GetField<T>(field.offset(),
  57. static_cast<T>(field.default_integer()));
  58. }
  59. // Get a field, if you know it's floating point and its exact type.
  60. template<typename T> T GetFieldF(const Table &table,
  61. const reflection::Field &field) {
  62. assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
  63. return table.GetField<T>(field.offset(),
  64. static_cast<T>(field.default_real()));
  65. }
  66. // Get a field, if you know it's a string.
  67. inline const String *GetFieldS(const Table &table,
  68. const reflection::Field &field) {
  69. assert(field.type()->base_type() == reflection::String);
  70. return table.GetPointer<const String *>(field.offset());
  71. }
  72. // Get a field, if you know it's a vector.
  73. template<typename T> Vector<T> *GetFieldV(const Table &table,
  74. const reflection::Field &field) {
  75. assert(field.type()->base_type() == reflection::Vector &&
  76. sizeof(T) == GetTypeSize(field.type()->element()));
  77. return table.GetPointer<Vector<T> *>(field.offset());
  78. }
  79. // Get a field, if you know it's a vector, generically.
  80. // To actually access elements, use the return value together with
  81. // field.type()->element() in any of GetAnyVectorElemI below etc.
  82. inline VectorOfAny *GetFieldAnyV(const Table &table,
  83. const reflection::Field &field) {
  84. return table.GetPointer<VectorOfAny *>(field.offset());
  85. }
  86. // Get a field, if you know it's a table.
  87. inline Table *GetFieldT(const Table &table,
  88. const reflection::Field &field) {
  89. assert(field.type()->base_type() == reflection::Obj ||
  90. field.type()->base_type() == reflection::Union);
  91. return table.GetPointer<Table *>(field.offset());
  92. }
  93. // Get a field, if you know it's a struct.
  94. inline const Struct *GetFieldStruct(const Table &table,
  95. const reflection::Field &field) {
  96. // TODO: This does NOT check if the field is a table or struct, but we'd need
  97. // access to the schema to check the is_struct flag.
  98. assert(field.type()->base_type() == reflection::Obj);
  99. return table.GetStruct<const Struct *>(field.offset());
  100. }
  101. // Get a structure's field, if you know it's a struct.
  102. inline const Struct *GetFieldStruct(const Struct &structure,
  103. const reflection::Field &field) {
  104. assert(field.type()->base_type() == reflection::Obj);
  105. return structure.GetStruct<const Struct *>(field.offset());
  106. }
  107. // Raw helper functions used below: get any value in memory as a 64bit int, a
  108. // double or a string.
  109. // All scalars get static_cast to an int64_t, strings use strtoull, every other
  110. // data type returns 0.
  111. int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data);
  112. // All scalars static cast to double, strings use strtod, every other data
  113. // type is 0.0.
  114. double GetAnyValueF(reflection::BaseType type, const uint8_t *data);
  115. // All scalars converted using stringstream, strings as-is, and all other
  116. // data types provide some level of debug-pretty-printing.
  117. std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
  118. const reflection::Schema *schema,
  119. int type_index);
  120. // Get any table field as a 64bit int, regardless of what type it is.
  121. inline int64_t GetAnyFieldI(const Table &table,
  122. const reflection::Field &field) {
  123. auto field_ptr = table.GetAddressOf(field.offset());
  124. return field_ptr ? GetAnyValueI(field.type()->base_type(), field_ptr)
  125. : field.default_integer();
  126. }
  127. // Get any table field as a double, regardless of what type it is.
  128. inline double GetAnyFieldF(const Table &table,
  129. const reflection::Field &field) {
  130. auto field_ptr = table.GetAddressOf(field.offset());
  131. return field_ptr ? GetAnyValueF(field.type()->base_type(), field_ptr)
  132. : field.default_real();
  133. }
  134. // Get any table field as a string, regardless of what type it is.
  135. // You may pass nullptr for the schema if you don't care to have fields that
  136. // are of table type pretty-printed.
  137. inline std::string GetAnyFieldS(const Table &table,
  138. const reflection::Field &field,
  139. const reflection::Schema *schema) {
  140. auto field_ptr = table.GetAddressOf(field.offset());
  141. return field_ptr ? GetAnyValueS(field.type()->base_type(), field_ptr, schema,
  142. field.type()->index())
  143. : "";
  144. }
  145. // Get any struct field as a 64bit int, regardless of what type it is.
  146. inline int64_t GetAnyFieldI(const Struct &st,
  147. const reflection::Field &field) {
  148. return GetAnyValueI(field.type()->base_type(),
  149. st.GetAddressOf(field.offset()));
  150. }
  151. // Get any struct field as a double, regardless of what type it is.
  152. inline double GetAnyFieldF(const Struct &st,
  153. const reflection::Field &field) {
  154. return GetAnyValueF(field.type()->base_type(),
  155. st.GetAddressOf(field.offset()));
  156. }
  157. // Get any struct field as a string, regardless of what type it is.
  158. inline std::string GetAnyFieldS(const Struct &st,
  159. const reflection::Field &field) {
  160. return GetAnyValueS(field.type()->base_type(),
  161. st.GetAddressOf(field.offset()), nullptr, -1);
  162. }
  163. // Get any vector element as a 64bit int, regardless of what type it is.
  164. inline int64_t GetAnyVectorElemI(const VectorOfAny *vec,
  165. reflection::BaseType elem_type, size_t i) {
  166. return GetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
  167. }
  168. // Get any vector element as a double, regardless of what type it is.
  169. inline double GetAnyVectorElemF(const VectorOfAny *vec,
  170. reflection::BaseType elem_type, size_t i) {
  171. return GetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
  172. }
  173. // Get any vector element as a string, regardless of what type it is.
  174. inline std::string GetAnyVectorElemS(const VectorOfAny *vec,
  175. reflection::BaseType elem_type, size_t i) {
  176. return GetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i,
  177. nullptr, -1);
  178. }
  179. // Get a vector element that's a table/string/vector from a generic vector.
  180. // Pass Table/String/VectorOfAny as template parameter.
  181. // Warning: does no typechecking.
  182. template<typename T> T *GetAnyVectorElemPointer(const VectorOfAny *vec,
  183. size_t i) {
  184. auto elem_ptr = vec->Data() + sizeof(uoffset_t) * i;
  185. return (T *)(elem_ptr + ReadScalar<uoffset_t>(elem_ptr));
  186. }
  187. // Get the inline-address of a vector element. Useful for Structs (pass Struct
  188. // as template arg), or being able to address a range of scalars in-line.
  189. // Get elem_size from GetTypeSizeInline().
  190. // Note: little-endian data on all platforms, use EndianScalar() instead of
  191. // raw pointer access with scalars).
  192. template<typename T> T *GetAnyVectorElemAddressOf(const VectorOfAny *vec,
  193. size_t i,
  194. size_t elem_size) {
  195. // C-cast to allow const conversion.
  196. return (T *)(vec->Data() + elem_size * i);
  197. }
  198. // Similarly, for elements of tables.
  199. template<typename T> T *GetAnyFieldAddressOf(const Table &table,
  200. const reflection::Field &field) {
  201. return (T *)table.GetAddressOf(field.offset());
  202. }
  203. // Similarly, for elements of structs.
  204. template<typename T> T *GetAnyFieldAddressOf(const Struct &st,
  205. const reflection::Field &field) {
  206. return (T *)st.GetAddressOf(field.offset());
  207. }
  208. // ------------------------- SETTERS -------------------------
  209. // Set any scalar field, if you know its exact type.
  210. template<typename T> bool SetField(Table *table, const reflection::Field &field,
  211. T val) {
  212. assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
  213. return table->SetField(field.offset(), val);
  214. }
  215. // Raw helper functions used below: set any value in memory as a 64bit int, a
  216. // double or a string.
  217. // These work for all scalar values, but do nothing for other data types.
  218. // To set a string, see SetString below.
  219. void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val);
  220. void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val);
  221. void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val);
  222. // Set any table field as a 64bit int, regardless of type what it is.
  223. inline bool SetAnyFieldI(Table *table, const reflection::Field &field,
  224. int64_t val) {
  225. auto field_ptr = table->GetAddressOf(field.offset());
  226. if (!field_ptr) return false;
  227. SetAnyValueI(field.type()->base_type(), field_ptr, val);
  228. return true;
  229. }
  230. // Set any table field as a double, regardless of what type it is.
  231. inline bool SetAnyFieldF(Table *table, const reflection::Field &field,
  232. double val) {
  233. auto field_ptr = table->GetAddressOf(field.offset());
  234. if (!field_ptr) return false;
  235. SetAnyValueF(field.type()->base_type(), field_ptr, val);
  236. return true;
  237. }
  238. // Set any table field as a string, regardless of what type it is.
  239. inline bool SetAnyFieldS(Table *table, const reflection::Field &field,
  240. const char *val) {
  241. auto field_ptr = table->GetAddressOf(field.offset());
  242. if (!field_ptr) return false;
  243. SetAnyValueS(field.type()->base_type(), field_ptr, val);
  244. return true;
  245. }
  246. // Set any struct field as a 64bit int, regardless of type what it is.
  247. inline void SetAnyFieldI(Struct *st, const reflection::Field &field,
  248. int64_t val) {
  249. SetAnyValueI(field.type()->base_type(), st->GetAddressOf(field.offset()),
  250. val);
  251. }
  252. // Set any struct field as a double, regardless of type what it is.
  253. inline void SetAnyFieldF(Struct *st, const reflection::Field &field,
  254. double val) {
  255. SetAnyValueF(field.type()->base_type(), st->GetAddressOf(field.offset()),
  256. val);
  257. }
  258. // Set any struct field as a string, regardless of type what it is.
  259. inline void SetAnyFieldS(Struct *st, const reflection::Field &field,
  260. const char *val) {
  261. SetAnyValueS(field.type()->base_type(), st->GetAddressOf(field.offset()),
  262. val);
  263. }
  264. // Set any vector element as a 64bit int, regardless of type what it is.
  265. inline void SetAnyVectorElemI(VectorOfAny *vec, reflection::BaseType elem_type,
  266. size_t i, int64_t val) {
  267. SetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
  268. }
  269. // Set any vector element as a double, regardless of type what it is.
  270. inline void SetAnyVectorElemF(VectorOfAny *vec, reflection::BaseType elem_type,
  271. size_t i, double val) {
  272. SetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
  273. }
  274. // Set any vector element as a string, regardless of type what it is.
  275. inline void SetAnyVectorElemS(VectorOfAny *vec, reflection::BaseType elem_type,
  276. size_t i, const char *val) {
  277. SetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
  278. }
  279. // ------------------------- RESIZING SETTERS -------------------------
  280. // "smart" pointer for use with resizing vectors: turns a pointer inside
  281. // a vector into a relative offset, such that it is not affected by resizes.
  282. template<typename T, typename U> class pointer_inside_vector {
  283. public:
  284. pointer_inside_vector(T *ptr, std::vector<U> &vec)
  285. : offset_(reinterpret_cast<uint8_t *>(ptr) -
  286. reinterpret_cast<uint8_t *>(vec.data())),
  287. vec_(vec) {}
  288. T *operator*() const {
  289. return reinterpret_cast<T *>(
  290. reinterpret_cast<uint8_t *>(vec_.data()) + offset_);
  291. }
  292. T *operator->() const {
  293. return operator*();
  294. }
  295. void operator=(const pointer_inside_vector &piv);
  296. private:
  297. size_t offset_;
  298. std::vector<U> &vec_;
  299. };
  300. // Helper to create the above easily without specifying template args.
  301. template<typename T, typename U> pointer_inside_vector<T, U> piv(T *ptr,
  302. std::vector<U> &vec) {
  303. return pointer_inside_vector<T, U>(ptr, vec);
  304. }
  305. inline const char *UnionTypeFieldSuffix() { return "_type"; }
  306. // Helper to figure out the actual table type a union refers to.
  307. inline const reflection::Object &GetUnionType(
  308. const reflection::Schema &schema, const reflection::Object &parent,
  309. const reflection::Field &unionfield, const Table &table) {
  310. auto enumdef = schema.enums()->Get(unionfield.type()->index());
  311. // TODO: this is clumsy and slow, but no other way to find it?
  312. auto type_field = parent.fields()->LookupByKey(
  313. (unionfield.name()->str() + UnionTypeFieldSuffix()).c_str());
  314. assert(type_field);
  315. auto union_type = GetFieldI<uint8_t>(table, *type_field);
  316. auto enumval = enumdef->values()->LookupByKey(union_type);
  317. return *enumval->object();
  318. }
  319. // Changes the contents of a string inside a FlatBuffer. FlatBuffer must
  320. // live inside a std::vector so we can resize the buffer if needed.
  321. // "str" must live inside "flatbuf" and may be invalidated after this call.
  322. // If your FlatBuffer's root table is not the schema's root table, you should
  323. // pass in your root_table type as well.
  324. void SetString(const reflection::Schema &schema, const std::string &val,
  325. const String *str, std::vector<uint8_t> *flatbuf,
  326. const reflection::Object *root_table = nullptr);
  327. // Resizes a flatbuffers::Vector inside a FlatBuffer. FlatBuffer must
  328. // live inside a std::vector so we can resize the buffer if needed.
  329. // "vec" must live inside "flatbuf" and may be invalidated after this call.
  330. // If your FlatBuffer's root table is not the schema's root table, you should
  331. // pass in your root_table type as well.
  332. uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
  333. const VectorOfAny *vec, uoffset_t num_elems,
  334. uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
  335. const reflection::Object *root_table = nullptr);
  336. #ifndef FLATBUFFERS_CPP98_STL
  337. template <typename T>
  338. void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val,
  339. const Vector<T> *vec, std::vector<uint8_t> *flatbuf,
  340. const reflection::Object *root_table = nullptr) {
  341. auto delta_elem = static_cast<int>(newsize) - static_cast<int>(vec->size());
  342. auto newelems = ResizeAnyVector(schema, newsize,
  343. reinterpret_cast<const VectorOfAny *>(vec),
  344. vec->size(),
  345. static_cast<uoffset_t>(sizeof(T)), flatbuf,
  346. root_table);
  347. // Set new elements to "val".
  348. for (int i = 0; i < delta_elem; i++) {
  349. auto loc = newelems + i * sizeof(T);
  350. auto is_scalar = std::is_scalar<T>::value;
  351. if (is_scalar) {
  352. WriteScalar(loc, val);
  353. } else { // struct
  354. *reinterpret_cast<T *>(loc) = val;
  355. }
  356. }
  357. }
  358. #endif
  359. // Adds any new data (in the form of a new FlatBuffer) to an existing
  360. // FlatBuffer. This can be used when any of the above methods are not
  361. // sufficient, in particular for adding new tables and new fields.
  362. // This is potentially slightly less efficient than a FlatBuffer constructed
  363. // in one piece, since the new FlatBuffer doesn't share any vtables with the
  364. // existing one.
  365. // The return value can now be set using Vector::MutateOffset or SetFieldT
  366. // below.
  367. const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
  368. const uint8_t *newbuf, size_t newlen);
  369. inline bool SetFieldT(Table *table, const reflection::Field &field,
  370. const uint8_t *val) {
  371. assert(sizeof(uoffset_t) == GetTypeSize(field.type()->base_type()));
  372. return table->SetPointer(field.offset(), val);
  373. }
  374. // ------------------------- COPYING -------------------------
  375. // Generic copying of tables from a FlatBuffer into a FlatBuffer builder.
  376. // Can be used to do any kind of merging/selecting you may want to do out
  377. // of existing buffers. Also useful to reconstruct a whole buffer if the
  378. // above resizing functionality has introduced garbage in a buffer you want
  379. // to remove.
  380. // Note: this does not deal with DAGs correctly. If the table passed forms a
  381. // DAG, the copy will be a tree instead (with duplicates). Strings can be
  382. // shared however, by passing true for use_string_pooling.
  383. Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
  384. const reflection::Schema &schema,
  385. const reflection::Object &objectdef,
  386. const Table &table,
  387. bool use_string_pooling = false);
  388. // Verifies the provided flatbuffer using reflection.
  389. // root should point to the root type for this flatbuffer.
  390. // buf should point to the start of flatbuffer data.
  391. // length specifies the size of the flatbuffer data.
  392. bool Verify(const reflection::Schema &schema,
  393. const reflection::Object &root,
  394. const uint8_t *buf,
  395. size_t length);
  396. } // namespace flatbuffers
  397. #endif // FLATBUFFERS_REFLECTION_H_