Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-08-27 09:30:27

0001 /*
0002  * Copyright 2015 Google Inc. All rights reserved.
0003  *
0004  * Licensed under the Apache License, Version 2.0 (the "License");
0005  * you may not use this file except in compliance with the License.
0006  * You may obtain a copy of the License at
0007  *
0008  *     http://www.apache.org/licenses/LICENSE-2.0
0009  *
0010  * Unless required by applicable law or agreed to in writing, software
0011  * distributed under the License is distributed on an "AS IS" BASIS,
0012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013  * See the License for the specific language governing permissions and
0014  * limitations under the License.
0015  */
0016 
0017 #ifndef FLATBUFFERS_REFLECTION_H_
0018 #define FLATBUFFERS_REFLECTION_H_
0019 
0020 // This is somewhat of a circular dependency because flatc (and thus this
0021 // file) is needed to generate this header in the first place.
0022 // Should normally not be a problem since it can be generated by the
0023 // previous version of flatc whenever this code needs to change.
0024 // See scripts/generate_code.py for generation.
0025 #include "flatbuffers/reflection_generated.h"
0026 
0027 // Helper functionality for reflection.
0028 
0029 namespace flatbuffers {
0030 
0031 // ------------------------- GETTERS -------------------------
0032 
0033 inline bool IsScalar(reflection::BaseType t) {
0034   return t >= reflection::UType && t <= reflection::Double;
0035 }
0036 inline bool IsInteger(reflection::BaseType t) {
0037   return t >= reflection::UType && t <= reflection::ULong;
0038 }
0039 inline bool IsFloat(reflection::BaseType t) {
0040   return t == reflection::Float || t == reflection::Double;
0041 }
0042 inline bool IsLong(reflection::BaseType t) {
0043   return t == reflection::Long || t == reflection::ULong;
0044 }
0045 
0046 // Size of a basic type, don't use with structs.
0047 inline size_t GetTypeSize(reflection::BaseType base_type) {
0048   // This needs to correspond to the BaseType enum.
0049   static size_t sizes[] = {
0050     0,  // None
0051     1,  // UType
0052     1,  // Bool
0053     1,  // Byte
0054     1,  // UByte
0055     2,  // Short
0056     2,  // UShort
0057     4,  // Int
0058     4,  // UInt
0059     8,  // Long
0060     8,  // ULong
0061     4,  // Float
0062     8,  // Double
0063     4,  // String
0064     4,  // Vector
0065     4,  // Obj
0066     4,  // Union
0067     0,  // Array. Only used in structs. 0 was chosen to prevent out-of-bounds
0068         // errors.
0069     8,  // Vector64
0070 
0071     0  // MaxBaseType. This must be kept the last entry in this array.
0072   };
0073   static_assert(sizeof(sizes) / sizeof(size_t) == reflection::MaxBaseType + 1,
0074                 "Size of sizes[] array does not match the count of BaseType "
0075                 "enum values.");
0076   return sizes[base_type];
0077 }
0078 
0079 // Same as above, but now correctly returns the size of a struct if
0080 // the field (or vector element) is a struct.
0081 inline size_t GetTypeSizeInline(reflection::BaseType base_type, int type_index,
0082                                 const reflection::Schema &schema) {
0083   if (base_type == reflection::Obj &&
0084       schema.objects()->Get(type_index)->is_struct()) {
0085     return schema.objects()->Get(type_index)->bytesize();
0086   } else {
0087     return GetTypeSize(base_type);
0088   }
0089 }
0090 
0091 // Get the root, regardless of what type it is.
0092 inline Table *GetAnyRoot(uint8_t *const flatbuf) {
0093   return GetMutableRoot<Table>(flatbuf);
0094 }
0095 
0096 inline const Table *GetAnyRoot(const uint8_t *const flatbuf) {
0097   return GetRoot<Table>(flatbuf);
0098 }
0099 
0100 inline Table *GetAnySizePrefixedRoot(uint8_t *const flatbuf) {
0101   return GetMutableSizePrefixedRoot<Table>(flatbuf);
0102 }
0103 
0104 inline const Table *GetAnySizePrefixedRoot(const uint8_t *const flatbuf) {
0105   return GetSizePrefixedRoot<Table>(flatbuf);
0106 }
0107 
0108 // Get a field's default, if you know it's an integer, and its exact type.
0109 template<typename T> T GetFieldDefaultI(const reflection::Field &field) {
0110   FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
0111   return static_cast<T>(field.default_integer());
0112 }
0113 
0114 // Get a field's default, if you know it's floating point and its exact type.
0115 template<typename T> T GetFieldDefaultF(const reflection::Field &field) {
0116   FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
0117   return static_cast<T>(field.default_real());
0118 }
0119 
0120 // Get a field, if you know it's an integer, and its exact type.
0121 template<typename T>
0122 T GetFieldI(const Table &table, const reflection::Field &field) {
0123   FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
0124   return table.GetField<T>(field.offset(),
0125                            static_cast<T>(field.default_integer()));
0126 }
0127 
0128 // Get a field, if you know it's floating point and its exact type.
0129 template<typename T>
0130 T GetFieldF(const Table &table, const reflection::Field &field) {
0131   FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
0132   return table.GetField<T>(field.offset(),
0133                            static_cast<T>(field.default_real()));
0134 }
0135 
0136 // Get a field, if you know it's a string.
0137 inline const String *GetFieldS(const Table &table,
0138                                const reflection::Field &field) {
0139   FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::String);
0140   return table.GetPointer<const String *>(field.offset());
0141 }
0142 
0143 // Get a field, if you know it's a vector.
0144 template<typename T>
0145 Vector<T> *GetFieldV(const Table &table, const reflection::Field &field) {
0146   FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Vector &&
0147                      sizeof(T) == GetTypeSize(field.type()->element()));
0148   return table.GetPointer<Vector<T> *>(field.offset());
0149 }
0150 
0151 // Get a field, if you know it's a vector, generically.
0152 // To actually access elements, use the return value together with
0153 // field.type()->element() in any of GetAnyVectorElemI below etc.
0154 inline VectorOfAny *GetFieldAnyV(const Table &table,
0155                                  const reflection::Field &field) {
0156   return table.GetPointer<VectorOfAny *>(field.offset());
0157 }
0158 
0159 // Get a field, if you know it's a table.
0160 inline Table *GetFieldT(const Table &table, const reflection::Field &field) {
0161   FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj ||
0162                      field.type()->base_type() == reflection::Union);
0163   return table.GetPointer<Table *>(field.offset());
0164 }
0165 
0166 // Get a field, if you know it's a struct.
0167 inline const Struct *GetFieldStruct(const Table &table,
0168                                     const reflection::Field &field) {
0169   // TODO: This does NOT check if the field is a table or struct, but we'd need
0170   // access to the schema to check the is_struct flag.
0171   FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj);
0172   return table.GetStruct<const Struct *>(field.offset());
0173 }
0174 
0175 // Get a structure's field, if you know it's a struct.
0176 inline const Struct *GetFieldStruct(const Struct &structure,
0177                                     const reflection::Field &field) {
0178   FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj);
0179   return structure.GetStruct<const Struct *>(field.offset());
0180 }
0181 
0182 // Raw helper functions used below: get any value in memory as a 64bit int, a
0183 // double or a string.
0184 // All scalars get static_cast to an int64_t, strings use strtoull, every other
0185 // data type returns 0.
0186 int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data);
0187 // All scalars static cast to double, strings use strtod, every other data
0188 // type is 0.0.
0189 double GetAnyValueF(reflection::BaseType type, const uint8_t *data);
0190 // All scalars converted using stringstream, strings as-is, and all other
0191 // data types provide some level of debug-pretty-printing.
0192 std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
0193                          const reflection::Schema *schema, int type_index);
0194 
0195 // Get any table field as a 64bit int, regardless of what type it is.
0196 inline int64_t GetAnyFieldI(const Table &table,
0197                             const reflection::Field &field) {
0198   auto field_ptr = table.GetAddressOf(field.offset());
0199   return field_ptr ? GetAnyValueI(field.type()->base_type(), field_ptr)
0200                    : field.default_integer();
0201 }
0202 
0203 // Get any table field as a double, regardless of what type it is.
0204 inline double GetAnyFieldF(const Table &table, const reflection::Field &field) {
0205   auto field_ptr = table.GetAddressOf(field.offset());
0206   return field_ptr ? GetAnyValueF(field.type()->base_type(), field_ptr)
0207                    : field.default_real();
0208 }
0209 
0210 // Get any table field as a string, regardless of what type it is.
0211 // You may pass nullptr for the schema if you don't care to have fields that
0212 // are of table type pretty-printed.
0213 inline std::string GetAnyFieldS(const Table &table,
0214                                 const reflection::Field &field,
0215                                 const reflection::Schema *schema) {
0216   auto field_ptr = table.GetAddressOf(field.offset());
0217   return field_ptr ? GetAnyValueS(field.type()->base_type(), field_ptr, schema,
0218                                   field.type()->index())
0219                    : "";
0220 }
0221 
0222 // Get any struct field as a 64bit int, regardless of what type it is.
0223 inline int64_t GetAnyFieldI(const Struct &st, const reflection::Field &field) {
0224   return GetAnyValueI(field.type()->base_type(),
0225                       st.GetAddressOf(field.offset()));
0226 }
0227 
0228 // Get any struct field as a double, regardless of what type it is.
0229 inline double GetAnyFieldF(const Struct &st, const reflection::Field &field) {
0230   return GetAnyValueF(field.type()->base_type(),
0231                       st.GetAddressOf(field.offset()));
0232 }
0233 
0234 // Get any struct field as a string, regardless of what type it is.
0235 inline std::string GetAnyFieldS(const Struct &st,
0236                                 const reflection::Field &field) {
0237   return GetAnyValueS(field.type()->base_type(),
0238                       st.GetAddressOf(field.offset()), nullptr, -1);
0239 }
0240 
0241 // Get any vector element as a 64bit int, regardless of what type it is.
0242 inline int64_t GetAnyVectorElemI(const VectorOfAny *vec,
0243                                  reflection::BaseType elem_type, size_t i) {
0244   return GetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
0245 }
0246 
0247 // Get any vector element as a double, regardless of what type it is.
0248 inline double GetAnyVectorElemF(const VectorOfAny *vec,
0249                                 reflection::BaseType elem_type, size_t i) {
0250   return GetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
0251 }
0252 
0253 // Get any vector element as a string, regardless of what type it is.
0254 inline std::string GetAnyVectorElemS(const VectorOfAny *vec,
0255                                      reflection::BaseType elem_type, size_t i) {
0256   return GetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i,
0257                       nullptr, -1);
0258 }
0259 
0260 // Get a vector element that's a table/string/vector from a generic vector.
0261 // Pass Table/String/VectorOfAny as template parameter.
0262 // Warning: does no typechecking.
0263 template<typename T>
0264 T *GetAnyVectorElemPointer(const VectorOfAny *vec, size_t i) {
0265   auto elem_ptr = vec->Data() + sizeof(uoffset_t) * i;
0266   return reinterpret_cast<T *>(elem_ptr + ReadScalar<uoffset_t>(elem_ptr));
0267 }
0268 
0269 // Get the inline-address of a vector element. Useful for Structs (pass Struct
0270 // as template arg), or being able to address a range of scalars in-line.
0271 // Get elem_size from GetTypeSizeInline().
0272 // Note: little-endian data on all platforms, use EndianScalar() instead of
0273 // raw pointer access with scalars).
0274 template<typename T>
0275 T *GetAnyVectorElemAddressOf(const VectorOfAny *vec, size_t i,
0276                              size_t elem_size) {
0277   return reinterpret_cast<T *>(vec->Data() + elem_size * i);
0278 }
0279 
0280 // Similarly, for elements of tables.
0281 template<typename T>
0282 T *GetAnyFieldAddressOf(const Table &table, const reflection::Field &field) {
0283   return reinterpret_cast<T *>(table.GetAddressOf(field.offset()));
0284 }
0285 
0286 // Similarly, for elements of structs.
0287 template<typename T>
0288 T *GetAnyFieldAddressOf(const Struct &st, const reflection::Field &field) {
0289   return reinterpret_cast<T *>(st.GetAddressOf(field.offset()));
0290 }
0291 
0292 // Loop over all the fields of the provided `object` and call `func` on each one
0293 // in increasing order by their field->id(). If `reverse` is true, `func` is
0294 // called in descending order
0295 void ForAllFields(const reflection::Object *object, bool reverse,
0296                   std::function<void(const reflection::Field *)> func);
0297 
0298 // ------------------------- SETTERS -------------------------
0299 
0300 // Set any scalar field, if you know its exact type.
0301 template<typename T>
0302 bool SetField(Table *table, const reflection::Field &field, T val) {
0303   reflection::BaseType type = field.type()->base_type();
0304   if (!IsScalar(type)) { return false; }
0305   FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(type));
0306   T def;
0307   if (IsInteger(type)) {
0308     def = GetFieldDefaultI<T>(field);
0309   } else {
0310     FLATBUFFERS_ASSERT(IsFloat(type));
0311     def = GetFieldDefaultF<T>(field);
0312   }
0313   return table->SetField(field.offset(), val, def);
0314 }
0315 
0316 // Raw helper functions used below: set any value in memory as a 64bit int, a
0317 // double or a string.
0318 // These work for all scalar values, but do nothing for other data types.
0319 // To set a string, see SetString below.
0320 void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val);
0321 void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val);
0322 void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val);
0323 
0324 // Set any table field as a 64bit int, regardless of type what it is.
0325 inline bool SetAnyFieldI(Table *table, const reflection::Field &field,
0326                          int64_t val) {
0327   auto field_ptr = table->GetAddressOf(field.offset());
0328   if (!field_ptr) return val == GetFieldDefaultI<int64_t>(field);
0329   SetAnyValueI(field.type()->base_type(), field_ptr, val);
0330   return true;
0331 }
0332 
0333 // Set any table field as a double, regardless of what type it is.
0334 inline bool SetAnyFieldF(Table *table, const reflection::Field &field,
0335                          double val) {
0336   auto field_ptr = table->GetAddressOf(field.offset());
0337   if (!field_ptr) return val == GetFieldDefaultF<double>(field);
0338   SetAnyValueF(field.type()->base_type(), field_ptr, val);
0339   return true;
0340 }
0341 
0342 // Set any table field as a string, regardless of what type it is.
0343 inline bool SetAnyFieldS(Table *table, const reflection::Field &field,
0344                          const char *val) {
0345   auto field_ptr = table->GetAddressOf(field.offset());
0346   if (!field_ptr) return false;
0347   SetAnyValueS(field.type()->base_type(), field_ptr, val);
0348   return true;
0349 }
0350 
0351 // Set any struct field as a 64bit int, regardless of type what it is.
0352 inline void SetAnyFieldI(Struct *st, const reflection::Field &field,
0353                          int64_t val) {
0354   SetAnyValueI(field.type()->base_type(), st->GetAddressOf(field.offset()),
0355                val);
0356 }
0357 
0358 // Set any struct field as a double, regardless of type what it is.
0359 inline void SetAnyFieldF(Struct *st, const reflection::Field &field,
0360                          double val) {
0361   SetAnyValueF(field.type()->base_type(), st->GetAddressOf(field.offset()),
0362                val);
0363 }
0364 
0365 // Set any struct field as a string, regardless of type what it is.
0366 inline void SetAnyFieldS(Struct *st, const reflection::Field &field,
0367                          const char *val) {
0368   SetAnyValueS(field.type()->base_type(), st->GetAddressOf(field.offset()),
0369                val);
0370 }
0371 
0372 // Set any vector element as a 64bit int, regardless of type what it is.
0373 inline void SetAnyVectorElemI(VectorOfAny *vec, reflection::BaseType elem_type,
0374                               size_t i, int64_t val) {
0375   SetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
0376 }
0377 
0378 // Set any vector element as a double, regardless of type what it is.
0379 inline void SetAnyVectorElemF(VectorOfAny *vec, reflection::BaseType elem_type,
0380                               size_t i, double val) {
0381   SetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
0382 }
0383 
0384 // Set any vector element as a string, regardless of type what it is.
0385 inline void SetAnyVectorElemS(VectorOfAny *vec, reflection::BaseType elem_type,
0386                               size_t i, const char *val) {
0387   SetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
0388 }
0389 
0390 // ------------------------- RESIZING SETTERS -------------------------
0391 
0392 // "smart" pointer for use with resizing vectors: turns a pointer inside
0393 // a vector into a relative offset, such that it is not affected by resizes.
0394 template<typename T, typename U> class pointer_inside_vector {
0395  public:
0396   pointer_inside_vector(T *ptr, std::vector<U> &vec)
0397       : offset_(reinterpret_cast<uint8_t *>(ptr) -
0398                 reinterpret_cast<uint8_t *>(vec.data())),
0399         vec_(vec) {}
0400 
0401   T *operator*() const {
0402     return reinterpret_cast<T *>(reinterpret_cast<uint8_t *>(vec_.data()) +
0403                                  offset_);
0404   }
0405   T *operator->() const { return operator*(); }
0406 
0407  private:
0408   size_t offset_;
0409   std::vector<U> &vec_;
0410 };
0411 
0412 // Helper to create the above easily without specifying template args.
0413 template<typename T, typename U>
0414 pointer_inside_vector<T, U> piv(T *ptr, std::vector<U> &vec) {
0415   return pointer_inside_vector<T, U>(ptr, vec);
0416 }
0417 
0418 inline const char *UnionTypeFieldSuffix() { return "_type"; }
0419 
0420 // Helper to figure out the actual table type a union refers to.
0421 inline const reflection::Object &GetUnionType(
0422     const reflection::Schema &schema, const reflection::Object &parent,
0423     const reflection::Field &unionfield, const Table &table) {
0424   auto enumdef = schema.enums()->Get(unionfield.type()->index());
0425   // TODO: this is clumsy and slow, but no other way to find it?
0426   auto type_field = parent.fields()->LookupByKey(
0427       (unionfield.name()->str() + UnionTypeFieldSuffix()).c_str());
0428   FLATBUFFERS_ASSERT(type_field);
0429   auto union_type = GetFieldI<uint8_t>(table, *type_field);
0430   auto enumval = enumdef->values()->LookupByKey(union_type);
0431   return *schema.objects()->Get(enumval->union_type()->index());
0432 }
0433 
0434 // Changes the contents of a string inside a FlatBuffer. FlatBuffer must
0435 // live inside a std::vector so we can resize the buffer if needed.
0436 // "str" must live inside "flatbuf" and may be invalidated after this call.
0437 // If your FlatBuffer's root table is not the schema's root table, you should
0438 // pass in your root_table type as well.
0439 void SetString(const reflection::Schema &schema, const std::string &val,
0440                const String *str, std::vector<uint8_t> *flatbuf,
0441                const reflection::Object *root_table = nullptr);
0442 
0443 // Resizes a flatbuffers::Vector inside a FlatBuffer. FlatBuffer must
0444 // live inside a std::vector so we can resize the buffer if needed.
0445 // "vec" must live inside "flatbuf" and may be invalidated after this call.
0446 // If your FlatBuffer's root table is not the schema's root table, you should
0447 // pass in your root_table type as well.
0448 uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
0449                          const VectorOfAny *vec, uoffset_t num_elems,
0450                          uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
0451                          const reflection::Object *root_table = nullptr);
0452 
0453 template<typename T>
0454 void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val,
0455                   const Vector<T> *vec, std::vector<uint8_t> *flatbuf,
0456                   const reflection::Object *root_table = nullptr) {
0457   auto delta_elem = static_cast<int>(newsize) - static_cast<int>(vec->size());
0458   auto newelems = ResizeAnyVector(
0459       schema, newsize, reinterpret_cast<const VectorOfAny *>(vec), vec->size(),
0460       static_cast<uoffset_t>(sizeof(T)), flatbuf, root_table);
0461   // Set new elements to "val".
0462   for (int i = 0; i < delta_elem; i++) {
0463     auto loc = newelems + i * sizeof(T);
0464     auto is_scalar = flatbuffers::is_scalar<T>::value;
0465     if (is_scalar) {
0466       WriteScalar(loc, val);
0467     } else {  // struct
0468       *reinterpret_cast<T *>(loc) = val;
0469     }
0470   }
0471 }
0472 
0473 // Adds any new data (in the form of a new FlatBuffer) to an existing
0474 // FlatBuffer. This can be used when any of the above methods are not
0475 // sufficient, in particular for adding new tables and new fields.
0476 // This is potentially slightly less efficient than a FlatBuffer constructed
0477 // in one piece, since the new FlatBuffer doesn't share any vtables with the
0478 // existing one.
0479 // The return value can now be set using Vector::MutateOffset or SetFieldT
0480 // below.
0481 const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
0482                              const uint8_t *newbuf, size_t newlen);
0483 
0484 inline bool SetFieldT(Table *table, const reflection::Field &field,
0485                       const uint8_t *val) {
0486   FLATBUFFERS_ASSERT(sizeof(uoffset_t) ==
0487                      GetTypeSize(field.type()->base_type()));
0488   return table->SetPointer(field.offset(), val);
0489 }
0490 
0491 // ------------------------- COPYING -------------------------
0492 
0493 // Generic copying of tables from a FlatBuffer into a FlatBuffer builder.
0494 // Can be used to do any kind of merging/selecting you may want to do out
0495 // of existing buffers. Also useful to reconstruct a whole buffer if the
0496 // above resizing functionality has introduced garbage in a buffer you want
0497 // to remove.
0498 // Note: this does not deal with DAGs correctly. If the table passed forms a
0499 // DAG, the copy will be a tree instead (with duplicates). Strings can be
0500 // shared however, by passing true for use_string_pooling.
0501 
0502 Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
0503                                 const reflection::Schema &schema,
0504                                 const reflection::Object &objectdef,
0505                                 const Table &table,
0506                                 bool use_string_pooling = false);
0507 
0508 // Verifies the provided flatbuffer using reflection.
0509 // root should point to the root type for this flatbuffer.
0510 // buf should point to the start of flatbuffer data.
0511 // length specifies the size of the flatbuffer data.
0512 bool Verify(const reflection::Schema &schema, const reflection::Object &root,
0513             const uint8_t *buf, size_t length, uoffset_t max_depth = 64,
0514             uoffset_t max_tables = 1000000);
0515 
0516 bool VerifySizePrefixed(const reflection::Schema &schema,
0517                         const reflection::Object &root, const uint8_t *buf,
0518                         size_t length, uoffset_t max_depth = 64,
0519                         uoffset_t max_tables = 1000000);
0520 
0521 }  // namespace flatbuffers
0522 
0523 #endif  // FLATBUFFERS_REFLECTION_H_