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 20 /** 21 * @file 22 * A customized version of the FlatBuffers implementation header file targeted 23 * for use within CHRE. This file differs from the mainline FlatBuffers release 24 * via the introduction of the feature flag FLATBUFFERS_CHRE. When defined, 25 * standard library features not used in CHRE are removed or remapped to their 26 * CHRE-specific alternatives. This includes removing support for strings, 27 * replacing std::vector with chre::DynamicVector, use of CHRE_ASSERT instead of 28 * assert(), etc. 29 */ 30 31 #include <cstdint> 32 #include <cstddef> 33 #include <cstdlib> 34 #include <cstring> 35 #include <utility> 36 #include <type_traits> 37 #include <vector> 38 #include <algorithm> 39 #include <memory> 40 41 #ifndef FLATBUFFERS_CHRE 42 #include <assert.h> 43 44 #include <set> 45 #include <string> 46 #else 47 // TODO: we should be able to leave this flag unset if we connect unique_ptr_t 48 // to chre::UniquePtr, but the features wrapped by this flag (e.g. use of 49 // std::function) aren't strictly required, so setting it for now. 50 #define FLATBUFFERS_CPP98_STL 51 52 #include "chre/util/container_support.h" 53 #include "chre/util/dynamic_vector.h" 54 #include "chre/util/unique_ptr.h" 55 56 #ifndef CHRE_ASSERT_USES_STDLIB_ASSERT 57 #ifdef assert 58 #define FLATBUFFERS_PRIOR_ASSERT assert 59 #undef assert 60 #endif 61 #define assert CHRE_ASSERT 62 #endif // CHRE_ASSERT_USES_STDLIB_ASSERT 63 #endif // FLATBUFFERS_CHRE 64 #ifdef _STLPORT_VERSION 65 #define FLATBUFFERS_CPP98_STL 66 #endif 67 #ifndef FLATBUFFERS_CPP98_STL 68 #include <functional> 69 #endif 70 71 /// @cond FLATBUFFERS_INTERNAL 72 #if __cplusplus <= 199711L && \ 73 (!defined(_MSC_VER) || _MSC_VER < 1600) && \ 74 (!defined(__GNUC__) || \ 75 (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40400)) 76 #error A C++11 compatible compiler with support for the auto typing is \ 77 required for FlatBuffers. 78 #error __cplusplus _MSC_VER __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__ 79 #endif 80 81 #if !defined(__clang__) && \ 82 defined(__GNUC__) && \ 83 (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40600) 84 // Backwards compatability for g++ 4.4, and 4.5 which don't have the nullptr 85 // and constexpr keywords. Note the __clang__ check is needed, because clang 86 // presents itself as an older GNUC compiler. 87 #ifndef nullptr_t 88 const class nullptr_t { 89 public: 90 template<class T> inline operator T*() const { return 0; } 91 private: 92 void operator&() const; 93 } nullptr = {}; 94 #endif 95 #ifndef constexpr 96 #define constexpr const 97 #endif 98 #endif 99 100 // The wire format uses a little endian encoding (since that's efficient for 101 // the common platforms). 102 #if !defined(FLATBUFFERS_LITTLEENDIAN) 103 #if defined(__GNUC__) || defined(__clang__) 104 #ifdef __BIG_ENDIAN__ 105 #define FLATBUFFERS_LITTLEENDIAN 0 106 #else 107 #define FLATBUFFERS_LITTLEENDIAN 1 108 #endif // __BIG_ENDIAN__ 109 #elif defined(_MSC_VER) 110 #if defined(_M_PPC) 111 #define FLATBUFFERS_LITTLEENDIAN 0 112 #else 113 #define FLATBUFFERS_LITTLEENDIAN 1 114 #endif 115 #else 116 #error Unable to determine endianness, define FLATBUFFERS_LITTLEENDIAN. 117 #endif 118 #endif // !defined(FLATBUFFERS_LITTLEENDIAN) 119 120 #define FLATBUFFERS_VERSION_MAJOR 1 121 #define FLATBUFFERS_VERSION_MINOR 6 122 #define FLATBUFFERS_VERSION_REVISION 0 123 #define FLATBUFFERS_STRING_EXPAND(X) #X 124 #define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X) 125 126 #if (!defined(_MSC_VER) || _MSC_VER > 1600) && \ 127 (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407)) 128 #define FLATBUFFERS_FINAL_CLASS final 129 #else 130 #define FLATBUFFERS_FINAL_CLASS 131 #endif 132 133 #if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \ 134 (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) 135 #define FLATBUFFERS_CONSTEXPR constexpr 136 #else 137 #define FLATBUFFERS_CONSTEXPR 138 #endif 139 140 /// @endcond 141 142 /// @file 143 namespace flatbuffers { 144 145 /// @cond FLATBUFFERS_INTERNAL 146 // Our default offset / size type, 32bit on purpose on 64bit systems. 147 // Also, using a consistent offset type maintains compatibility of serialized 148 // offset values between 32bit and 64bit systems. 149 typedef uint32_t uoffset_t; 150 151 // Signed offsets for references that can go in both directions. 152 typedef int32_t soffset_t; 153 154 // Offset/index used in v-tables, can be changed to uint8_t in 155 // format forks to save a bit of space if desired. 156 typedef uint16_t voffset_t; 157 158 typedef uintmax_t largest_scalar_t; 159 160 // In 32bits, this evaluates to 2GB - 1 161 #define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(soffset_t) * 8 - 1)) - 1) 162 163 // We support aligning the contents of buffers up to this size. 164 #define FLATBUFFERS_MAX_ALIGNMENT 16 165 166 #ifndef FLATBUFFERS_CPP98_STL 167 // Pointer to relinquished memory. 168 typedef std::unique_ptr<uint8_t, std::function<void(uint8_t * /* unused */)>> 169 unique_ptr_t; 170 #endif 171 172 // Wrapper for uoffset_t to allow safe template specialization. 173 template<typename T> struct Offset { 174 uoffset_t o; 175 Offset() : o(0) {} 176 Offset(uoffset_t _o) : o(_o) {} 177 Offset<void> Union() const { return Offset<void>(o); } 178 }; 179 180 inline void EndianCheck() { 181 int endiantest = 1; 182 // If this fails, see FLATBUFFERS_LITTLEENDIAN above. 183 assert(*reinterpret_cast<char *>(&endiantest) == FLATBUFFERS_LITTLEENDIAN); 184 (void)endiantest; 185 } 186 187 template<typename T> T EndianSwap(T t) { 188 #if defined(_MSC_VER) 189 #define FLATBUFFERS_BYTESWAP16 _byteswap_ushort 190 #define FLATBUFFERS_BYTESWAP32 _byteswap_ulong 191 #define FLATBUFFERS_BYTESWAP64 _byteswap_uint64 192 #else 193 #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ < 408 194 // __builtin_bswap16 was missing prior to GCC 4.8. 195 #define FLATBUFFERS_BYTESWAP16(x) \ 196 static_cast<uint16_t>(__builtin_bswap32(static_cast<uint32_t>(x) << 16)) 197 #else 198 #define FLATBUFFERS_BYTESWAP16 __builtin_bswap16 199 #endif 200 #define FLATBUFFERS_BYTESWAP32 __builtin_bswap32 201 #define FLATBUFFERS_BYTESWAP64 __builtin_bswap64 202 #endif 203 if (sizeof(T) == 1) { // Compile-time if-then's. 204 return t; 205 } else if (sizeof(T) == 2) { 206 auto r = FLATBUFFERS_BYTESWAP16(*reinterpret_cast<uint16_t *>(&t)); 207 return *reinterpret_cast<T *>(&r); 208 } else if (sizeof(T) == 4) { 209 auto r = FLATBUFFERS_BYTESWAP32(*reinterpret_cast<uint32_t *>(&t)); 210 return *reinterpret_cast<T *>(&r); 211 } else if (sizeof(T) == 8) { 212 auto r = FLATBUFFERS_BYTESWAP64(*reinterpret_cast<uint64_t *>(&t)); 213 return *reinterpret_cast<T *>(&r); 214 } else { 215 assert(0); 216 } 217 } 218 219 template<typename T> T EndianScalar(T t) { 220 #if FLATBUFFERS_LITTLEENDIAN 221 return t; 222 #else 223 return EndianSwap(t); 224 #endif 225 } 226 227 template<typename T> T ReadScalar(const void *p) { 228 return EndianScalar(*reinterpret_cast<const T *>(p)); 229 } 230 231 template<typename T> void WriteScalar(void *p, T t) { 232 *reinterpret_cast<T *>(p) = EndianScalar(t); 233 } 234 235 template<typename T> size_t AlignOf() { 236 #ifdef _MSC_VER 237 return __alignof(T); 238 #else 239 #ifndef alignof 240 return __alignof__(T); 241 #else 242 return alignof(T); 243 #endif 244 #endif 245 } 246 247 // When we read serialized data from memory, in the case of most scalars, 248 // we want to just read T, but in the case of Offset, we want to actually 249 // perform the indirection and return a pointer. 250 // The template specialization below does just that. 251 // It is wrapped in a struct since function templates can't overload on the 252 // return type like this. 253 // The typedef is for the convenience of callers of this function 254 // (avoiding the need for a trailing return decltype) 255 template<typename T> struct IndirectHelper { 256 typedef T return_type; 257 typedef T mutable_return_type; 258 static const size_t element_stride = sizeof(T); 259 static return_type Read(const uint8_t *p, uoffset_t i) { 260 return EndianScalar((reinterpret_cast<const T *>(p))[i]); 261 } 262 }; 263 template<typename T> struct IndirectHelper<Offset<T>> { 264 typedef const T *return_type; 265 typedef T *mutable_return_type; 266 static const size_t element_stride = sizeof(uoffset_t); 267 static return_type Read(const uint8_t *p, uoffset_t i) { 268 p += i * sizeof(uoffset_t); 269 return reinterpret_cast<return_type>(p + ReadScalar<uoffset_t>(p)); 270 } 271 }; 272 template<typename T> struct IndirectHelper<const T *> { 273 typedef const T *return_type; 274 typedef T *mutable_return_type; 275 static const size_t element_stride = sizeof(T); 276 static return_type Read(const uint8_t *p, uoffset_t i) { 277 return reinterpret_cast<const T *>(p + i * sizeof(T)); 278 } 279 }; 280 281 // An STL compatible iterator implementation for Vector below, effectively 282 // calling Get() for every element. 283 template<typename T, typename IT> 284 struct VectorIterator 285 : public std::iterator<std::random_access_iterator_tag, IT, uoffset_t> { 286 287 typedef std::iterator<std::random_access_iterator_tag, IT, uoffset_t> super_type; 288 289 public: 290 VectorIterator(const uint8_t *data, uoffset_t i) : 291 data_(data + IndirectHelper<T>::element_stride * i) {} 292 VectorIterator(const VectorIterator &other) : data_(other.data_) {} 293 #ifndef FLATBUFFERS_CPP98_STL 294 VectorIterator(VectorIterator &&other) : data_(std::move(other.data_)) {} 295 #endif 296 297 VectorIterator &operator=(const VectorIterator &other) { 298 data_ = other.data_; 299 return *this; 300 } 301 302 VectorIterator &operator=(VectorIterator &&other) { 303 data_ = other.data_; 304 return *this; 305 } 306 307 bool operator==(const VectorIterator &other) const { 308 return data_ == other.data_; 309 } 310 311 bool operator!=(const VectorIterator &other) const { 312 return data_ != other.data_; 313 } 314 315 ptrdiff_t operator-(const VectorIterator &other) const { 316 return (data_ - other.data_) / IndirectHelper<T>::element_stride; 317 } 318 319 typename super_type::value_type operator *() const { 320 return IndirectHelper<T>::Read(data_, 0); 321 } 322 323 typename super_type::value_type operator->() const { 324 return IndirectHelper<T>::Read(data_, 0); 325 } 326 327 VectorIterator &operator++() { 328 data_ += IndirectHelper<T>::element_stride; 329 return *this; 330 } 331 332 VectorIterator operator++(int) { 333 VectorIterator temp(data_, 0); 334 data_ += IndirectHelper<T>::element_stride; 335 return temp; 336 } 337 338 VectorIterator operator+(const uoffset_t &offset) { 339 return VectorIterator(data_ + offset * IndirectHelper<T>::element_stride, 0); 340 } 341 342 VectorIterator& operator+=(const uoffset_t &offset) { 343 data_ += offset * IndirectHelper<T>::element_stride; 344 return *this; 345 } 346 347 VectorIterator &operator--() { 348 data_ -= IndirectHelper<T>::element_stride; 349 return *this; 350 } 351 352 VectorIterator operator--(int) { 353 VectorIterator temp(data_, 0); 354 data_ -= IndirectHelper<T>::element_stride; 355 return temp; 356 } 357 358 VectorIterator operator-(const uoffset_t &offset) { 359 return VectorIterator(data_ - offset * IndirectHelper<T>::element_stride, 0); 360 } 361 362 VectorIterator& operator-=(const uoffset_t &offset) { 363 data_ -= offset * IndirectHelper<T>::element_stride; 364 return *this; 365 } 366 367 private: 368 const uint8_t *data_; 369 }; 370 371 // This is used as a helper type for accessing vectors. 372 // Vector::data() assumes the vector elements start after the length field. 373 template<typename T> class Vector { 374 public: 375 typedef VectorIterator<T, typename IndirectHelper<T>::mutable_return_type> 376 iterator; 377 typedef VectorIterator<T, typename IndirectHelper<T>::return_type> 378 const_iterator; 379 380 uoffset_t size() const { return EndianScalar(length_); } 381 382 // Deprecated: use size(). Here for backwards compatibility. 383 uoffset_t Length() const { return size(); } 384 385 typedef typename IndirectHelper<T>::return_type return_type; 386 typedef typename IndirectHelper<T>::mutable_return_type mutable_return_type; 387 388 return_type Get(uoffset_t i) const { 389 assert(i < size()); 390 return IndirectHelper<T>::Read(Data(), i); 391 } 392 393 return_type operator[](uoffset_t i) const { return Get(i); } 394 395 // If this is a Vector of enums, T will be its storage type, not the enum 396 // type. This function makes it convenient to retrieve value with enum 397 // type E. 398 template<typename E> E GetEnum(uoffset_t i) const { 399 return static_cast<E>(Get(i)); 400 } 401 402 const void *GetStructFromOffset(size_t o) const { 403 return reinterpret_cast<const void *>(Data() + o); 404 } 405 406 iterator begin() { return iterator(Data(), 0); } 407 const_iterator begin() const { return const_iterator(Data(), 0); } 408 409 iterator end() { return iterator(Data(), size()); } 410 const_iterator end() const { return const_iterator(Data(), size()); } 411 412 // Change elements if you have a non-const pointer to this object. 413 // Scalars only. See reflection.h, and the documentation. 414 void Mutate(uoffset_t i, const T& val) { 415 assert(i < size()); 416 WriteScalar(data() + i, val); 417 } 418 419 // Change an element of a vector of tables (or strings). 420 // "val" points to the new table/string, as you can obtain from 421 // e.g. reflection::AddFlatBuffer(). 422 void MutateOffset(uoffset_t i, const uint8_t *val) { 423 assert(i < size()); 424 assert(sizeof(T) == sizeof(uoffset_t)); 425 WriteScalar(data() + i, 426 static_cast<uoffset_t>(val - (Data() + i * sizeof(uoffset_t)))); 427 } 428 429 // Get a mutable pointer to tables/strings inside this vector. 430 mutable_return_type GetMutableObject(uoffset_t i) const { 431 assert(i < size()); 432 return const_cast<mutable_return_type>(IndirectHelper<T>::Read(Data(), i)); 433 } 434 435 // The raw data in little endian format. Use with care. 436 const uint8_t *Data() const { 437 return reinterpret_cast<const uint8_t *>(&length_ + 1); 438 } 439 440 uint8_t *Data() { 441 return reinterpret_cast<uint8_t *>(&length_ + 1); 442 } 443 444 // Similarly, but typed, much like std::vector::data 445 const T *data() const { return reinterpret_cast<const T *>(Data()); } 446 T *data() { return reinterpret_cast<T *>(Data()); } 447 448 template<typename K> return_type LookupByKey(K key) const { 449 void *search_result = std::bsearch(&key, Data(), size(), 450 IndirectHelper<T>::element_stride, KeyCompare<K>); 451 452 if (!search_result) { 453 return nullptr; // Key not found. 454 } 455 456 const uint8_t *element = reinterpret_cast<const uint8_t *>(search_result); 457 458 return IndirectHelper<T>::Read(element, 0); 459 } 460 461 protected: 462 // This class is only used to access pre-existing data. Don't ever 463 // try to construct these manually. 464 Vector(); 465 466 uoffset_t length_; 467 468 private: 469 template<typename K> static int KeyCompare(const void *ap, const void *bp) { 470 const K *key = reinterpret_cast<const K *>(ap); 471 const uint8_t *data = reinterpret_cast<const uint8_t *>(bp); 472 auto table = IndirectHelper<T>::Read(data, 0); 473 474 // std::bsearch compares with the operands transposed, so we negate the 475 // result here. 476 return -table->KeyCompareWithValue(*key); 477 } 478 }; 479 480 // Represent a vector much like the template above, but in this case we 481 // don't know what the element types are (used with reflection.h). 482 class VectorOfAny { 483 public: 484 uoffset_t size() const { return EndianScalar(length_); } 485 486 const uint8_t *Data() const { 487 return reinterpret_cast<const uint8_t *>(&length_ + 1); 488 } 489 uint8_t *Data() { 490 return reinterpret_cast<uint8_t *>(&length_ + 1); 491 } 492 protected: 493 VectorOfAny(); 494 495 uoffset_t length_; 496 }; 497 498 // Convenient helper function to get the length of any vector, regardless 499 // of wether it is null or not (the field is not set). 500 template<typename T> static inline size_t VectorLength(const Vector<T> *v) { 501 return v ? v->Length() : 0; 502 } 503 504 #ifndef FLATBUFFERS_CHRE 505 struct String : public Vector<char> { 506 const char *c_str() const { return reinterpret_cast<const char *>(Data()); } 507 std::string str() const { return std::string(c_str(), Length()); } 508 509 bool operator <(const String &o) const { 510 return strcmp(c_str(), o.c_str()) < 0; 511 } 512 }; 513 #endif // FLATBUFFERS_CHRE 514 515 // Simple indirection for buffer allocation, to allow this to be overridden 516 // with custom allocation (see the FlatBufferBuilder constructor). 517 class simple_allocator { 518 public: 519 virtual ~simple_allocator() {} 520 virtual uint8_t *allocate(size_t size) const { 521 #ifndef FLATBUFFERS_CHRE 522 return new uint8_t[size]; 523 #else 524 return static_cast<uint8_t *>(chre::memoryAlloc(size)); 525 #endif 526 } 527 virtual void deallocate(uint8_t *p) const { 528 #ifndef FLATBUFFERS_CHRE 529 delete[] p; 530 #else 531 return chre::memoryFree(p); 532 #endif 533 } 534 }; 535 536 // This is a minimal replication of std::vector<uint8_t> functionality, 537 // except growing from higher to lower addresses. i.e push_back() inserts data 538 // in the lowest address in the vector. 539 class vector_downward { 540 public: 541 explicit vector_downward(size_t initial_size, 542 const simple_allocator &allocator) 543 : reserved_((initial_size + sizeof(largest_scalar_t) - 1) & 544 ~(sizeof(largest_scalar_t) - 1)), 545 buf_(allocator.allocate(reserved_)), 546 cur_(buf_ + reserved_), 547 allocator_(allocator) {} 548 549 ~vector_downward() { 550 if (buf_) 551 allocator_.deallocate(buf_); 552 } 553 554 void clear() { 555 if (buf_ == nullptr) 556 buf_ = allocator_.allocate(reserved_); 557 558 cur_ = buf_ + reserved_; 559 } 560 561 #ifndef FLATBUFFERS_CPP98_STL 562 // Relinquish the pointer to the caller. 563 unique_ptr_t release() { 564 // Actually deallocate from the start of the allocated memory. 565 std::function<void(uint8_t *)> deleter( 566 std::bind(&simple_allocator::deallocate, allocator_, buf_)); 567 568 // Point to the desired offset. 569 unique_ptr_t retval(data(), deleter); 570 571 // Don't deallocate when this instance is destroyed. 572 buf_ = nullptr; 573 cur_ = nullptr; 574 575 return retval; 576 } 577 #endif 578 579 size_t growth_policy(size_t bytes) { 580 return (bytes / 2) & ~(sizeof(largest_scalar_t) - 1); 581 } 582 583 uint8_t *make_space(size_t len) { 584 if (len > static_cast<size_t>(cur_ - buf_)) { 585 reallocate(len); 586 } 587 cur_ -= len; 588 // Beyond this, signed offsets may not have enough range: 589 // (FlatBuffers > 2GB not supported). 590 assert(size() < FLATBUFFERS_MAX_BUFFER_SIZE); 591 return cur_; 592 } 593 594 uoffset_t size() const { 595 assert(cur_ != nullptr && buf_ != nullptr); 596 return static_cast<uoffset_t>(reserved_ - static_cast<size_t>(cur_ - buf_)); 597 } 598 599 uint8_t *data() const { 600 assert(cur_ != nullptr); 601 return cur_; 602 } 603 604 uint8_t *data_at(size_t offset) const { return buf_ + reserved_ - offset; } 605 606 void push(const uint8_t *bytes, size_t num) { 607 auto dest = make_space(num); 608 memcpy(dest, bytes, num); 609 } 610 611 // Specialized version of push() that avoids memcpy call for small data. 612 template<typename T> void push_small(T little_endian_t) { 613 auto dest = make_space(sizeof(T)); 614 *reinterpret_cast<T *>(dest) = little_endian_t; 615 } 616 617 // fill() is most frequently called with small byte counts (<= 4), 618 // which is why we're using loops rather than calling memset. 619 void fill(size_t zero_pad_bytes) { 620 auto dest = make_space(zero_pad_bytes); 621 for (size_t i = 0; i < zero_pad_bytes; i++) dest[i] = 0; 622 } 623 624 // Version for when we know the size is larger. 625 void fill_big(size_t zero_pad_bytes) { 626 auto dest = make_space(zero_pad_bytes); 627 memset(dest, 0, zero_pad_bytes); 628 } 629 630 void pop(size_t bytes_to_remove) { cur_ += bytes_to_remove; } 631 632 private: 633 // You shouldn't really be copying instances of this class. 634 vector_downward(const vector_downward &); 635 vector_downward &operator=(const vector_downward &); 636 637 size_t reserved_; 638 uint8_t *buf_; 639 uint8_t *cur_; // Points at location between empty (below) and used (above). 640 const simple_allocator &allocator_; 641 642 void reallocate(size_t len) { 643 auto old_size = size(); 644 auto largest_align = AlignOf<largest_scalar_t>(); 645 reserved_ += (std::max)(len, growth_policy(reserved_)); 646 // Round up to avoid undefined behavior from unaligned loads and stores. 647 reserved_ = (reserved_ + (largest_align - 1)) & ~(largest_align - 1); 648 auto new_buf = allocator_.allocate(reserved_); 649 auto new_cur = new_buf + reserved_ - old_size; 650 memcpy(new_cur, cur_, old_size); 651 cur_ = new_cur; 652 allocator_.deallocate(buf_); 653 buf_ = new_buf; 654 } 655 }; 656 657 // Converts a Field ID to a virtual table offset. 658 inline voffset_t FieldIndexToOffset(voffset_t field_id) { 659 // Should correspond to what EndTable() below builds up. 660 const int fixed_fields = 2; // Vtable size and Object Size. 661 return static_cast<voffset_t>((field_id + fixed_fields) * sizeof(voffset_t)); 662 } 663 664 // Computes how many bytes you'd have to pad to be able to write an 665 // "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in 666 // memory). 667 inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) { 668 return ((~buf_size) + 1) & (scalar_size - 1); 669 } 670 671 template <typename T> const T* data(const std::vector<T> &v) { 672 return v.empty() ? nullptr : &v.front(); 673 } 674 template <typename T> T* data(std::vector<T> &v) { 675 return v.empty() ? nullptr : &v.front(); 676 } 677 678 /// @endcond 679 680 /// @addtogroup flatbuffers_cpp_api 681 /// @{ 682 /// @class FlatBufferBuilder 683 /// @brief Helper class to hold data needed in creation of a FlatBuffer. 684 /// To serialize data, you typically call one of the `Create*()` functions in 685 /// the generated code, which in turn call a sequence of `StartTable`/ 686 /// `PushElement`/`AddElement`/`EndTable`, or the builtin `CreateString`/ 687 /// `CreateVector` functions. Do this is depth-first order to build up a tree to 688 /// the root. `Finish()` wraps up the buffer ready for transport. 689 class FlatBufferBuilder 690 /// @cond FLATBUFFERS_INTERNAL 691 FLATBUFFERS_FINAL_CLASS 692 /// @endcond 693 { 694 public: 695 /// @brief Default constructor for FlatBufferBuilder. 696 /// @param[in] initial_size The initial size of the buffer, in bytes. Defaults 697 /// to`1024`. 698 /// @param[in] allocator A pointer to the `simple_allocator` that should be 699 /// used. Defaults to `nullptr`, which means the `default_allocator` will be 700 /// be used. 701 explicit FlatBufferBuilder(uoffset_t initial_size = 1024, 702 const simple_allocator *allocator = nullptr) 703 : buf_(initial_size, allocator ? *allocator : default_allocator), 704 nested(false), finished(false), minalign_(1), force_defaults_(false), 705 dedup_vtables_(true) { 706 #ifndef FLATBUFFERS_CHRE 707 string_pool = nullptr; 708 #endif 709 710 offsetbuf_.reserve(16); // Avoid first few reallocs. 711 vtables_.reserve(16); 712 EndianCheck(); 713 } 714 715 ~FlatBufferBuilder() { 716 #ifndef FLATBUFFERS_CHRE 717 if (string_pool) delete string_pool; 718 #endif 719 } 720 721 /// @brief Reset all the state in this FlatBufferBuilder so it can be reused 722 /// to construct another buffer. 723 void Clear() { 724 buf_.clear(); 725 offsetbuf_.clear(); 726 nested = false; 727 finished = false; 728 vtables_.clear(); 729 minalign_ = 1; 730 #ifndef FLATBUFFERS_CHRE 731 if (string_pool) string_pool->clear(); 732 #endif 733 } 734 735 /// @brief The current size of the serialized buffer, counting from the end. 736 /// @return Returns an `uoffset_t` with the current size of the buffer. 737 uoffset_t GetSize() const { return buf_.size(); } 738 739 /// @brief Get the serialized buffer (after you call `Finish()`). 740 /// @return Returns an `uint8_t` pointer to the FlatBuffer data inside the 741 /// buffer. 742 uint8_t *GetBufferPointer() const { 743 Finished(); 744 return buf_.data(); 745 } 746 747 /// @brief Get a pointer to an unfinished buffer. 748 /// @return Returns a `uint8_t` pointer to the unfinished buffer. 749 uint8_t *GetCurrentBufferPointer() const { return buf_.data(); } 750 751 #ifndef FLATBUFFERS_CPP98_STL 752 /// @brief Get the released pointer to the serialized buffer. 753 /// @warning Do NOT attempt to use this FlatBufferBuilder afterwards! 754 /// @return The `unique_ptr` returned has a special allocator that knows how 755 /// to deallocate this pointer (since it points to the middle of an 756 /// allocation). Thus, do not mix this pointer with other `unique_ptr`'s, or 757 /// call `release()`/`reset()` on it. 758 unique_ptr_t ReleaseBufferPointer() { 759 Finished(); 760 return buf_.release(); 761 } 762 #endif 763 764 /// @brief get the minimum alignment this buffer needs to be accessed 765 /// properly. This is only known once all elements have been written (after 766 /// you call Finish()). You can use this information if you need to embed 767 /// a FlatBuffer in some other buffer, such that you can later read it 768 /// without first having to copy it into its own buffer. 769 size_t GetBufferMinAlignment() { 770 Finished(); 771 return minalign_; 772 } 773 774 /// @cond FLATBUFFERS_INTERNAL 775 void Finished() const { 776 // If you get this assert, you're attempting to get access a buffer 777 // which hasn't been finished yet. Be sure to call 778 // FlatBufferBuilder::Finish with your root table. 779 // If you really need to access an unfinished buffer, call 780 // GetCurrentBufferPointer instead. 781 assert(finished); 782 } 783 /// @endcond 784 785 /// @brief In order to save space, fields that are set to their default value 786 /// don't get serialized into the buffer. 787 /// @param[in] bool fd When set to `true`, always serializes default values. 788 void ForceDefaults(bool fd) { force_defaults_ = fd; } 789 790 /// @brief By default vtables are deduped in order to save space. 791 /// @param[in] bool dedup When set to `true`, dedup vtables. 792 void DedupVtables(bool dedup) { dedup_vtables_ = dedup; } 793 794 /// @cond FLATBUFFERS_INTERNAL 795 void Pad(size_t num_bytes) { buf_.fill(num_bytes); } 796 797 void Align(size_t elem_size) { 798 if (elem_size > minalign_) minalign_ = elem_size; 799 buf_.fill(PaddingBytes(buf_.size(), elem_size)); 800 } 801 802 void PushFlatBuffer(const uint8_t *bytes, size_t size) { 803 PushBytes(bytes, size); 804 finished = true; 805 } 806 807 void PushBytes(const uint8_t *bytes, size_t size) { 808 buf_.push(bytes, size); 809 } 810 811 void PopBytes(size_t amount) { buf_.pop(amount); } 812 813 template<typename T> void AssertScalarT() { 814 #ifndef FLATBUFFERS_CPP98_STL 815 // The code assumes power of 2 sizes and endian-swap-ability. 816 static_assert(std::is_scalar<T>::value 817 // The Offset<T> type is essentially a scalar but fails is_scalar. 818 || sizeof(T) == sizeof(Offset<void>), 819 "T must be a scalar type"); 820 #endif 821 } 822 823 // Write a single aligned scalar to the buffer 824 template<typename T> uoffset_t PushElement(T element) { 825 AssertScalarT<T>(); 826 T litle_endian_element = EndianScalar(element); 827 Align(sizeof(T)); 828 buf_.push_small(litle_endian_element); 829 return GetSize(); 830 } 831 832 template<typename T> uoffset_t PushElement(Offset<T> off) { 833 // Special case for offsets: see ReferTo below. 834 return PushElement(ReferTo(off.o)); 835 } 836 837 // When writing fields, we track where they are, so we can create correct 838 // vtables later. 839 void TrackField(voffset_t field, uoffset_t off) { 840 FieldLoc fl = { off, field }; 841 offsetbuf_.push_back(fl); 842 } 843 844 // Like PushElement, but additionally tracks the field this represents. 845 template<typename T> void AddElement(voffset_t field, T e, T def) { 846 // We don't serialize values equal to the default. 847 if (e == def && !force_defaults_) return; 848 auto off = PushElement(e); 849 TrackField(field, off); 850 } 851 852 template<typename T> void AddOffset(voffset_t field, Offset<T> off) { 853 if (!off.o) return; // An offset of 0 means NULL, don't store. 854 AddElement(field, ReferTo(off.o), static_cast<uoffset_t>(0)); 855 } 856 857 template<typename T> void AddStruct(voffset_t field, const T *structptr) { 858 if (!structptr) return; // Default, don't store. 859 Align(AlignOf<T>()); 860 buf_.push_small(*structptr); 861 TrackField(field, GetSize()); 862 } 863 864 void AddStructOffset(voffset_t field, uoffset_t off) { 865 TrackField(field, off); 866 } 867 868 // Offsets initially are relative to the end of the buffer (downwards). 869 // This function converts them to be relative to the current location 870 // in the buffer (when stored here), pointing upwards. 871 uoffset_t ReferTo(uoffset_t off) { 872 // Align to ensure GetSize() below is correct. 873 Align(sizeof(uoffset_t)); 874 // Offset must refer to something already in buffer. 875 assert(off && off <= GetSize()); 876 return GetSize() - off + static_cast<uoffset_t>(sizeof(uoffset_t)); 877 } 878 879 void NotNested() { 880 // If you hit this, you're trying to construct a Table/Vector/String 881 // during the construction of its parent table (between the MyTableBuilder 882 // and table.Finish(). 883 // Move the creation of these sub-objects to above the MyTableBuilder to 884 // not get this assert. 885 // Ignoring this assert may appear to work in simple cases, but the reason 886 // it is here is that storing objects in-line may cause vtable offsets 887 // to not fit anymore. It also leads to vtable duplication. 888 assert(!nested); 889 } 890 891 // From generated code (or from the parser), we call StartTable/EndTable 892 // with a sequence of AddElement calls in between. 893 uoffset_t StartTable() { 894 NotNested(); 895 nested = true; 896 return GetSize(); 897 } 898 899 // This finishes one serialized object by generating the vtable if it's a 900 // table, comparing it against existing vtables, and writing the 901 // resulting vtable offset. 902 uoffset_t EndTable(uoffset_t start, voffset_t numfields) { 903 // If you get this assert, a corresponding StartTable wasn't called. 904 assert(nested); 905 // Write the vtable offset, which is the start of any Table. 906 // We fill it's value later. 907 auto vtableoffsetloc = PushElement<soffset_t>(0); 908 // Write a vtable, which consists entirely of voffset_t elements. 909 // It starts with the number of offsets, followed by a type id, followed 910 // by the offsets themselves. In reverse: 911 buf_.fill_big(numfields * sizeof(voffset_t)); 912 auto table_object_size = vtableoffsetloc - start; 913 assert(table_object_size < 0x10000); // Vtable use 16bit offsets. 914 PushElement<voffset_t>(static_cast<voffset_t>(table_object_size)); 915 PushElement<voffset_t>(FieldIndexToOffset(numfields)); 916 // Write the offsets into the table 917 for (auto field_location = offsetbuf_.begin(); 918 field_location != offsetbuf_.end(); 919 ++field_location) { 920 auto pos = static_cast<voffset_t>(vtableoffsetloc - field_location->off); 921 // If this asserts, it means you've set a field twice. 922 assert(!ReadScalar<voffset_t>(buf_.data() + field_location->id)); 923 WriteScalar<voffset_t>(buf_.data() + field_location->id, pos); 924 } 925 offsetbuf_.clear(); 926 auto vt1 = reinterpret_cast<voffset_t *>(buf_.data()); 927 auto vt1_size = ReadScalar<voffset_t>(vt1); 928 auto vt_use = GetSize(); 929 // See if we already have generated a vtable with this exact same 930 // layout before. If so, make it point to the old one, remove this one. 931 if (dedup_vtables_) { 932 for (auto it = vtables_.begin(); it != vtables_.end(); ++it) { 933 auto vt2 = reinterpret_cast<voffset_t *>(buf_.data_at(*it)); 934 auto vt2_size = *vt2; 935 if (vt1_size != vt2_size || memcmp(vt2, vt1, vt1_size)) continue; 936 vt_use = *it; 937 buf_.pop(GetSize() - vtableoffsetloc); 938 break; 939 } 940 } 941 // If this is a new vtable, remember it. 942 if (vt_use == GetSize()) { 943 vtables_.push_back(vt_use); 944 } 945 // Fill the vtable offset we created above. 946 // The offset points from the beginning of the object to where the 947 // vtable is stored. 948 // Offsets default direction is downward in memory for future format 949 // flexibility (storing all vtables at the start of the file). 950 WriteScalar(buf_.data_at(vtableoffsetloc), 951 static_cast<soffset_t>(vt_use) - 952 static_cast<soffset_t>(vtableoffsetloc)); 953 954 nested = false; 955 return vtableoffsetloc; 956 } 957 958 // This checks a required field has been set in a given table that has 959 // just been constructed. 960 template<typename T> void Required(Offset<T> table, voffset_t field) { 961 auto table_ptr = buf_.data_at(table.o); 962 auto vtable_ptr = table_ptr - ReadScalar<soffset_t>(table_ptr); 963 bool ok = ReadScalar<voffset_t>(vtable_ptr + field) != 0; 964 // If this fails, the caller will show what field needs to be set. 965 assert(ok); 966 (void)ok; 967 } 968 969 uoffset_t StartStruct(size_t alignment) { 970 Align(alignment); 971 return GetSize(); 972 } 973 974 uoffset_t EndStruct() { return GetSize(); } 975 976 void ClearOffsets() { offsetbuf_.clear(); } 977 978 // Aligns such that when "len" bytes are written, an object can be written 979 // after it with "alignment" without padding. 980 void PreAlign(size_t len, size_t alignment) { 981 buf_.fill(PaddingBytes(GetSize() + len, alignment)); 982 } 983 template<typename T> void PreAlign(size_t len) { 984 AssertScalarT<T>(); 985 PreAlign(len, sizeof(T)); 986 } 987 /// @endcond 988 989 #ifndef FLATBUFFERS_CHRE 990 /// @brief Store a string in the buffer, which can contain any binary data. 991 /// @param[in] str A const char pointer to the data to be stored as a string. 992 /// @param[in] len The number of bytes that should be stored from `str`. 993 /// @return Returns the offset in the buffer where the string starts. 994 Offset<String> CreateString(const char *str, size_t len) { 995 NotNested(); 996 PreAlign<uoffset_t>(len + 1); // Always 0-terminated. 997 buf_.fill(1); 998 PushBytes(reinterpret_cast<const uint8_t *>(str), len); 999 PushElement(static_cast<uoffset_t>(len)); 1000 return Offset<String>(GetSize()); 1001 } 1002 1003 /// @brief Store a string in the buffer, which is null-terminated. 1004 /// @param[in] str A const char pointer to a C-string to add to the buffer. 1005 /// @return Returns the offset in the buffer where the string starts. 1006 Offset<String> CreateString(const char *str) { 1007 return CreateString(str, strlen(str)); 1008 } 1009 1010 /// @brief Store a string in the buffer, which can contain any binary data. 1011 /// @param[in] str A const reference to a std::string to store in the buffer. 1012 /// @return Returns the offset in the buffer where the string starts. 1013 Offset<String> CreateString(const std::string &str) { 1014 return CreateString(str.c_str(), str.length()); 1015 } 1016 1017 /// @brief Store a string in the buffer, which can contain any binary data. 1018 /// @param[in] str A const pointer to a `String` struct to add to the buffer. 1019 /// @return Returns the offset in the buffer where the string starts 1020 Offset<String> CreateString(const String *str) { 1021 return str ? CreateString(str->c_str(), str->Length()) : 0; 1022 } 1023 1024 /// @brief Store a string in the buffer, which can contain any binary data. 1025 /// If a string with this exact contents has already been serialized before, 1026 /// instead simply returns the offset of the existing string. 1027 /// @param[in] str A const char pointer to the data to be stored as a string. 1028 /// @param[in] len The number of bytes that should be stored from `str`. 1029 /// @return Returns the offset in the buffer where the string starts. 1030 Offset<String> CreateSharedString(const char *str, size_t len) { 1031 if (!string_pool) 1032 string_pool = new StringOffsetMap(StringOffsetCompare(buf_)); 1033 auto size_before_string = buf_.size(); 1034 // Must first serialize the string, since the set is all offsets into 1035 // buffer. 1036 auto off = CreateString(str, len); 1037 auto it = string_pool->find(off); 1038 // If it exists we reuse existing serialized data! 1039 if (it != string_pool->end()) { 1040 // We can remove the string we serialized. 1041 buf_.pop(buf_.size() - size_before_string); 1042 return *it; 1043 } 1044 // Record this string for future use. 1045 string_pool->insert(off); 1046 return off; 1047 } 1048 1049 /// @brief Store a string in the buffer, which null-terminated. 1050 /// If a string with this exact contents has already been serialized before, 1051 /// instead simply returns the offset of the existing string. 1052 /// @param[in] str A const char pointer to a C-string to add to the buffer. 1053 /// @return Returns the offset in the buffer where the string starts. 1054 Offset<String> CreateSharedString(const char *str) { 1055 return CreateSharedString(str, strlen(str)); 1056 } 1057 1058 /// @brief Store a string in the buffer, which can contain any binary data. 1059 /// If a string with this exact contents has already been serialized before, 1060 /// instead simply returns the offset of the existing string. 1061 /// @param[in] str A const reference to a std::string to store in the buffer. 1062 /// @return Returns the offset in the buffer where the string starts. 1063 Offset<String> CreateSharedString(const std::string &str) { 1064 return CreateSharedString(str.c_str(), str.length()); 1065 } 1066 1067 /// @brief Store a string in the buffer, which can contain any binary data. 1068 /// If a string with this exact contents has already been serialized before, 1069 /// instead simply returns the offset of the existing string. 1070 /// @param[in] str A const pointer to a `String` struct to add to the buffer. 1071 /// @return Returns the offset in the buffer where the string starts 1072 Offset<String> CreateSharedString(const String *str) { 1073 return CreateSharedString(str->c_str(), str->Length()); 1074 } 1075 #endif // FLATBUFFERS_CHRE 1076 1077 /// @cond FLATBUFFERS_INTERNAL 1078 uoffset_t EndVector(size_t len) { 1079 assert(nested); // Hit if no corresponding StartVector. 1080 nested = false; 1081 return PushElement(static_cast<uoffset_t>(len)); 1082 } 1083 1084 void StartVector(size_t len, size_t elemsize) { 1085 NotNested(); 1086 nested = true; 1087 PreAlign<uoffset_t>(len * elemsize); 1088 PreAlign(len * elemsize, elemsize); // Just in case elemsize > uoffset_t. 1089 } 1090 1091 // Call this right before StartVector/CreateVector if you want to force the 1092 // alignment to be something different than what the element size would 1093 // normally dictate. 1094 // This is useful when storing a nested_flatbuffer in a vector of bytes, 1095 // or when storing SIMD floats, etc. 1096 void ForceVectorAlignment(size_t len, size_t elemsize, size_t alignment) { 1097 PreAlign(len * elemsize, alignment); 1098 } 1099 1100 uint8_t *ReserveElements(size_t len, size_t elemsize) { 1101 return buf_.make_space(len * elemsize); 1102 } 1103 /// @endcond 1104 1105 /// @brief Serialize an array into a FlatBuffer `vector`. 1106 /// @tparam T The data type of the array elements. 1107 /// @param[in] v A pointer to the array of type `T` to serialize into the 1108 /// buffer as a `vector`. 1109 /// @param[in] len The number of elements to serialize. 1110 /// @return Returns a typed `Offset` into the serialized data indicating 1111 /// where the vector is stored. 1112 template<typename T> Offset<Vector<T>> CreateVector(const T *v, size_t len) { 1113 StartVector(len, sizeof(T)); 1114 for (auto i = len; i > 0; ) { 1115 PushElement(v[--i]); 1116 } 1117 return Offset<Vector<T>>(EndVector(len)); 1118 } 1119 1120 #ifndef FLATBUFFERS_CHRE 1121 /// @brief Serialize a `std::vector` into a FlatBuffer `vector`. 1122 /// @tparam T The data type of the `std::vector` elements. 1123 /// @param v A const reference to the `std::vector` to serialize into the 1124 /// buffer as a `vector`. 1125 /// @return Returns a typed `Offset` into the serialized data indicating 1126 /// where the vector is stored. 1127 template<typename T> Offset<Vector<T>> CreateVector(const std::vector<T> &v) { 1128 return CreateVector(data(v), v.size()); 1129 } 1130 1131 // vector<bool> may be implemented using a bit-set, so we can't access it as 1132 // an array. Instead, read elements manually. 1133 // Background: https://isocpp.org/blog/2012/11/on-vectorbool 1134 Offset<Vector<uint8_t>> CreateVector(const std::vector<bool> &v) { 1135 StartVector(v.size(), sizeof(uint8_t)); 1136 for (auto i = v.size(); i > 0; ) { 1137 PushElement(static_cast<uint8_t>(v[--i])); 1138 } 1139 return Offset<Vector<uint8_t>>(EndVector(v.size())); 1140 } 1141 #else // FLATBUFFERS_CHRE 1142 // We need to define this function as it's optionally used in the 1143 // Create<Type>Direct() helper functions generated by the FlatBuffer compiler, 1144 // however its use at runtime is not supported. 1145 template<typename T> Offset<Vector<T>> CreateVector(const std::vector<T> &v) { 1146 // std::vector use by FlatBuffers is not supported in CHRE. 1147 CHRE_ASSERT(false); 1148 return 0; 1149 } 1150 1151 /// @brief Serialize a `chre::DynamicVector` into a FlatBuffer `vector`. 1152 /// @tparam T The data type of the `chre::DynamicVector` elements. 1153 /// @param v A const reference to the `chre::DynamicVector` to serialize into 1154 /// the buffer as a `vector`. 1155 /// @return Returns a typed `Offset` into the serialized data indicating 1156 /// where the vector is stored. 1157 template<typename T> Offset<Vector<T>> CreateVector( 1158 const chre::DynamicVector<T> &v) { 1159 return CreateVector(v.data(), v.size()); 1160 } 1161 #endif // FLATBUFFERS_CHRE 1162 1163 #ifndef FLATBUFFERS_CPP98_STL 1164 /// @brief Serialize values returned by a function into a FlatBuffer `vector`. 1165 /// This is a convenience function that takes care of iteration for you. 1166 /// @tparam T The data type of the `std::vector` elements. 1167 /// @param f A function that takes the current iteration 0..vector_size-1 and 1168 /// returns any type that you can construct a FlatBuffers vector out of. 1169 /// @return Returns a typed `Offset` into the serialized data indicating 1170 /// where the vector is stored. 1171 template<typename T> Offset<Vector<T>> CreateVector(size_t vector_size, 1172 const std::function<T (size_t i)> &f) { 1173 std::vector<T> elems(vector_size); 1174 for (size_t i = 0; i < vector_size; i++) elems[i] = f(i); 1175 return CreateVector(elems); 1176 } 1177 #endif 1178 1179 #ifndef FLATBUFFERS_CHRE 1180 /// @brief Serialize a `std::vector<std::string>` into a FlatBuffer `vector`. 1181 /// This is a convenience function for a common case. 1182 /// @param v A const reference to the `std::vector` to serialize into the 1183 /// buffer as a `vector`. 1184 /// @return Returns a typed `Offset` into the serialized data indicating 1185 /// where the vector is stored. 1186 Offset<Vector<Offset<String>>> CreateVectorOfStrings( 1187 const std::vector<std::string> &v) { 1188 std::vector<Offset<String>> offsets(v.size()); 1189 for (size_t i = 0; i < v.size(); i++) offsets[i] = CreateString(v[i]); 1190 return CreateVector(offsets); 1191 } 1192 #endif // FLATBUFFERS_CHRE 1193 1194 /// @brief Serialize an array of structs into a FlatBuffer `vector`. 1195 /// @tparam T The data type of the struct array elements. 1196 /// @param[in] v A pointer to the array of type `T` to serialize into the 1197 /// buffer as a `vector`. 1198 /// @param[in] len The number of elements to serialize. 1199 /// @return Returns a typed `Offset` into the serialized data indicating 1200 /// where the vector is stored. 1201 template<typename T> Offset<Vector<const T *>> CreateVectorOfStructs( 1202 const T *v, size_t len) { 1203 StartVector(len * sizeof(T) / AlignOf<T>(), AlignOf<T>()); 1204 PushBytes(reinterpret_cast<const uint8_t *>(v), sizeof(T) * len); 1205 return Offset<Vector<const T *>>(EndVector(len)); 1206 } 1207 1208 #ifndef FLATBUFFERS_CPP98_STL 1209 /// @brief Serialize an array of structs into a FlatBuffer `vector`. 1210 /// @tparam T The data type of the struct array elements. 1211 /// @param[in] f A function that takes the current iteration 0..vector_size-1 1212 /// and a pointer to the struct that must be filled. 1213 /// @return Returns a typed `Offset` into the serialized data indicating 1214 /// where the vector is stored. 1215 /// This is mostly useful when flatbuffers are generated with mutation 1216 /// accessors. 1217 template<typename T> Offset<Vector<const T *>> CreateVectorOfStructs( 1218 size_t vector_size, const std::function<void(size_t i, T *)> &filler) { 1219 StartVector(vector_size * sizeof(T) / AlignOf<T>(), AlignOf<T>()); 1220 T *structs = reinterpret_cast<T *>(buf_.make_space(vector_size * sizeof(T))); 1221 for (size_t i = 0; i < vector_size; i++) { 1222 filler(i, structs); 1223 structs++; 1224 } 1225 return Offset<Vector<const T *>>(EndVector(vector_size)); 1226 } 1227 #endif 1228 1229 /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`. 1230 /// @tparam T The data type of the `std::vector` struct elements. 1231 /// @param[in]] v A const reference to the `std::vector` of structs to 1232 /// serialize into the buffer as a `vector`. 1233 /// @return Returns a typed `Offset` into the serialized data indicating 1234 /// where the vector is stored. 1235 template<typename T> Offset<Vector<const T *>> CreateVectorOfStructs( 1236 const std::vector<T> &v) { 1237 return CreateVectorOfStructs(data(v), v.size()); 1238 } 1239 1240 /// @cond FLATBUFFERS_INTERNAL 1241 template<typename T> 1242 struct TableKeyComparator { 1243 TableKeyComparator(vector_downward& buf) : buf_(buf) {} 1244 bool operator()(const Offset<T> &a, const Offset<T> &b) const { 1245 auto table_a = reinterpret_cast<T *>(buf_.data_at(a.o)); 1246 auto table_b = reinterpret_cast<T *>(buf_.data_at(b.o)); 1247 return table_a->KeyCompareLessThan(table_b); 1248 } 1249 vector_downward& buf_; 1250 1251 private: 1252 TableKeyComparator& operator= (const TableKeyComparator&); 1253 }; 1254 /// @endcond 1255 1256 #ifndef FLATBUFFERS_CHRE 1257 /// @brief Serialize an array of `table` offsets as a `vector` in the buffer 1258 /// in sorted order. 1259 /// @tparam T The data type that the offset refers to. 1260 /// @param[in] v An array of type `Offset<T>` that contains the `table` 1261 /// offsets to store in the buffer in sorted order. 1262 /// @param[in] len The number of elements to store in the `vector`. 1263 /// @return Returns a typed `Offset` into the serialized data indicating 1264 /// where the vector is stored. 1265 template<typename T> Offset<Vector<Offset<T>>> CreateVectorOfSortedTables( 1266 Offset<T> *v, size_t len) { 1267 std::sort(v, v + len, TableKeyComparator<T>(buf_)); 1268 return CreateVector(v, len); 1269 } 1270 1271 /// @brief Serialize an array of `table` offsets as a `vector` in the buffer 1272 /// in sorted order. 1273 /// @tparam T The data type that the offset refers to. 1274 /// @param[in] v An array of type `Offset<T>` that contains the `table` 1275 /// offsets to store in the buffer in sorted order. 1276 /// @return Returns a typed `Offset` into the serialized data indicating 1277 /// where the vector is stored. 1278 template<typename T> Offset<Vector<Offset<T>>> CreateVectorOfSortedTables( 1279 std::vector<Offset<T>> *v) { 1280 return CreateVectorOfSortedTables(data(*v), v->size()); 1281 } 1282 #endif // FLATBUFFERS_CHRE 1283 1284 /// @brief Specialized version of `CreateVector` for non-copying use cases. 1285 /// Write the data any time later to the returned buffer pointer `buf`. 1286 /// @param[in] len The number of elements to store in the `vector`. 1287 /// @param[in] elemsize The size of each element in the `vector`. 1288 /// @param[out] buf A pointer to a `uint8_t` pointer that can be 1289 /// written to at a later time to serialize the data into a `vector` 1290 /// in the buffer. 1291 uoffset_t CreateUninitializedVector(size_t len, size_t elemsize, 1292 uint8_t **buf) { 1293 NotNested(); 1294 StartVector(len, elemsize); 1295 buf_.make_space(len * elemsize); 1296 auto vec_start = GetSize(); 1297 auto vec_end = EndVector(len); 1298 *buf = buf_.data_at(vec_start); 1299 return vec_end; 1300 } 1301 1302 /// @brief Specialized version of `CreateVector` for non-copying use cases. 1303 /// Write the data any time later to the returned buffer pointer `buf`. 1304 /// @tparam T The data type of the data that will be stored in the buffer 1305 /// as a `vector`. 1306 /// @param[in] len The number of elements to store in the `vector`. 1307 /// @param[out] buf A pointer to a pointer of type `T` that can be 1308 /// written to at a later time to serialize the data into a `vector` 1309 /// in the buffer. 1310 template<typename T> Offset<Vector<T>> CreateUninitializedVector( 1311 size_t len, T **buf) { 1312 return CreateUninitializedVector(len, sizeof(T), 1313 reinterpret_cast<uint8_t **>(buf)); 1314 } 1315 1316 /// @brief The length of a FlatBuffer file header. 1317 static const size_t kFileIdentifierLength = 4; 1318 1319 /// @brief Finish serializing a buffer by writing the root offset. 1320 /// @param[in] file_identifier If a `file_identifier` is given, the buffer 1321 /// will be prefixed with a standard FlatBuffers file header. 1322 template<typename T> void Finish(Offset<T> root, 1323 const char *file_identifier = nullptr) { 1324 1325 Finish(root.o, file_identifier, false); 1326 } 1327 1328 /// @brief Finish a buffer with a 32 bit size field pre-fixed (size of the 1329 /// buffer following the size field). These buffers are NOT compatible 1330 /// with standard buffers created by Finish, i.e. you can't call GetRoot 1331 /// on them, you have to use GetSizePrefixedRoot instead. 1332 /// All >32 bit quantities in this buffer will be aligned when the whole 1333 /// size pre-fixed buffer is aligned. 1334 /// These kinds of buffers are useful for creating a stream of FlatBuffers. 1335 template<typename T> void FinishSizePrefixed(Offset<T> root, 1336 const char *file_identifier = nullptr) { 1337 Finish(root.o, file_identifier, true); 1338 } 1339 1340 private: 1341 // You shouldn't really be copying instances of this class. 1342 FlatBufferBuilder(const FlatBufferBuilder &); 1343 FlatBufferBuilder &operator=(const FlatBufferBuilder &); 1344 1345 void Finish(uoffset_t root, const char *file_identifier, bool size_prefix) { 1346 NotNested(); 1347 // This will cause the whole buffer to be aligned. 1348 PreAlign((size_prefix ? sizeof(uoffset_t) : 0) + 1349 sizeof(uoffset_t) + 1350 (file_identifier ? kFileIdentifierLength : 0), 1351 minalign_); 1352 if (file_identifier) { 1353 assert(strlen(file_identifier) == kFileIdentifierLength); 1354 PushBytes(reinterpret_cast<const uint8_t *>(file_identifier), 1355 kFileIdentifierLength); 1356 } 1357 PushElement(ReferTo(root)); // Location of root. 1358 if (size_prefix) { 1359 PushElement(GetSize()); 1360 } 1361 finished = true; 1362 } 1363 1364 struct FieldLoc { 1365 uoffset_t off; 1366 voffset_t id; 1367 }; 1368 1369 simple_allocator default_allocator; 1370 1371 vector_downward buf_; 1372 1373 #ifndef FLATBUFFERS_CHRE 1374 // Accumulating offsets of table members while it is being built. 1375 std::vector<FieldLoc> offsetbuf_; 1376 #else 1377 chre::DynamicVector<FieldLoc> offsetbuf_; 1378 #endif // FLATBUFFERS_CHRE 1379 1380 // Ensure objects are not nested. 1381 bool nested; 1382 1383 // Ensure the buffer is finished before it is being accessed. 1384 bool finished; 1385 1386 #ifndef FLATBUFFERS_CHRE 1387 std::vector<uoffset_t> vtables_; // todo: Could make this into a map? 1388 #else 1389 chre::DynamicVector<uoffset_t> vtables_; 1390 #endif 1391 1392 size_t minalign_; 1393 1394 bool force_defaults_; // Serialize values equal to their defaults anyway. 1395 1396 bool dedup_vtables_; 1397 1398 #ifndef FLATBUFFERS_CHRE 1399 struct StringOffsetCompare { 1400 StringOffsetCompare(const vector_downward &buf) : buf_(&buf) {} 1401 bool operator() (const Offset<String> &a, const Offset<String> &b) const { 1402 auto stra = reinterpret_cast<const String *>(buf_->data_at(a.o)); 1403 auto strb = reinterpret_cast<const String *>(buf_->data_at(b.o)); 1404 return strncmp(stra->c_str(), strb->c_str(), 1405 std::min(stra->size(), strb->size()) + 1) < 0; 1406 } 1407 const vector_downward *buf_; 1408 }; 1409 1410 // For use with CreateSharedString. Instantiated on first use only. 1411 typedef std::set<Offset<String>, StringOffsetCompare> StringOffsetMap; 1412 StringOffsetMap *string_pool; 1413 #endif // FLATBUFFERS_CHRE 1414 }; 1415 /// @} 1416 1417 /// @cond FLATBUFFERS_INTERNAL 1418 // Helpers to get a typed pointer to the root object contained in the buffer. 1419 template<typename T> T *GetMutableRoot(void *buf) { 1420 EndianCheck(); 1421 return reinterpret_cast<T *>(reinterpret_cast<uint8_t *>(buf) + 1422 EndianScalar(*reinterpret_cast<uoffset_t *>(buf))); 1423 } 1424 1425 template<typename T> const T *GetRoot(const void *buf) { 1426 return GetMutableRoot<T>(const_cast<void *>(buf)); 1427 } 1428 1429 template<typename T> const T *GetSizePrefixedRoot(const void *buf) { 1430 return GetRoot<T>(reinterpret_cast<const uint8_t *>(buf) + sizeof(uoffset_t)); 1431 } 1432 1433 /// Helpers to get a typed pointer to objects that are currently being built. 1434 /// @warning Creating new objects will lead to reallocations and invalidates 1435 /// the pointer! 1436 template<typename T> T *GetMutableTemporaryPointer(FlatBufferBuilder &fbb, 1437 Offset<T> offset) { 1438 return reinterpret_cast<T *>(fbb.GetCurrentBufferPointer() + 1439 fbb.GetSize() - offset.o); 1440 } 1441 1442 template<typename T> const T *GetTemporaryPointer(FlatBufferBuilder &fbb, 1443 Offset<T> offset) { 1444 return GetMutableTemporaryPointer<T>(fbb, offset); 1445 } 1446 1447 // Helper to see if the identifier in a buffer has the expected value. 1448 inline bool BufferHasIdentifier(const void *buf, const char *identifier) { 1449 return strncmp(reinterpret_cast<const char *>(buf) + sizeof(uoffset_t), 1450 identifier, FlatBufferBuilder::kFileIdentifierLength) == 0; 1451 } 1452 1453 // Helper class to verify the integrity of a FlatBuffer 1454 class Verifier FLATBUFFERS_FINAL_CLASS { 1455 public: 1456 Verifier(const uint8_t *buf, size_t buf_len, size_t _max_depth = 64, 1457 size_t _max_tables = 1000000) 1458 : buf_(buf), end_(buf + buf_len), depth_(0), max_depth_(_max_depth), 1459 num_tables_(0), max_tables_(_max_tables) 1460 #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE 1461 , upper_bound_(buf) 1462 #endif 1463 {} 1464 1465 // Central location where any verification failures register. 1466 bool Check(bool ok) const { 1467 #ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE 1468 assert(ok); 1469 #endif 1470 #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE 1471 if (!ok) 1472 upper_bound_ = buf_; 1473 #endif 1474 return ok; 1475 } 1476 1477 // Verify any range within the buffer. 1478 bool Verify(const void *elem, size_t elem_len) const { 1479 #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE 1480 auto upper_bound = reinterpret_cast<const uint8_t *>(elem) + elem_len; 1481 if (upper_bound_ < upper_bound) 1482 upper_bound_ = upper_bound; 1483 #endif 1484 return Check(elem_len <= (size_t) (end_ - buf_) && 1485 elem >= buf_ && 1486 elem <= end_ - elem_len); 1487 } 1488 1489 // Verify a range indicated by sizeof(T). 1490 template<typename T> bool Verify(const void *elem) const { 1491 return Verify(elem, sizeof(T)); 1492 } 1493 1494 // Verify a pointer (may be NULL) of a table type. 1495 template<typename T> bool VerifyTable(const T *table) { 1496 return !table || table->Verify(*this); 1497 } 1498 1499 // Verify a pointer (may be NULL) of any vector type. 1500 template<typename T> bool Verify(const Vector<T> *vec) const { 1501 const uint8_t *end; 1502 return !vec || 1503 VerifyVector(reinterpret_cast<const uint8_t *>(vec), sizeof(T), 1504 &end); 1505 } 1506 1507 // Verify a pointer (may be NULL) of a vector to struct. 1508 template<typename T> bool Verify(const Vector<const T *> *vec) const { 1509 return Verify(reinterpret_cast<const Vector<T> *>(vec)); 1510 } 1511 1512 #ifndef FLATBUFFERS_CHRE 1513 // Verify a pointer (may be NULL) to string. 1514 bool Verify(const String *str) const { 1515 const uint8_t *end; 1516 return !str || 1517 (VerifyVector(reinterpret_cast<const uint8_t *>(str), 1, &end) && 1518 Verify(end, 1) && // Must have terminator 1519 Check(*end == '\0')); // Terminating byte must be 0. 1520 } 1521 #endif // FLATBUFFERS_CHRE 1522 1523 // Common code between vectors and strings. 1524 bool VerifyVector(const uint8_t *vec, size_t elem_size, 1525 const uint8_t **end) const { 1526 // Check we can read the size field. 1527 if (!Verify<uoffset_t>(vec)) return false; 1528 // Check the whole array. If this is a string, the byte past the array 1529 // must be 0. 1530 auto size = ReadScalar<uoffset_t>(vec); 1531 auto max_elems = FLATBUFFERS_MAX_BUFFER_SIZE / elem_size; 1532 if (!Check(size < max_elems)) 1533 return false; // Protect against byte_size overflowing. 1534 auto byte_size = sizeof(size) + elem_size * size; 1535 *end = vec + byte_size; 1536 return Verify(vec, byte_size); 1537 } 1538 1539 #ifndef FLATBUFFERS_CHRE 1540 // Special case for string contents, after the above has been called. 1541 bool VerifyVectorOfStrings(const Vector<Offset<String>> *vec) const { 1542 if (vec) { 1543 for (uoffset_t i = 0; i < vec->size(); i++) { 1544 if (!Verify(vec->Get(i))) return false; 1545 } 1546 } 1547 return true; 1548 } 1549 #endif // FLATBUFFERS_CHRE 1550 1551 // Special case for table contents, after the above has been called. 1552 template<typename T> bool VerifyVectorOfTables(const Vector<Offset<T>> *vec) { 1553 if (vec) { 1554 for (uoffset_t i = 0; i < vec->size(); i++) { 1555 if (!vec->Get(i)->Verify(*this)) return false; 1556 } 1557 } 1558 return true; 1559 } 1560 1561 template<typename T> bool VerifyBufferFromStart(const char *identifier, 1562 const uint8_t *start) { 1563 if (identifier && 1564 (size_t(end_ - start) < 2 * sizeof(flatbuffers::uoffset_t) || 1565 !BufferHasIdentifier(start, identifier))) { 1566 return false; 1567 } 1568 1569 // Call T::Verify, which must be in the generated code for this type. 1570 return Verify<uoffset_t>(start) && 1571 reinterpret_cast<const T *>(start + ReadScalar<uoffset_t>(start))-> 1572 Verify(*this) 1573 #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE 1574 && GetComputedSize() 1575 #endif 1576 ; 1577 } 1578 1579 // Verify this whole buffer, starting with root type T. 1580 template<typename T> bool VerifyBuffer(const char *identifier) { 1581 return VerifyBufferFromStart<T>(identifier, buf_); 1582 } 1583 1584 template<typename T> bool VerifySizePrefixedBuffer(const char *identifier) { 1585 return Verify<uoffset_t>(buf_) && 1586 ReadScalar<uoffset_t>(buf_) == end_ - buf_ - sizeof(uoffset_t) && 1587 VerifyBufferFromStart<T>(identifier, buf_ + sizeof(uoffset_t)); 1588 } 1589 1590 // Called at the start of a table to increase counters measuring data 1591 // structure depth and amount, and possibly bails out with false if 1592 // limits set by the constructor have been hit. Needs to be balanced 1593 // with EndTable(). 1594 bool VerifyComplexity() { 1595 depth_++; 1596 num_tables_++; 1597 return Check(depth_ <= max_depth_ && num_tables_ <= max_tables_); 1598 } 1599 1600 // Called at the end of a table to pop the depth count. 1601 bool EndTable() { 1602 depth_--; 1603 return true; 1604 } 1605 1606 #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE 1607 // Returns the message size in bytes 1608 size_t GetComputedSize() const { 1609 uintptr_t size = upper_bound_ - buf_; 1610 // Align the size to uoffset_t 1611 size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1); 1612 return (buf_ + size > end_) ? 0 : size; 1613 } 1614 #endif 1615 1616 private: 1617 const uint8_t *buf_; 1618 const uint8_t *end_; 1619 size_t depth_; 1620 size_t max_depth_; 1621 size_t num_tables_; 1622 size_t max_tables_; 1623 #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE 1624 mutable const uint8_t *upper_bound_; 1625 #endif 1626 }; 1627 1628 // Convenient way to bundle a buffer and its length, to pass it around 1629 // typed by its root. 1630 // A BufferRef does not own its buffer. 1631 struct BufferRefBase {}; // for std::is_base_of 1632 template<typename T> struct BufferRef : BufferRefBase { 1633 BufferRef() : buf(nullptr), len(0), must_free(false) {} 1634 BufferRef(uint8_t *_buf, uoffset_t _len) 1635 : buf(_buf), len(_len), must_free(false) {} 1636 1637 ~BufferRef() { if (must_free) free(buf); } 1638 1639 const T *GetRoot() const { return flatbuffers::GetRoot<T>(buf); } 1640 1641 bool Verify() { 1642 Verifier verifier(buf, len); 1643 return verifier.VerifyBuffer<T>(nullptr); 1644 } 1645 1646 uint8_t *buf; 1647 uoffset_t len; 1648 bool must_free; 1649 }; 1650 1651 // "structs" are flat structures that do not have an offset table, thus 1652 // always have all members present and do not support forwards/backwards 1653 // compatible extensions. 1654 1655 class Struct FLATBUFFERS_FINAL_CLASS { 1656 public: 1657 template<typename T> T GetField(uoffset_t o) const { 1658 return ReadScalar<T>(&data_[o]); 1659 } 1660 1661 template<typename T> T GetStruct(uoffset_t o) const { 1662 return reinterpret_cast<T>(&data_[o]); 1663 } 1664 1665 const uint8_t *GetAddressOf(uoffset_t o) const { return &data_[o]; } 1666 uint8_t *GetAddressOf(uoffset_t o) { return &data_[o]; } 1667 1668 private: 1669 uint8_t data_[1]; 1670 }; 1671 1672 // "tables" use an offset table (possibly shared) that allows fields to be 1673 // omitted and added at will, but uses an extra indirection to read. 1674 class Table { 1675 public: 1676 const uint8_t *GetVTable() const { 1677 return data_ - ReadScalar<soffset_t>(data_); 1678 } 1679 1680 // This gets the field offset for any of the functions below it, or 0 1681 // if the field was not present. 1682 voffset_t GetOptionalFieldOffset(voffset_t field) const { 1683 // The vtable offset is always at the start. 1684 auto vtable = GetVTable(); 1685 // The first element is the size of the vtable (fields + type id + itself). 1686 auto vtsize = ReadScalar<voffset_t>(vtable); 1687 // If the field we're accessing is outside the vtable, we're reading older 1688 // data, so it's the same as if the offset was 0 (not present). 1689 return field < vtsize ? ReadScalar<voffset_t>(vtable + field) : 0; 1690 } 1691 1692 template<typename T> T GetField(voffset_t field, T defaultval) const { 1693 auto field_offset = GetOptionalFieldOffset(field); 1694 return field_offset ? ReadScalar<T>(data_ + field_offset) : defaultval; 1695 } 1696 1697 template<typename P> P GetPointer(voffset_t field) { 1698 auto field_offset = GetOptionalFieldOffset(field); 1699 auto p = data_ + field_offset; 1700 return field_offset 1701 ? reinterpret_cast<P>(p + ReadScalar<uoffset_t>(p)) 1702 : nullptr; 1703 } 1704 template<typename P> P GetPointer(voffset_t field) const { 1705 return const_cast<Table *>(this)->GetPointer<P>(field); 1706 } 1707 1708 template<typename P> P GetStruct(voffset_t field) const { 1709 auto field_offset = GetOptionalFieldOffset(field); 1710 auto p = const_cast<uint8_t *>(data_ + field_offset); 1711 return field_offset ? reinterpret_cast<P>(p) : nullptr; 1712 } 1713 1714 template<typename T> bool SetField(voffset_t field, T val) { 1715 auto field_offset = GetOptionalFieldOffset(field); 1716 if (!field_offset) return false; 1717 WriteScalar(data_ + field_offset, val); 1718 return true; 1719 } 1720 1721 bool SetPointer(voffset_t field, const uint8_t *val) { 1722 auto field_offset = GetOptionalFieldOffset(field); 1723 if (!field_offset) return false; 1724 WriteScalar(data_ + field_offset, 1725 static_cast<uoffset_t>(val - (data_ + field_offset))); 1726 return true; 1727 } 1728 1729 uint8_t *GetAddressOf(voffset_t field) { 1730 auto field_offset = GetOptionalFieldOffset(field); 1731 return field_offset ? data_ + field_offset : nullptr; 1732 } 1733 const uint8_t *GetAddressOf(voffset_t field) const { 1734 return const_cast<Table *>(this)->GetAddressOf(field); 1735 } 1736 1737 bool CheckField(voffset_t field) const { 1738 return GetOptionalFieldOffset(field) != 0; 1739 } 1740 1741 // Verify the vtable of this table. 1742 // Call this once per table, followed by VerifyField once per field. 1743 bool VerifyTableStart(Verifier &verifier) const { 1744 // Check the vtable offset. 1745 if (!verifier.Verify<soffset_t>(data_)) return false; 1746 auto vtable = GetVTable(); 1747 // Check the vtable size field, then check vtable fits in its entirety. 1748 return verifier.VerifyComplexity() && 1749 verifier.Verify<voffset_t>(vtable) && 1750 (ReadScalar<voffset_t>(vtable) & (sizeof(voffset_t) - 1)) == 0 && 1751 verifier.Verify(vtable, ReadScalar<voffset_t>(vtable)); 1752 } 1753 1754 // Verify a particular field. 1755 template<typename T> bool VerifyField(const Verifier &verifier, 1756 voffset_t field) const { 1757 // Calling GetOptionalFieldOffset should be safe now thanks to 1758 // VerifyTable(). 1759 auto field_offset = GetOptionalFieldOffset(field); 1760 // Check the actual field. 1761 return !field_offset || verifier.Verify<T>(data_ + field_offset); 1762 } 1763 1764 // VerifyField for required fields. 1765 template<typename T> bool VerifyFieldRequired(const Verifier &verifier, 1766 voffset_t field) const { 1767 auto field_offset = GetOptionalFieldOffset(field); 1768 return verifier.Check(field_offset != 0) && 1769 verifier.Verify<T>(data_ + field_offset); 1770 } 1771 1772 private: 1773 // private constructor & copy constructor: you obtain instances of this 1774 // class by pointing to existing data only 1775 Table(); 1776 Table(const Table &other); 1777 1778 uint8_t data_[1]; 1779 }; 1780 1781 /// @brief This can compute the start of a FlatBuffer from a root pointer, i.e. 1782 /// it is the opposite transformation of GetRoot(). 1783 /// This may be useful if you want to pass on a root and have the recipient 1784 /// delete the buffer afterwards. 1785 inline const uint8_t *GetBufferStartFromRootPointer(const void *root) { 1786 auto table = reinterpret_cast<const Table *>(root); 1787 auto vtable = table->GetVTable(); 1788 // Either the vtable is before the root or after the root. 1789 auto start = std::min(vtable, reinterpret_cast<const uint8_t *>(root)); 1790 // Align to at least sizeof(uoffset_t). 1791 start = reinterpret_cast<const uint8_t *>( 1792 reinterpret_cast<uintptr_t>(start) & ~(sizeof(uoffset_t) - 1)); 1793 // Additionally, there may be a file_identifier in the buffer, and the root 1794 // offset. The buffer may have been aligned to any size between 1795 // sizeof(uoffset_t) and FLATBUFFERS_MAX_ALIGNMENT (see "force_align"). 1796 // Sadly, the exact alignment is only known when constructing the buffer, 1797 // since it depends on the presence of values with said alignment properties. 1798 // So instead, we simply look at the next uoffset_t values (root, 1799 // file_identifier, and alignment padding) to see which points to the root. 1800 // None of the other values can "impersonate" the root since they will either 1801 // be 0 or four ASCII characters. 1802 static_assert(FlatBufferBuilder::kFileIdentifierLength == sizeof(uoffset_t), 1803 "file_identifier is assumed to be the same size as uoffset_t"); 1804 for (auto possible_roots = FLATBUFFERS_MAX_ALIGNMENT / sizeof(uoffset_t) + 1; 1805 possible_roots; 1806 possible_roots--) { 1807 start -= sizeof(uoffset_t); 1808 if (ReadScalar<uoffset_t>(start) + start == 1809 reinterpret_cast<const uint8_t *>(root)) return start; 1810 } 1811 // We didn't find the root, either the "root" passed isn't really a root, 1812 // or the buffer is corrupt. 1813 // Assert, because calling this function with bad data may cause reads 1814 // outside of buffer boundaries. 1815 assert(false); 1816 return nullptr; 1817 } 1818 1819 // Base class for native objects (FlatBuffer data de-serialized into native 1820 // C++ data structures). 1821 // Contains no functionality, purely documentative. 1822 struct NativeTable { 1823 }; 1824 1825 /// @brief Function types to be used with resolving hashes into objects and 1826 /// back again. The resolver gets a pointer to a field inside an object API 1827 /// object that is of the type specified in the schema using the attribute 1828 /// `cpp_type` (it is thus important whatever you write to this address 1829 /// matches that type). The value of this field is initially null, so you 1830 /// may choose to implement a delayed binding lookup using this function 1831 /// if you wish. The resolver does the opposite lookup, for when the object 1832 /// is being serialized again. 1833 typedef uint64_t hash_value_t; 1834 #ifdef FLATBUFFERS_CPP98_STL 1835 typedef void (*resolver_function_t)(void **pointer_adr, hash_value_t hash); 1836 typedef hash_value_t (*rehasher_function_t)(void *pointer); 1837 #else 1838 typedef std::function<void (void **pointer_adr, hash_value_t hash)> 1839 resolver_function_t; 1840 typedef std::function<hash_value_t (void *pointer)> rehasher_function_t; 1841 #endif 1842 1843 // Helper function to test if a field is present, using any of the field 1844 // enums in the generated code. 1845 // `table` must be a generated table type. Since this is a template parameter, 1846 // this is not typechecked to be a subclass of Table, so beware! 1847 // Note: this function will return false for fields equal to the default 1848 // value, since they're not stored in the buffer (unless force_defaults was 1849 // used). 1850 template<typename T> bool IsFieldPresent(const T *table, voffset_t field) { 1851 // Cast, since Table is a private baseclass of any table types. 1852 return reinterpret_cast<const Table *>(table)->CheckField(field); 1853 } 1854 1855 // Utility function for reverse lookups on the EnumNames*() functions 1856 // (in the generated C++ code) 1857 // names must be NULL terminated. 1858 inline int LookupEnum(const char **names, const char *name) { 1859 for (const char **p = names; *p; p++) 1860 if (!strcmp(*p, name)) 1861 return static_cast<int>(p - names); 1862 return -1; 1863 } 1864 1865 // These macros allow us to layout a struct with a guarantee that they'll end 1866 // up looking the same on different compilers and platforms. 1867 // It does this by disallowing the compiler to do any padding, and then 1868 // does padding itself by inserting extra padding fields that make every 1869 // element aligned to its own size. 1870 // Additionally, it manually sets the alignment of the struct as a whole, 1871 // which is typically its largest element, or a custom size set in the schema 1872 // by the force_align attribute. 1873 // These are used in the generated code only. 1874 1875 #if defined(_MSC_VER) 1876 #define MANUALLY_ALIGNED_STRUCT(alignment) \ 1877 __pragma(pack(1)); \ 1878 struct __declspec(align(alignment)) 1879 #define STRUCT_END(name, size) \ 1880 __pragma(pack()); \ 1881 static_assert(sizeof(name) == size, "compiler breaks packing rules") 1882 #elif defined(__GNUC__) || defined(__clang__) 1883 #define MANUALLY_ALIGNED_STRUCT(alignment) \ 1884 _Pragma("pack(1)") \ 1885 struct __attribute__((aligned(alignment))) 1886 #define STRUCT_END(name, size) \ 1887 _Pragma("pack()") \ 1888 static_assert(sizeof(name) == size, "compiler breaks packing rules") 1889 #else 1890 #error Unknown compiler, please define structure alignment macros 1891 #endif 1892 1893 // String which identifies the current version of FlatBuffers. 1894 // flatbuffer_version_string is used by Google developers to identify which 1895 // applications uploaded to Google Play are using this library. This allows 1896 // the development team at Google to determine the popularity of the library. 1897 // How it works: Applications that are uploaded to the Google Play Store are 1898 // scanned for this version string. We track which applications are using it 1899 // to measure popularity. You are free to remove it (of course) but we would 1900 // appreciate if you left it in. 1901 1902 // Weak linkage is culled by VS & doesn't work on cygwin. 1903 #if !defined(_WIN32) && !defined(__CYGWIN__) 1904 1905 extern volatile __attribute__((weak)) const char *flatbuffer_version_string; 1906 volatile __attribute__((weak)) const char *flatbuffer_version_string = 1907 "FlatBuffers " 1908 FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "." 1909 FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MINOR) "." 1910 FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION); 1911 1912 #endif // !defined(_WIN32) && !defined(__CYGWIN__) 1913 1914 #define DEFINE_BITMASK_OPERATORS(E, T)\ 1915 inline E operator | (E lhs, E rhs){\ 1916 return E(T(lhs) | T(rhs));\ 1917 }\ 1918 inline E operator & (E lhs, E rhs){\ 1919 return E(T(lhs) & T(rhs));\ 1920 }\ 1921 inline E operator ^ (E lhs, E rhs){\ 1922 return E(T(lhs) ^ T(rhs));\ 1923 }\ 1924 inline E operator ~ (E lhs){\ 1925 return E(~T(lhs));\ 1926 }\ 1927 inline E operator |= (E &lhs, E rhs){\ 1928 lhs = lhs | rhs;\ 1929 return lhs;\ 1930 }\ 1931 inline E operator &= (E &lhs, E rhs){\ 1932 lhs = lhs & rhs;\ 1933 return lhs;\ 1934 }\ 1935 inline E operator ^= (E &lhs, E rhs){\ 1936 lhs = lhs ^ rhs;\ 1937 return lhs;\ 1938 }\ 1939 inline bool operator !(E rhs) \ 1940 {\ 1941 return !bool(T(rhs)); \ 1942 } 1943 /// @endcond 1944 } // namespace flatbuffers 1945 1946 #ifdef FLATBUFFERS_CHRE 1947 #ifndef CHRE_ASSERT_USES_STDLIB_ASSERT 1948 #undef assert 1949 #ifdef FLATBUFFERS_PRIOR_ASSERT 1950 #define assert FLATBUFFERS_PRIOR_ASSERT 1951 #endif 1952 #endif // define CHRE_ASSERT_USES_STDLIB_ASSERT 1953 #endif 1954 1955 #endif // FLATBUFFERS_H_ 1956