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