reflection.h 21 KB

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