/* * Copyright 2015 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef FLATBUFFERS_REFLECTION_H_ #define FLATBUFFERS_REFLECTION_H_ // This is somewhat of a circular dependency because flatc (and thus this // file) is needed to generate this header in the first place. // Should normally not be a problem since it can be generated by the // previous version of flatc whenever this code needs to change. // See scripts/generate_code.py for generation. #include "flatbuffers/reflection_generated.h" // Helper functionality for reflection. namespace flatbuffers { // ------------------------- GETTERS ------------------------- inline bool IsScalar(reflection::BaseType t) { … } inline bool IsInteger(reflection::BaseType t) { … } inline bool IsFloat(reflection::BaseType t) { … } inline bool IsLong(reflection::BaseType t) { … } // Size of a basic type, don't use with structs. inline size_t GetTypeSize(reflection::BaseType base_type) { … } // Same as above, but now correctly returns the size of a struct if // the field (or vector element) is a struct. inline size_t GetTypeSizeInline(reflection::BaseType base_type, int type_index, const reflection::Schema &schema) { … } // Get the root, regardless of what type it is. inline Table *GetAnyRoot(uint8_t *const flatbuf) { … } inline const Table *GetAnyRoot(const uint8_t *const flatbuf) { … } inline Table *GetAnySizePrefixedRoot(uint8_t *const flatbuf) { … } inline const Table *GetAnySizePrefixedRoot(const uint8_t *const flatbuf) { … } // Get a field's default, if you know it's an integer, and its exact type. template<typename T> T GetFieldDefaultI(const reflection::Field &field) { … } // Get a field's default, if you know it's floating point and its exact type. template<typename T> T GetFieldDefaultF(const reflection::Field &field) { … } // Get a field, if you know it's an integer, and its exact type. template<typename T> T GetFieldI(const Table &table, const reflection::Field &field) { … } // Get a field, if you know it's floating point and its exact type. template<typename T> T GetFieldF(const Table &table, const reflection::Field &field) { … } // Get a field, if you know it's a string. inline const String *GetFieldS(const Table &table, const reflection::Field &field) { … } // Get a field, if you know it's a vector. template<typename T> Vector<T> *GetFieldV(const Table &table, const reflection::Field &field) { … } // Get a field, if you know it's a vector, generically. // To actually access elements, use the return value together with // field.type()->element() in any of GetAnyVectorElemI below etc. inline VectorOfAny *GetFieldAnyV(const Table &table, const reflection::Field &field) { … } // Get a field, if you know it's a table. inline Table *GetFieldT(const Table &table, const reflection::Field &field) { … } // Get a field, if you know it's a struct. inline const Struct *GetFieldStruct(const Table &table, const reflection::Field &field) { … } // Get a structure's field, if you know it's a struct. inline const Struct *GetFieldStruct(const Struct &structure, const reflection::Field &field) { … } // Raw helper functions used below: get any value in memory as a 64bit int, a // double or a string. // All scalars get static_cast to an int64_t, strings use strtoull, every other // data type returns 0. int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data); // All scalars static cast to double, strings use strtod, every other data // type is 0.0. double GetAnyValueF(reflection::BaseType type, const uint8_t *data); // All scalars converted using stringstream, strings as-is, and all other // data types provide some level of debug-pretty-printing. std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data, const reflection::Schema *schema, int type_index); // Get any table field as a 64bit int, regardless of what type it is. inline int64_t GetAnyFieldI(const Table &table, const reflection::Field &field) { … } // Get any table field as a double, regardless of what type it is. inline double GetAnyFieldF(const Table &table, const reflection::Field &field) { … } // Get any table field as a string, regardless of what type it is. // You may pass nullptr for the schema if you don't care to have fields that // are of table type pretty-printed. inline std::string GetAnyFieldS(const Table &table, const reflection::Field &field, const reflection::Schema *schema) { … } // Get any struct field as a 64bit int, regardless of what type it is. inline int64_t GetAnyFieldI(const Struct &st, const reflection::Field &field) { … } // Get any struct field as a double, regardless of what type it is. inline double GetAnyFieldF(const Struct &st, const reflection::Field &field) { … } // Get any struct field as a string, regardless of what type it is. inline std::string GetAnyFieldS(const Struct &st, const reflection::Field &field) { … } // Get any vector element as a 64bit int, regardless of what type it is. inline int64_t GetAnyVectorElemI(const VectorOfAny *vec, reflection::BaseType elem_type, size_t i) { … } // Get any vector element as a double, regardless of what type it is. inline double GetAnyVectorElemF(const VectorOfAny *vec, reflection::BaseType elem_type, size_t i) { … } // Get any vector element as a string, regardless of what type it is. inline std::string GetAnyVectorElemS(const VectorOfAny *vec, reflection::BaseType elem_type, size_t i) { … } // Get a vector element that's a table/string/vector from a generic vector. // Pass Table/String/VectorOfAny as template parameter. // Warning: does no typechecking. template<typename T> T *GetAnyVectorElemPointer(const VectorOfAny *vec, size_t i) { … } // Get the inline-address of a vector element. Useful for Structs (pass Struct // as template arg), or being able to address a range of scalars in-line. // Get elem_size from GetTypeSizeInline(). // Note: little-endian data on all platforms, use EndianScalar() instead of // raw pointer access with scalars). template<typename T> T *GetAnyVectorElemAddressOf(const VectorOfAny *vec, size_t i, size_t elem_size) { … } // Similarly, for elements of tables. template<typename T> T *GetAnyFieldAddressOf(const Table &table, const reflection::Field &field) { … } // Similarly, for elements of structs. template<typename T> T *GetAnyFieldAddressOf(const Struct &st, const reflection::Field &field) { … } // Loop over all the fields of the provided `object` and call `func` on each one // in increasing order by their field->id(). If `reverse` is true, `func` is // called in descending order void ForAllFields(const reflection::Object *object, bool reverse, std::function<void(const reflection::Field *)> func); // ------------------------- SETTERS ------------------------- // Set any scalar field, if you know its exact type. template<typename T> bool SetField(Table *table, const reflection::Field &field, T val) { … } // Raw helper functions used below: set any value in memory as a 64bit int, a // double or a string. // These work for all scalar values, but do nothing for other data types. // To set a string, see SetString below. void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val); void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val); void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val); // Set any table field as a 64bit int, regardless of type what it is. inline bool SetAnyFieldI(Table *table, const reflection::Field &field, int64_t val) { … } // Set any table field as a double, regardless of what type it is. inline bool SetAnyFieldF(Table *table, const reflection::Field &field, double val) { … } // Set any table field as a string, regardless of what type it is. inline bool SetAnyFieldS(Table *table, const reflection::Field &field, const char *val) { … } // Set any struct field as a 64bit int, regardless of type what it is. inline void SetAnyFieldI(Struct *st, const reflection::Field &field, int64_t val) { … } // Set any struct field as a double, regardless of type what it is. inline void SetAnyFieldF(Struct *st, const reflection::Field &field, double val) { … } // Set any struct field as a string, regardless of type what it is. inline void SetAnyFieldS(Struct *st, const reflection::Field &field, const char *val) { … } // Set any vector element as a 64bit int, regardless of type what it is. inline void SetAnyVectorElemI(VectorOfAny *vec, reflection::BaseType elem_type, size_t i, int64_t val) { … } // Set any vector element as a double, regardless of type what it is. inline void SetAnyVectorElemF(VectorOfAny *vec, reflection::BaseType elem_type, size_t i, double val) { … } // Set any vector element as a string, regardless of type what it is. inline void SetAnyVectorElemS(VectorOfAny *vec, reflection::BaseType elem_type, size_t i, const char *val) { … } // ------------------------- RESIZING SETTERS ------------------------- // "smart" pointer for use with resizing vectors: turns a pointer inside // a vector into a relative offset, such that it is not affected by resizes. template<typename T, typename U> class pointer_inside_vector { … }; // Helper to create the above easily without specifying template args. template<typename T, typename U> pointer_inside_vector<T, U> piv(T *ptr, std::vector<U> &vec) { … } inline const char *UnionTypeFieldSuffix() { … } // Helper to figure out the actual table type a union refers to. inline const reflection::Object &GetUnionType( const reflection::Schema &schema, const reflection::Object &parent, const reflection::Field &unionfield, const Table &table) { … } // Changes the contents of a string inside a FlatBuffer. FlatBuffer must // live inside a std::vector so we can resize the buffer if needed. // "str" must live inside "flatbuf" and may be invalidated after this call. // If your FlatBuffer's root table is not the schema's root table, you should // pass in your root_table type as well. void SetString(const reflection::Schema &schema, const std::string &val, const String *str, std::vector<uint8_t> *flatbuf, const reflection::Object *root_table = nullptr); // Resizes a flatbuffers::Vector inside a FlatBuffer. FlatBuffer must // live inside a std::vector so we can resize the buffer if needed. // "vec" must live inside "flatbuf" and may be invalidated after this call. // If your FlatBuffer's root table is not the schema's root table, you should // pass in your root_table type as well. uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize, const VectorOfAny *vec, uoffset_t num_elems, uoffset_t elem_size, std::vector<uint8_t> *flatbuf, const reflection::Object *root_table = nullptr); template<typename T> void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val, const Vector<T> *vec, std::vector<uint8_t> *flatbuf, const reflection::Object *root_table = nullptr) { … } // Adds any new data (in the form of a new FlatBuffer) to an existing // FlatBuffer. This can be used when any of the above methods are not // sufficient, in particular for adding new tables and new fields. // This is potentially slightly less efficient than a FlatBuffer constructed // in one piece, since the new FlatBuffer doesn't share any vtables with the // existing one. // The return value can now be set using Vector::MutateOffset or SetFieldT // below. const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf, const uint8_t *newbuf, size_t newlen); inline bool SetFieldT(Table *table, const reflection::Field &field, const uint8_t *val) { … } // ------------------------- COPYING ------------------------- // Generic copying of tables from a FlatBuffer into a FlatBuffer builder. // Can be used to do any kind of merging/selecting you may want to do out // of existing buffers. Also useful to reconstruct a whole buffer if the // above resizing functionality has introduced garbage in a buffer you want // to remove. // Note: this does not deal with DAGs correctly. If the table passed forms a // DAG, the copy will be a tree instead (with duplicates). Strings can be // shared however, by passing true for use_string_pooling. Offset<const Table *> CopyTable(FlatBufferBuilder &fbb, const reflection::Schema &schema, const reflection::Object &objectdef, const Table &table, bool use_string_pooling = false); // Verifies the provided flatbuffer using reflection. // root should point to the root type for this flatbuffer. // buf should point to the start of flatbuffer data. // length specifies the size of the flatbuffer data. bool Verify(const reflection::Schema &schema, const reflection::Object &root, const uint8_t *buf, size_t length, uoffset_t max_depth = 64, uoffset_t max_tables = 1000000); bool VerifySizePrefixed(const reflection::Schema &schema, const reflection::Object &root, const uint8_t *buf, size_t length, uoffset_t max_depth = 64, uoffset_t max_tables = 1000000); } // namespace flatbuffers #endif // FLATBUFFERS_REFLECTION_H_