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