/* * Copyright 2014 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_H_ #define FLATBUFFERS_H_ // TODO: These includes are for mitigating the pains of users editing their // source because they relied on flatbuffers.h to include everything for them. #include "flatbuffers/array.h" #include "flatbuffers/base.h" #include "flatbuffers/buffer.h" #include "flatbuffers/buffer_ref.h" #include "flatbuffers/detached_buffer.h" #include "flatbuffers/flatbuffer_builder.h" #include "flatbuffers/stl_emulation.h" #include "flatbuffers/string.h" #include "flatbuffers/struct.h" #include "flatbuffers/table.h" #include "flatbuffers/vector.h" #include "flatbuffers/vector_downward.h" #include "flatbuffers/verifier.h" namespace flatbuffers { /// @brief This can compute the start of a FlatBuffer from a root pointer, i.e. /// it is the opposite transformation of GetRoot(). /// This may be useful if you want to pass on a root and have the recipient /// delete the buffer afterwards. inline const uint8_t *GetBufferStartFromRootPointer(const void *root) { auto table = reinterpret_cast(root); auto vtable = table->GetVTable(); // Either the vtable is before the root or after the root. auto start = (std::min)(vtable, reinterpret_cast(root)); // Align to at least sizeof(uoffset_t). start = reinterpret_cast(reinterpret_cast(start) & ~(sizeof(uoffset_t) - 1)); // Additionally, there may be a file_identifier in the buffer, and the root // offset. The buffer may have been aligned to any size between // sizeof(uoffset_t) and FLATBUFFERS_MAX_ALIGNMENT (see "force_align"). // Sadly, the exact alignment is only known when constructing the buffer, // since it depends on the presence of values with said alignment properties. // So instead, we simply look at the next uoffset_t values (root, // file_identifier, and alignment padding) to see which points to the root. // None of the other values can "impersonate" the root since they will either // be 0 or four ASCII characters. static_assert(flatbuffers::kFileIdentifierLength == sizeof(uoffset_t), "file_identifier is assumed to be the same size as uoffset_t"); for (auto possible_roots = FLATBUFFERS_MAX_ALIGNMENT / sizeof(uoffset_t) + 1; possible_roots; possible_roots--) { start -= sizeof(uoffset_t); if (ReadScalar(start) + start == reinterpret_cast(root)) return start; } // We didn't find the root, either the "root" passed isn't really a root, // or the buffer is corrupt. // Assert, because calling this function with bad data may cause reads // outside of buffer boundaries. FLATBUFFERS_ASSERT(false); return nullptr; } /// @brief This return the prefixed size of a FlatBuffer. inline uoffset_t GetPrefixedSize(const uint8_t *buf) { return ReadScalar(buf); } // Base class for native objects (FlatBuffer data de-serialized into native // C++ data structures). // Contains no functionality, purely documentative. struct NativeTable {}; /// @brief Function types to be used with resolving hashes into objects and /// back again. The resolver gets a pointer to a field inside an object API /// object that is of the type specified in the schema using the attribute /// `cpp_type` (it is thus important whatever you write to this address /// matches that type). The value of this field is initially null, so you /// may choose to implement a delayed binding lookup using this function /// if you wish. The resolver does the opposite lookup, for when the object /// is being serialized again. typedef uint64_t hash_value_t; typedef std::function resolver_function_t; typedef std::function rehasher_function_t; // Helper function to test if a field is present, using any of the field // enums in the generated code. // `table` must be a generated table type. Since this is a template parameter, // this is not typechecked to be a subclass of Table, so beware! // Note: this function will return false for fields equal to the default // value, since they're not stored in the buffer (unless force_defaults was // used). template bool IsFieldPresent(const T *table, typename T::FlatBuffersVTableOffset field) { // Cast, since Table is a private baseclass of any table types. return reinterpret_cast(table)->CheckField( static_cast(field)); } // Utility function for reverse lookups on the EnumNames*() functions // (in the generated C++ code) // names must be NULL terminated. inline int LookupEnum(const char **names, const char *name) { for (const char **p = names; *p; p++) if (!strcmp(*p, name)) return static_cast(p - names); return -1; } // These macros allow us to layout a struct with a guarantee that they'll end // up looking the same on different compilers and platforms. // It does this by disallowing the compiler to do any padding, and then // does padding itself by inserting extra padding fields that make every // element aligned to its own size. // Additionally, it manually sets the alignment of the struct as a whole, // which is typically its largest element, or a custom size set in the schema // by the force_align attribute. // These are used in the generated code only. // clang-format off #if defined(_MSC_VER) #define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \ __pragma(pack(1)) \ struct __declspec(align(alignment)) #define FLATBUFFERS_STRUCT_END(name, size) \ __pragma(pack()) \ static_assert(sizeof(name) == size, "compiler breaks packing rules") #elif defined(__GNUC__) || defined(__clang__) || defined(__ICCARM__) #define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \ _Pragma("pack(1)") \ struct __attribute__((aligned(alignment))) #define FLATBUFFERS_STRUCT_END(name, size) \ _Pragma("pack()") \ static_assert(sizeof(name) == size, "compiler breaks packing rules") #else #error Unknown compiler, please define structure alignment macros #endif // clang-format on // Minimal reflection via code generation. // Besides full-fat reflection (see reflection.h) and parsing/printing by // loading schemas (see idl.h), we can also have code generation for minimal // reflection data which allows pretty-printing and other uses without needing // a schema or a parser. // Generate code with --reflect-types (types only) or --reflect-names (names // also) to enable. // See minireflect.h for utilities using this functionality. // These types are organized slightly differently as the ones in idl.h. enum SequenceType { ST_TABLE, ST_STRUCT, ST_UNION, ST_ENUM }; // Scalars have the same order as in idl.h // clang-format off #define FLATBUFFERS_GEN_ELEMENTARY_TYPES(ET) \ ET(ET_UTYPE) \ ET(ET_BOOL) \ ET(ET_CHAR) \ ET(ET_UCHAR) \ ET(ET_SHORT) \ ET(ET_USHORT) \ ET(ET_INT) \ ET(ET_UINT) \ ET(ET_LONG) \ ET(ET_ULONG) \ ET(ET_FLOAT) \ ET(ET_DOUBLE) \ ET(ET_STRING) \ ET(ET_SEQUENCE) // See SequenceType. enum ElementaryType { #define FLATBUFFERS_ET(E) E, FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET) #undef FLATBUFFERS_ET }; inline const char * const *ElementaryTypeNames() { static const char * const names[] = { #define FLATBUFFERS_ET(E) #E, FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET) #undef FLATBUFFERS_ET }; return names; } // clang-format on // Basic type info cost just 16bits per field! // We're explicitly defining the signedness since the signedness of integer // bitfields is otherwise implementation-defined and causes warnings on older // GCC compilers. struct TypeCode { // ElementaryType unsigned short base_type : 4; // Either vector (in table) or array (in struct) unsigned short is_repeating : 1; // Index into type_refs below, or -1 for none. signed short sequence_ref : 11; }; static_assert(sizeof(TypeCode) == 2, "TypeCode"); struct TypeTable; // Signature of the static method present in each type. typedef const TypeTable *(*TypeFunction)(); struct TypeTable { SequenceType st; size_t num_elems; // of type_codes, values, names (but not type_refs). const TypeCode *type_codes; // num_elems count const TypeFunction *type_refs; // less than num_elems entries (see TypeCode). const int16_t *array_sizes; // less than num_elems entries (see TypeCode). const int64_t *values; // Only set for non-consecutive enum/union or structs. const char *const *names; // Only set if compiled with --reflect-names. }; // String which identifies the current version of FlatBuffers. inline const char *flatbuffers_version_string() { return "FlatBuffers " FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "." FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MINOR) "." FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION); } // clang-format off #define FLATBUFFERS_DEFINE_BITMASK_OPERATORS(E, T)\ inline E operator | (E lhs, E rhs){\ return E(T(lhs) | T(rhs));\ }\ inline E operator & (E lhs, E rhs){\ return E(T(lhs) & T(rhs));\ }\ inline E operator ^ (E lhs, E rhs){\ return E(T(lhs) ^ T(rhs));\ }\ inline E operator ~ (E lhs){\ return E(~T(lhs));\ }\ inline E operator |= (E &lhs, E rhs){\ lhs = lhs | rhs;\ return lhs;\ }\ inline E operator &= (E &lhs, E rhs){\ lhs = lhs & rhs;\ return lhs;\ }\ inline E operator ^= (E &lhs, E rhs){\ lhs = lhs ^ rhs;\ return lhs;\ }\ inline bool operator !(E rhs) \ {\ return !bool(T(rhs)); \ } /// @endcond } // namespace flatbuffers // clang-format on #endif // FLATBUFFERS_H_