Home | History | Annotate | Download | only in flatbuffers
      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 inline bool IsScalar(reflection::BaseType t) {
     34   return t >= reflection::UType && t <= reflection::Double;
     35 }
     36 inline bool IsInteger(reflection::BaseType t) {
     37   return t >= reflection::UType && t <= reflection::ULong;
     38 }
     39 inline bool IsFloat(reflection::BaseType t) {
     40   return t == reflection::Float || t == reflection::Double;
     41 }
     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.
     47 inline 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.
     55 inline 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.
     66 inline Table *GetAnyRoot(uint8_t *flatbuf) {
     67   return GetMutableRoot<Table>(flatbuf);
     68 }
     69 inline 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.
     74 template<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.
     80 template<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.
     86 template<typename T>
     87 T 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.
     94 template<typename T>
     95 T 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.
    102 inline 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.
    109 template<typename T>
    110 Vector<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.
    119 inline 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.
    125 inline 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.
    132 inline 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.
    141 inline 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.
    151 int64_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.
    154 double 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.
    157 std::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.
    161 inline 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.
    169 inline double GetAnyFieldF(const Table &table, const reflection::Field &field) {
    170   auto field_ptr = table.GetAddressOf(field.offset());
    171   return field_ptr ? GetAnyValueF(field.type()->base_type(), field_ptr)
    172                    : field.default_real();
    173 }
    174 
    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.
    178 inline 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.
    188 inline 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.
    194 inline 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.
    200 inline 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.
    207 inline 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.
    213 inline 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.
    219 inline 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.
    228 template<typename T>
    229 T *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).
    239 template<typename T>
    240 T *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.
    246 template<typename T>
    247 T *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.
    252 template<typename T>
    253 T *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.
    260 template<typename T>
    261 bool 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.
    279 void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val);
    280 void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val);
    281 void 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.
    284 inline 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.
    293 inline 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.
    302 inline 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.
    311 inline 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.
    318 inline 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.
    325 inline 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.
    332 inline 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.
    338 inline 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.
    344 inline 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.
    353 template<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.
    373 template<typename T, typename U>
    374 pointer_inside_vector<T, U> piv(T *ptr, std::vector<U> &vec) {
    375   return pointer_inside_vector<T, U>(ptr, vec);
    376 }
    377 
    378 inline const char *UnionTypeFieldSuffix() { return "_type"; }
    379 
    380 // Helper to figure out the actual table type a union refers to.
    381 inline 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.
    399 void 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.
    408 uint8_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 
    413 template<typename T>
    414 void 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.
    441 const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
    442                              const uint8_t *newbuf, size_t newlen);
    443 
    444 inline 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 
    462 Offset<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.
    472 bool 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_
    478