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