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