Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2014 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_H_ |
| 18 | #define FLATBUFFERS_H_ |
| 19 | |
James Kuszmaul | 3b15b0c | 2022-11-08 14:03:16 -0800 | [diff] [blame^] | 20 | #include <algorithm> |
| 21 | |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 22 | // TODO: These includes are for mitigating the pains of users editing their |
| 23 | // source because they relied on flatbuffers.h to include everything for them. |
| 24 | #include "flatbuffers/array.h" |
Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame] | 25 | #include "flatbuffers/base.h" |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 26 | #include "flatbuffers/buffer.h" |
| 27 | #include "flatbuffers/buffer_ref.h" |
| 28 | #include "flatbuffers/detached_buffer.h" |
| 29 | #include "flatbuffers/flatbuffer_builder.h" |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 30 | #include "flatbuffers/stl_emulation.h" |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 31 | #include "flatbuffers/string.h" |
| 32 | #include "flatbuffers/struct.h" |
| 33 | #include "flatbuffers/table.h" |
| 34 | #include "flatbuffers/vector.h" |
| 35 | #include "flatbuffers/vector_downward.h" |
| 36 | #include "flatbuffers/verifier.h" |
Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame] | 37 | |
| 38 | namespace flatbuffers { |
Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame] | 39 | |
| 40 | /// @brief This can compute the start of a FlatBuffer from a root pointer, i.e. |
| 41 | /// it is the opposite transformation of GetRoot(). |
| 42 | /// This may be useful if you want to pass on a root and have the recipient |
| 43 | /// delete the buffer afterwards. |
| 44 | inline const uint8_t *GetBufferStartFromRootPointer(const void *root) { |
| 45 | auto table = reinterpret_cast<const Table *>(root); |
| 46 | auto vtable = table->GetVTable(); |
| 47 | // Either the vtable is before the root or after the root. |
| 48 | auto start = (std::min)(vtable, reinterpret_cast<const uint8_t *>(root)); |
| 49 | // Align to at least sizeof(uoffset_t). |
| 50 | start = reinterpret_cast<const uint8_t *>(reinterpret_cast<uintptr_t>(start) & |
| 51 | ~(sizeof(uoffset_t) - 1)); |
| 52 | // Additionally, there may be a file_identifier in the buffer, and the root |
| 53 | // offset. The buffer may have been aligned to any size between |
| 54 | // sizeof(uoffset_t) and FLATBUFFERS_MAX_ALIGNMENT (see "force_align"). |
| 55 | // Sadly, the exact alignment is only known when constructing the buffer, |
| 56 | // since it depends on the presence of values with said alignment properties. |
| 57 | // So instead, we simply look at the next uoffset_t values (root, |
| 58 | // file_identifier, and alignment padding) to see which points to the root. |
| 59 | // None of the other values can "impersonate" the root since they will either |
| 60 | // be 0 or four ASCII characters. |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 61 | static_assert(flatbuffers::kFileIdentifierLength == sizeof(uoffset_t), |
Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame] | 62 | "file_identifier is assumed to be the same size as uoffset_t"); |
| 63 | for (auto possible_roots = FLATBUFFERS_MAX_ALIGNMENT / sizeof(uoffset_t) + 1; |
| 64 | possible_roots; possible_roots--) { |
| 65 | start -= sizeof(uoffset_t); |
| 66 | if (ReadScalar<uoffset_t>(start) + start == |
| 67 | reinterpret_cast<const uint8_t *>(root)) |
| 68 | return start; |
| 69 | } |
| 70 | // We didn't find the root, either the "root" passed isn't really a root, |
| 71 | // or the buffer is corrupt. |
| 72 | // Assert, because calling this function with bad data may cause reads |
| 73 | // outside of buffer boundaries. |
| 74 | FLATBUFFERS_ASSERT(false); |
| 75 | return nullptr; |
| 76 | } |
| 77 | |
| 78 | /// @brief This return the prefixed size of a FlatBuffer. |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 79 | inline uoffset_t GetPrefixedSize(const uint8_t *buf) { |
| 80 | return ReadScalar<uoffset_t>(buf); |
| 81 | } |
Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame] | 82 | |
| 83 | // Base class for native objects (FlatBuffer data de-serialized into native |
| 84 | // C++ data structures). |
| 85 | // Contains no functionality, purely documentative. |
| 86 | struct NativeTable {}; |
| 87 | |
| 88 | /// @brief Function types to be used with resolving hashes into objects and |
| 89 | /// back again. The resolver gets a pointer to a field inside an object API |
| 90 | /// object that is of the type specified in the schema using the attribute |
| 91 | /// `cpp_type` (it is thus important whatever you write to this address |
| 92 | /// matches that type). The value of this field is initially null, so you |
| 93 | /// may choose to implement a delayed binding lookup using this function |
| 94 | /// if you wish. The resolver does the opposite lookup, for when the object |
| 95 | /// is being serialized again. |
| 96 | typedef uint64_t hash_value_t; |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 97 | typedef std::function<void(void **pointer_adr, hash_value_t hash)> |
| 98 | resolver_function_t; |
| 99 | typedef std::function<hash_value_t(void *pointer)> rehasher_function_t; |
Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame] | 100 | |
| 101 | // Helper function to test if a field is present, using any of the field |
| 102 | // enums in the generated code. |
| 103 | // `table` must be a generated table type. Since this is a template parameter, |
| 104 | // this is not typechecked to be a subclass of Table, so beware! |
| 105 | // Note: this function will return false for fields equal to the default |
| 106 | // value, since they're not stored in the buffer (unless force_defaults was |
| 107 | // used). |
| 108 | template<typename T> |
| 109 | bool IsFieldPresent(const T *table, typename T::FlatBuffersVTableOffset field) { |
| 110 | // Cast, since Table is a private baseclass of any table types. |
| 111 | return reinterpret_cast<const Table *>(table)->CheckField( |
| 112 | static_cast<voffset_t>(field)); |
| 113 | } |
| 114 | |
| 115 | // Utility function for reverse lookups on the EnumNames*() functions |
| 116 | // (in the generated C++ code) |
| 117 | // names must be NULL terminated. |
| 118 | inline int LookupEnum(const char **names, const char *name) { |
| 119 | for (const char **p = names; *p; p++) |
| 120 | if (!strcmp(*p, name)) return static_cast<int>(p - names); |
| 121 | return -1; |
| 122 | } |
| 123 | |
| 124 | // These macros allow us to layout a struct with a guarantee that they'll end |
| 125 | // up looking the same on different compilers and platforms. |
| 126 | // It does this by disallowing the compiler to do any padding, and then |
| 127 | // does padding itself by inserting extra padding fields that make every |
| 128 | // element aligned to its own size. |
| 129 | // Additionally, it manually sets the alignment of the struct as a whole, |
| 130 | // which is typically its largest element, or a custom size set in the schema |
| 131 | // by the force_align attribute. |
| 132 | // These are used in the generated code only. |
| 133 | |
| 134 | // clang-format off |
| 135 | #if defined(_MSC_VER) |
| 136 | #define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \ |
| 137 | __pragma(pack(1)) \ |
| 138 | struct __declspec(align(alignment)) |
| 139 | #define FLATBUFFERS_STRUCT_END(name, size) \ |
| 140 | __pragma(pack()) \ |
| 141 | static_assert(sizeof(name) == size, "compiler breaks packing rules") |
| 142 | #elif defined(__GNUC__) || defined(__clang__) || defined(__ICCARM__) |
| 143 | #define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \ |
| 144 | _Pragma("pack(1)") \ |
| 145 | struct __attribute__((aligned(alignment))) |
| 146 | #define FLATBUFFERS_STRUCT_END(name, size) \ |
| 147 | _Pragma("pack()") \ |
| 148 | static_assert(sizeof(name) == size, "compiler breaks packing rules") |
| 149 | #else |
| 150 | #error Unknown compiler, please define structure alignment macros |
| 151 | #endif |
| 152 | // clang-format on |
| 153 | |
| 154 | // Minimal reflection via code generation. |
| 155 | // Besides full-fat reflection (see reflection.h) and parsing/printing by |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 156 | // loading schemas (see idl.h), we can also have code generation for minimal |
Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame] | 157 | // reflection data which allows pretty-printing and other uses without needing |
| 158 | // a schema or a parser. |
| 159 | // Generate code with --reflect-types (types only) or --reflect-names (names |
| 160 | // also) to enable. |
| 161 | // See minireflect.h for utilities using this functionality. |
| 162 | |
| 163 | // These types are organized slightly differently as the ones in idl.h. |
| 164 | enum SequenceType { ST_TABLE, ST_STRUCT, ST_UNION, ST_ENUM }; |
| 165 | |
| 166 | // Scalars have the same order as in idl.h |
| 167 | // clang-format off |
| 168 | #define FLATBUFFERS_GEN_ELEMENTARY_TYPES(ET) \ |
| 169 | ET(ET_UTYPE) \ |
| 170 | ET(ET_BOOL) \ |
| 171 | ET(ET_CHAR) \ |
| 172 | ET(ET_UCHAR) \ |
| 173 | ET(ET_SHORT) \ |
| 174 | ET(ET_USHORT) \ |
| 175 | ET(ET_INT) \ |
| 176 | ET(ET_UINT) \ |
| 177 | ET(ET_LONG) \ |
| 178 | ET(ET_ULONG) \ |
| 179 | ET(ET_FLOAT) \ |
| 180 | ET(ET_DOUBLE) \ |
| 181 | ET(ET_STRING) \ |
| 182 | ET(ET_SEQUENCE) // See SequenceType. |
| 183 | |
| 184 | enum ElementaryType { |
| 185 | #define FLATBUFFERS_ET(E) E, |
| 186 | FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET) |
| 187 | #undef FLATBUFFERS_ET |
| 188 | }; |
| 189 | |
| 190 | inline const char * const *ElementaryTypeNames() { |
| 191 | static const char * const names[] = { |
| 192 | #define FLATBUFFERS_ET(E) #E, |
| 193 | FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET) |
| 194 | #undef FLATBUFFERS_ET |
| 195 | }; |
| 196 | return names; |
| 197 | } |
| 198 | // clang-format on |
| 199 | |
| 200 | // Basic type info cost just 16bits per field! |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 201 | // We're explicitly defining the signedness since the signedness of integer |
| 202 | // bitfields is otherwise implementation-defined and causes warnings on older |
| 203 | // GCC compilers. |
Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame] | 204 | struct TypeCode { |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 205 | // ElementaryType |
| 206 | unsigned short base_type : 4; |
| 207 | // Either vector (in table) or array (in struct) |
| 208 | unsigned short is_repeating : 1; |
| 209 | // Index into type_refs below, or -1 for none. |
| 210 | signed short sequence_ref : 11; |
Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame] | 211 | }; |
| 212 | |
| 213 | static_assert(sizeof(TypeCode) == 2, "TypeCode"); |
| 214 | |
| 215 | struct TypeTable; |
| 216 | |
| 217 | // Signature of the static method present in each type. |
| 218 | typedef const TypeTable *(*TypeFunction)(); |
| 219 | |
| 220 | struct TypeTable { |
| 221 | SequenceType st; |
| 222 | size_t num_elems; // of type_codes, values, names (but not type_refs). |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 223 | const TypeCode *type_codes; // num_elems count |
Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame] | 224 | const TypeFunction *type_refs; // less than num_elems entries (see TypeCode). |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 225 | const int16_t *array_sizes; // less than num_elems entries (see TypeCode). |
Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame] | 226 | const int64_t *values; // Only set for non-consecutive enum/union or structs. |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 227 | const char *const *names; // Only set if compiled with --reflect-names. |
Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame] | 228 | }; |
| 229 | |
| 230 | // String which identifies the current version of FlatBuffers. |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 231 | inline const char *flatbuffers_version_string() { |
| 232 | return "FlatBuffers " FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "." |
| 233 | FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MINOR) "." |
| 234 | FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION); |
| 235 | } |
Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame] | 236 | |
Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame] | 237 | // clang-format off |
Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame] | 238 | #define FLATBUFFERS_DEFINE_BITMASK_OPERATORS(E, T)\ |
| 239 | inline E operator | (E lhs, E rhs){\ |
| 240 | return E(T(lhs) | T(rhs));\ |
| 241 | }\ |
| 242 | inline E operator & (E lhs, E rhs){\ |
| 243 | return E(T(lhs) & T(rhs));\ |
| 244 | }\ |
| 245 | inline E operator ^ (E lhs, E rhs){\ |
| 246 | return E(T(lhs) ^ T(rhs));\ |
| 247 | }\ |
| 248 | inline E operator ~ (E lhs){\ |
| 249 | return E(~T(lhs));\ |
| 250 | }\ |
| 251 | inline E operator |= (E &lhs, E rhs){\ |
| 252 | lhs = lhs | rhs;\ |
| 253 | return lhs;\ |
| 254 | }\ |
| 255 | inline E operator &= (E &lhs, E rhs){\ |
| 256 | lhs = lhs & rhs;\ |
| 257 | return lhs;\ |
| 258 | }\ |
| 259 | inline E operator ^= (E &lhs, E rhs){\ |
| 260 | lhs = lhs ^ rhs;\ |
| 261 | return lhs;\ |
| 262 | }\ |
| 263 | inline bool operator !(E rhs) \ |
| 264 | {\ |
| 265 | return !bool(T(rhs)); \ |
| 266 | } |
| 267 | /// @endcond |
| 268 | } // namespace flatbuffers |
| 269 | |
| 270 | // clang-format on |
| 271 | |
| 272 | #endif // FLATBUFFERS_H_ |