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