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