blob: 999419383e33887238d02630b9f185a92861f476 [file] [log] [blame]
James Kuszmaul8e62b022022-03-22 09:33:25 -07001/*
2 * Copyright 2021 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_FLATBUFFER_BUILDER_H_
18#define FLATBUFFERS_FLATBUFFER_BUILDER_H_
19
20#include <functional>
21
22#include "flatbuffers/allocator.h"
23#include "flatbuffers/array.h"
24#include "flatbuffers/base.h"
25#include "flatbuffers/buffer_ref.h"
26#include "flatbuffers/default_allocator.h"
27#include "flatbuffers/detached_buffer.h"
28#include "flatbuffers/stl_emulation.h"
29#include "flatbuffers/string.h"
30#include "flatbuffers/struct.h"
31#include "flatbuffers/table.h"
32#include "flatbuffers/vector.h"
33#include "flatbuffers/vector_downward.h"
34#include "flatbuffers/verifier.h"
35
36namespace flatbuffers {
37
38// Converts a Field ID to a virtual table offset.
39inline voffset_t FieldIndexToOffset(voffset_t field_id) {
40 // Should correspond to what EndTable() below builds up.
41 const int fixed_fields = 2; // Vtable size and Object Size.
42 return static_cast<voffset_t>((field_id + fixed_fields) * sizeof(voffset_t));
43}
44
45template<typename T, typename Alloc = std::allocator<T>>
46const T *data(const std::vector<T, Alloc> &v) {
47 // Eventually the returned pointer gets passed down to memcpy, so
48 // we need it to be non-null to avoid undefined behavior.
49 static uint8_t t;
50 return v.empty() ? reinterpret_cast<const T *>(&t) : &v.front();
51}
52template<typename T, typename Alloc = std::allocator<T>>
53T *data(std::vector<T, Alloc> &v) {
54 // Eventually the returned pointer gets passed down to memcpy, so
55 // we need it to be non-null to avoid undefined behavior.
56 static uint8_t t;
57 return v.empty() ? reinterpret_cast<T *>(&t) : &v.front();
58}
59
60/// @addtogroup flatbuffers_cpp_api
61/// @{
62/// @class FlatBufferBuilder
63/// @brief Helper class to hold data needed in creation of a FlatBuffer.
64/// To serialize data, you typically call one of the `Create*()` functions in
65/// the generated code, which in turn call a sequence of `StartTable`/
66/// `PushElement`/`AddElement`/`EndTable`, or the builtin `CreateString`/
67/// `CreateVector` functions. Do this is depth-first order to build up a tree to
68/// the root. `Finish()` wraps up the buffer ready for transport.
69class FlatBufferBuilder {
70 public:
71 /// @brief Default constructor for FlatBufferBuilder.
72 /// @param[in] initial_size The initial size of the buffer, in bytes. Defaults
73 /// to `1024`.
74 /// @param[in] allocator An `Allocator` to use. If null will use
75 /// `DefaultAllocator`.
76 /// @param[in] own_allocator Whether the builder/vector should own the
77 /// allocator. Defaults to / `false`.
78 /// @param[in] buffer_minalign Force the buffer to be aligned to the given
79 /// minimum alignment upon reallocation. Only needed if you intend to store
80 /// types with custom alignment AND you wish to read the buffer in-place
81 /// directly after creation.
82 explicit FlatBufferBuilder(
83 size_t initial_size = 1024, Allocator *allocator = nullptr,
84 bool own_allocator = false,
85 size_t buffer_minalign = AlignOf<largest_scalar_t>())
86 : buf_(initial_size, allocator, own_allocator, buffer_minalign),
87 num_field_loc(0),
88 max_voffset_(0),
89 nested(false),
90 finished(false),
91 minalign_(1),
92 force_defaults_(false),
93 dedup_vtables_(true),
94 string_pool(nullptr) {
95 EndianCheck();
96 }
97
98 /// @brief Move constructor for FlatBufferBuilder.
99 FlatBufferBuilder(FlatBufferBuilder &&other)
100 : buf_(1024, nullptr, false, AlignOf<largest_scalar_t>()),
101 num_field_loc(0),
102 max_voffset_(0),
103 nested(false),
104 finished(false),
105 minalign_(1),
106 force_defaults_(false),
107 dedup_vtables_(true),
108 string_pool(nullptr) {
109 EndianCheck();
110 // Default construct and swap idiom.
111 // Lack of delegating constructors in vs2010 makes it more verbose than
112 // needed.
113 Swap(other);
114 }
115
116 /// @brief Move assignment operator for FlatBufferBuilder.
117 FlatBufferBuilder &operator=(FlatBufferBuilder &&other) {
118 // Move construct a temporary and swap idiom
119 FlatBufferBuilder temp(std::move(other));
120 Swap(temp);
121 return *this;
122 }
123
124 void Swap(FlatBufferBuilder &other) {
125 using std::swap;
126 buf_.swap(other.buf_);
127 swap(num_field_loc, other.num_field_loc);
128 swap(max_voffset_, other.max_voffset_);
129 swap(nested, other.nested);
130 swap(finished, other.finished);
131 swap(minalign_, other.minalign_);
132 swap(force_defaults_, other.force_defaults_);
133 swap(dedup_vtables_, other.dedup_vtables_);
134 swap(string_pool, other.string_pool);
135 }
136
137 ~FlatBufferBuilder() {
138 if (string_pool) delete string_pool;
139 }
140
141 void Reset() {
142 Clear(); // clear builder state
143 buf_.reset(); // deallocate buffer
144 }
145
146 /// @brief Reset all the state in this FlatBufferBuilder so it can be reused
147 /// to construct another buffer.
148 void Clear() {
149 ClearOffsets();
150 buf_.clear();
151 nested = false;
152 finished = false;
153 minalign_ = 1;
154 if (string_pool) string_pool->clear();
155 }
156
157 /// @brief The current size of the serialized buffer, counting from the end.
158 /// @return Returns an `uoffset_t` with the current size of the buffer.
159 uoffset_t GetSize() const { return buf_.size(); }
160
161 /// @brief Get the serialized buffer (after you call `Finish()`).
162 /// @return Returns an `uint8_t` pointer to the FlatBuffer data inside the
163 /// buffer.
164 uint8_t *GetBufferPointer() const {
165 Finished();
166 return buf_.data();
167 }
168
169 /// @brief Get the serialized buffer (after you call `Finish()`) as a span.
170 /// @return Returns a constructed flatbuffers::span that is a view over the
171 /// FlatBuffer data inside the buffer.
172 flatbuffers::span<uint8_t> GetBufferSpan() const {
173 Finished();
174 return flatbuffers::span<uint8_t>(buf_.data(), buf_.size());
175 }
176
177 /// @brief Get a pointer to an unfinished buffer.
178 /// @return Returns a `uint8_t` pointer to the unfinished buffer.
179 uint8_t *GetCurrentBufferPointer() const { return buf_.data(); }
180
181 /// @brief Get the released pointer to the serialized buffer.
182 /// @warning Do NOT attempt to use this FlatBufferBuilder afterwards!
183 /// @return A `FlatBuffer` that owns the buffer and its allocator and
184 /// behaves similar to a `unique_ptr` with a deleter.
185 FLATBUFFERS_ATTRIBUTE([[deprecated("use Release() instead")]])
186 DetachedBuffer ReleaseBufferPointer() {
187 Finished();
188 return buf_.release();
189 }
190
191 /// @brief Get the released DetachedBuffer.
192 /// @return A `DetachedBuffer` that owns the buffer and its allocator.
193 DetachedBuffer Release() {
194 Finished();
195 return buf_.release();
196 }
197
198 /// @brief Get the released pointer to the serialized buffer.
199 /// @param size The size of the memory block containing
200 /// the serialized `FlatBuffer`.
201 /// @param offset The offset from the released pointer where the finished
202 /// `FlatBuffer` starts.
203 /// @return A raw pointer to the start of the memory block containing
204 /// the serialized `FlatBuffer`.
205 /// @remark If the allocator is owned, it gets deleted when the destructor is
206 /// called..
207 uint8_t *ReleaseRaw(size_t &size, size_t &offset) {
208 Finished();
209 return buf_.release_raw(size, offset);
210 }
211
212 /// @brief get the minimum alignment this buffer needs to be accessed
213 /// properly. This is only known once all elements have been written (after
214 /// you call Finish()). You can use this information if you need to embed
215 /// a FlatBuffer in some other buffer, such that you can later read it
216 /// without first having to copy it into its own buffer.
217 size_t GetBufferMinAlignment() const {
218 Finished();
219 return minalign_;
220 }
221
222 /// @cond FLATBUFFERS_INTERNAL
223 void Finished() const {
224 // If you get this assert, you're attempting to get access a buffer
225 // which hasn't been finished yet. Be sure to call
226 // FlatBufferBuilder::Finish with your root table.
227 // If you really need to access an unfinished buffer, call
228 // GetCurrentBufferPointer instead.
229 FLATBUFFERS_ASSERT(finished);
230 }
231 /// @endcond
232
233 /// @brief In order to save space, fields that are set to their default value
234 /// don't get serialized into the buffer.
235 /// @param[in] fd When set to `true`, always serializes default values that
236 /// are set. Optional fields which are not set explicitly, will still not be
237 /// serialized.
238 void ForceDefaults(bool fd) { force_defaults_ = fd; }
239
240 /// @brief By default vtables are deduped in order to save space.
241 /// @param[in] dedup When set to `true`, dedup vtables.
242 void DedupVtables(bool dedup) { dedup_vtables_ = dedup; }
243
244 /// @cond FLATBUFFERS_INTERNAL
245 void Pad(size_t num_bytes) { buf_.fill(num_bytes); }
246
247 void TrackMinAlign(size_t elem_size) {
248 if (elem_size > minalign_) minalign_ = elem_size;
249 }
250
251 void Align(size_t elem_size) {
252 TrackMinAlign(elem_size);
253 buf_.fill(PaddingBytes(buf_.size(), elem_size));
254 }
255
256 void PushFlatBuffer(const uint8_t *bytes, size_t size) {
257 PushBytes(bytes, size);
258 finished = true;
259 }
260
261 void PushBytes(const uint8_t *bytes, size_t size) { buf_.push(bytes, size); }
262
263 void PopBytes(size_t amount) { buf_.pop(amount); }
264
265 template<typename T> void AssertScalarT() {
266 // The code assumes power of 2 sizes and endian-swap-ability.
267 static_assert(flatbuffers::is_scalar<T>::value, "T must be a scalar type");
268 }
269
270 // Write a single aligned scalar to the buffer
271 template<typename T> uoffset_t PushElement(T element) {
272 AssertScalarT<T>();
273 Align(sizeof(T));
274 buf_.push_small(EndianScalar(element));
275 return GetSize();
276 }
277
278 template<typename T> uoffset_t PushElement(Offset<T> off) {
279 // Special case for offsets: see ReferTo below.
280 return PushElement(ReferTo(off.o));
281 }
282
283 // When writing fields, we track where they are, so we can create correct
284 // vtables later.
285 void TrackField(voffset_t field, uoffset_t off) {
286 FieldLoc fl = { off, field };
287 buf_.scratch_push_small(fl);
288 num_field_loc++;
289 if (field > max_voffset_) { max_voffset_ = field; }
290 }
291
292 // Like PushElement, but additionally tracks the field this represents.
293 template<typename T> void AddElement(voffset_t field, T e, T def) {
294 // We don't serialize values equal to the default.
295 if (IsTheSameAs(e, def) && !force_defaults_) return;
296 TrackField(field, PushElement(e));
297 }
298
299 template<typename T> void AddElement(voffset_t field, T e) {
300 TrackField(field, PushElement(e));
301 }
302
303 template<typename T> void AddOffset(voffset_t field, Offset<T> off) {
304 if (off.IsNull()) return; // Don't store.
305 AddElement(field, ReferTo(off.o), static_cast<uoffset_t>(0));
306 }
307
308 template<typename T> void AddStruct(voffset_t field, const T *structptr) {
309 if (!structptr) return; // Default, don't store.
310 Align(AlignOf<T>());
311 buf_.push_small(*structptr);
312 TrackField(field, GetSize());
313 }
314
315 void AddStructOffset(voffset_t field, uoffset_t off) {
316 TrackField(field, off);
317 }
318
319 // Offsets initially are relative to the end of the buffer (downwards).
320 // This function converts them to be relative to the current location
321 // in the buffer (when stored here), pointing upwards.
322 uoffset_t ReferTo(uoffset_t off) {
323 // Align to ensure GetSize() below is correct.
324 Align(sizeof(uoffset_t));
325 // Offset must refer to something already in buffer.
326 const uoffset_t size = GetSize();
327 FLATBUFFERS_ASSERT(off && off <= size);
328 return size - off + static_cast<uoffset_t>(sizeof(uoffset_t));
329 }
330
331 void NotNested() {
332 // If you hit this, you're trying to construct a Table/Vector/String
333 // during the construction of its parent table (between the MyTableBuilder
334 // and table.Finish().
335 // Move the creation of these sub-objects to above the MyTableBuilder to
336 // not get this assert.
337 // Ignoring this assert may appear to work in simple cases, but the reason
338 // it is here is that storing objects in-line may cause vtable offsets
339 // to not fit anymore. It also leads to vtable duplication.
340 FLATBUFFERS_ASSERT(!nested);
341 // If you hit this, fields were added outside the scope of a table.
342 FLATBUFFERS_ASSERT(!num_field_loc);
343 }
344
345 // From generated code (or from the parser), we call StartTable/EndTable
346 // with a sequence of AddElement calls in between.
347 uoffset_t StartTable() {
348 NotNested();
349 nested = true;
350 return GetSize();
351 }
352
353 // This finishes one serialized object by generating the vtable if it's a
354 // table, comparing it against existing vtables, and writing the
355 // resulting vtable offset.
356 uoffset_t EndTable(uoffset_t start) {
357 // If you get this assert, a corresponding StartTable wasn't called.
358 FLATBUFFERS_ASSERT(nested);
359 // Write the vtable offset, which is the start of any Table.
360 // We fill it's value later.
361 auto vtableoffsetloc = PushElement<soffset_t>(0);
362 // Write a vtable, which consists entirely of voffset_t elements.
363 // It starts with the number of offsets, followed by a type id, followed
364 // by the offsets themselves. In reverse:
365 // Include space for the last offset and ensure empty tables have a
366 // minimum size.
367 max_voffset_ =
368 (std::max)(static_cast<voffset_t>(max_voffset_ + sizeof(voffset_t)),
369 FieldIndexToOffset(0));
370 buf_.fill_big(max_voffset_);
371 auto table_object_size = vtableoffsetloc - start;
372 // Vtable use 16bit offsets.
373 FLATBUFFERS_ASSERT(table_object_size < 0x10000);
374 WriteScalar<voffset_t>(buf_.data() + sizeof(voffset_t),
375 static_cast<voffset_t>(table_object_size));
376 WriteScalar<voffset_t>(buf_.data(), max_voffset_);
377 // Write the offsets into the table
378 for (auto it = buf_.scratch_end() - num_field_loc * sizeof(FieldLoc);
379 it < buf_.scratch_end(); it += sizeof(FieldLoc)) {
380 auto field_location = reinterpret_cast<FieldLoc *>(it);
381 auto pos = static_cast<voffset_t>(vtableoffsetloc - field_location->off);
382 // If this asserts, it means you've set a field twice.
383 FLATBUFFERS_ASSERT(
384 !ReadScalar<voffset_t>(buf_.data() + field_location->id));
385 WriteScalar<voffset_t>(buf_.data() + field_location->id, pos);
386 }
387 ClearOffsets();
388 auto vt1 = reinterpret_cast<voffset_t *>(buf_.data());
389 auto vt1_size = ReadScalar<voffset_t>(vt1);
390 auto vt_use = GetSize();
391 // See if we already have generated a vtable with this exact same
392 // layout before. If so, make it point to the old one, remove this one.
393 if (dedup_vtables_) {
394 for (auto it = buf_.scratch_data(); it < buf_.scratch_end();
395 it += sizeof(uoffset_t)) {
396 auto vt_offset_ptr = reinterpret_cast<uoffset_t *>(it);
397 auto vt2 = reinterpret_cast<voffset_t *>(buf_.data_at(*vt_offset_ptr));
398 auto vt2_size = ReadScalar<voffset_t>(vt2);
399 if (vt1_size != vt2_size || 0 != memcmp(vt2, vt1, vt1_size)) continue;
400 vt_use = *vt_offset_ptr;
401 buf_.pop(GetSize() - vtableoffsetloc);
402 break;
403 }
404 }
405 // If this is a new vtable, remember it.
406 if (vt_use == GetSize()) { buf_.scratch_push_small(vt_use); }
407 // Fill the vtable offset we created above.
408 // The offset points from the beginning of the object to where the
409 // vtable is stored.
410 // Offsets default direction is downward in memory for future format
411 // flexibility (storing all vtables at the start of the file).
412 WriteScalar(buf_.data_at(vtableoffsetloc),
413 static_cast<soffset_t>(vt_use) -
414 static_cast<soffset_t>(vtableoffsetloc));
415
416 nested = false;
417 return vtableoffsetloc;
418 }
419
420 FLATBUFFERS_ATTRIBUTE([[deprecated("call the version above instead")]])
421 uoffset_t EndTable(uoffset_t start, voffset_t /*numfields*/) {
422 return EndTable(start);
423 }
424
425 // This checks a required field has been set in a given table that has
426 // just been constructed.
427 template<typename T> void Required(Offset<T> table, voffset_t field);
428
429 uoffset_t StartStruct(size_t alignment) {
430 Align(alignment);
431 return GetSize();
432 }
433
434 uoffset_t EndStruct() { return GetSize(); }
435
436 void ClearOffsets() {
437 buf_.scratch_pop(num_field_loc * sizeof(FieldLoc));
438 num_field_loc = 0;
439 max_voffset_ = 0;
440 }
441
442 // Aligns such that when "len" bytes are written, an object can be written
443 // after it with "alignment" without padding.
444 void PreAlign(size_t len, size_t alignment) {
445 TrackMinAlign(alignment);
446 buf_.fill(PaddingBytes(GetSize() + len, alignment));
447 }
448 template<typename T> void PreAlign(size_t len) {
449 AssertScalarT<T>();
450 PreAlign(len, sizeof(T));
451 }
452 /// @endcond
453
454 /// @brief Store a string in the buffer, which can contain any binary data.
455 /// @param[in] str A const char pointer to the data to be stored as a string.
456 /// @param[in] len The number of bytes that should be stored from `str`.
457 /// @return Returns the offset in the buffer where the string starts.
458 Offset<String> CreateString(const char *str, size_t len) {
459 NotNested();
460 PreAlign<uoffset_t>(len + 1); // Always 0-terminated.
461 buf_.fill(1);
462 PushBytes(reinterpret_cast<const uint8_t *>(str), len);
463 PushElement(static_cast<uoffset_t>(len));
464 return Offset<String>(GetSize());
465 }
466
467 /// @brief Store a string in the buffer, which is null-terminated.
468 /// @param[in] str A const char pointer to a C-string to add to the buffer.
469 /// @return Returns the offset in the buffer where the string starts.
470 Offset<String> CreateString(const char *str) {
471 return CreateString(str, strlen(str));
472 }
473
474 /// @brief Store a string in the buffer, which is null-terminated.
475 /// @param[in] str A char pointer to a C-string to add to the buffer.
476 /// @return Returns the offset in the buffer where the string starts.
477 Offset<String> CreateString(char *str) {
478 return CreateString(str, strlen(str));
479 }
480
481 /// @brief Store a string in the buffer, which can contain any binary data.
482 /// @param[in] str A const reference to a std::string to store in the buffer.
483 /// @return Returns the offset in the buffer where the string starts.
484 Offset<String> CreateString(const std::string &str) {
485 return CreateString(str.c_str(), str.length());
486 }
487
488 // clang-format off
489 #ifdef FLATBUFFERS_HAS_STRING_VIEW
490 /// @brief Store a string in the buffer, which can contain any binary data.
491 /// @param[in] str A const string_view to copy in to the buffer.
492 /// @return Returns the offset in the buffer where the string starts.
493 Offset<String> CreateString(flatbuffers::string_view str) {
494 return CreateString(str.data(), str.size());
495 }
496 #endif // FLATBUFFERS_HAS_STRING_VIEW
497 // clang-format on
498
499 /// @brief Store a string in the buffer, which can contain any binary data.
500 /// @param[in] str A const pointer to a `String` struct to add to the buffer.
501 /// @return Returns the offset in the buffer where the string starts
502 Offset<String> CreateString(const String *str) {
503 return str ? CreateString(str->c_str(), str->size()) : 0;
504 }
505
506 /// @brief Store a string in the buffer, which can contain any binary data.
507 /// @param[in] str A const reference to a std::string like type with support
508 /// of T::c_str() and T::length() to store in the buffer.
509 /// @return Returns the offset in the buffer where the string starts.
510 template<typename T> Offset<String> CreateString(const T &str) {
511 return CreateString(str.c_str(), str.length());
512 }
513
514 /// @brief Store a string in the buffer, which can contain any binary data.
515 /// If a string with this exact contents has already been serialized before,
516 /// instead simply returns the offset of the existing string. This uses a map
517 /// stored on the heap, but only stores the numerical offsets.
518 /// @param[in] str A const char pointer to the data to be stored as a string.
519 /// @param[in] len The number of bytes that should be stored from `str`.
520 /// @return Returns the offset in the buffer where the string starts.
521 Offset<String> CreateSharedString(const char *str, size_t len) {
522 FLATBUFFERS_ASSERT(FLATBUFFERS_GENERAL_HEAP_ALLOC_OK);
523 if (!string_pool)
524 string_pool = new StringOffsetMap(StringOffsetCompare(buf_));
525 auto size_before_string = buf_.size();
526 // Must first serialize the string, since the set is all offsets into
527 // buffer.
528 auto off = CreateString(str, len);
529 auto it = string_pool->find(off);
530 // If it exists we reuse existing serialized data!
531 if (it != string_pool->end()) {
532 // We can remove the string we serialized.
533 buf_.pop(buf_.size() - size_before_string);
534 return *it;
535 }
536 // Record this string for future use.
537 string_pool->insert(off);
538 return off;
539 }
540
541#ifdef FLATBUFFERS_HAS_STRING_VIEW
542 /// @brief Store a string in the buffer, which can contain any binary data.
543 /// If a string with this exact contents has already been serialized before,
544 /// instead simply returns the offset of the existing string. This uses a map
545 /// stored on the heap, but only stores the numerical offsets.
546 /// @param[in] str A const std::string_view to store in the buffer.
547 /// @return Returns the offset in the buffer where the string starts
548 Offset<String> CreateSharedString(const flatbuffers::string_view str) {
549 return CreateSharedString(str.data(), str.size());
550 }
551#else
552 /// @brief Store a string in the buffer, which null-terminated.
553 /// If a string with this exact contents has already been serialized before,
554 /// instead simply returns the offset of the existing string. This uses a map
555 /// stored on the heap, but only stores the numerical offsets.
556 /// @param[in] str A const char pointer to a C-string to add to the buffer.
557 /// @return Returns the offset in the buffer where the string starts.
558 Offset<String> CreateSharedString(const char *str) {
559 return CreateSharedString(str, strlen(str));
560 }
561
562 /// @brief Store a string in the buffer, which can contain any binary data.
563 /// If a string with this exact contents has already been serialized before,
564 /// instead simply returns the offset of the existing string. This uses a map
565 /// stored on the heap, but only stores the numerical offsets.
566 /// @param[in] str A const reference to a std::string to store in the buffer.
567 /// @return Returns the offset in the buffer where the string starts.
568 Offset<String> CreateSharedString(const std::string &str) {
569 return CreateSharedString(str.c_str(), str.length());
570 }
571#endif
572
573 /// @brief Store a string in the buffer, which can contain any binary data.
574 /// If a string with this exact contents has already been serialized before,
575 /// instead simply returns the offset of the existing string. This uses a map
576 /// stored on the heap, but only stores the numerical offsets.
577 /// @param[in] str A const pointer to a `String` struct to add to the buffer.
578 /// @return Returns the offset in the buffer where the string starts
579 Offset<String> CreateSharedString(const String *str) {
580 return CreateSharedString(str->c_str(), str->size());
581 }
582
583 /// @cond FLATBUFFERS_INTERNAL
584 uoffset_t EndVector(size_t len) {
585 FLATBUFFERS_ASSERT(nested); // Hit if no corresponding StartVector.
586 nested = false;
587 return PushElement(static_cast<uoffset_t>(len));
588 }
589
590 void StartVector(size_t len, size_t elemsize) {
591 NotNested();
592 nested = true;
593 PreAlign<uoffset_t>(len * elemsize);
594 PreAlign(len * elemsize, elemsize); // Just in case elemsize > uoffset_t.
595 }
596
597 // Call this right before StartVector/CreateVector if you want to force the
598 // alignment to be something different than what the element size would
599 // normally dictate.
600 // This is useful when storing a nested_flatbuffer in a vector of bytes,
601 // or when storing SIMD floats, etc.
602 void ForceVectorAlignment(size_t len, size_t elemsize, size_t alignment) {
603 FLATBUFFERS_ASSERT(VerifyAlignmentRequirements(alignment));
604 PreAlign(len * elemsize, alignment);
605 }
606
607 // Similar to ForceVectorAlignment but for String fields.
608 void ForceStringAlignment(size_t len, size_t alignment) {
609 FLATBUFFERS_ASSERT(VerifyAlignmentRequirements(alignment));
610 PreAlign((len + 1) * sizeof(char), alignment);
611 }
612
613 /// @endcond
614
615 /// @brief Serialize an array into a FlatBuffer `vector`.
616 /// @tparam T The data type of the array elements.
617 /// @param[in] v A pointer to the array of type `T` to serialize into the
618 /// buffer as a `vector`.
619 /// @param[in] len The number of elements to serialize.
620 /// @return Returns a typed `Offset` into the serialized data indicating
621 /// where the vector is stored.
622 template<typename T> Offset<Vector<T>> CreateVector(const T *v, size_t len) {
623 // If this assert hits, you're specifying a template argument that is
624 // causing the wrong overload to be selected, remove it.
625 AssertScalarT<T>();
626 StartVector(len, sizeof(T));
627 if (len == 0) { return Offset<Vector<T>>(EndVector(len)); }
628 // clang-format off
629 #if FLATBUFFERS_LITTLEENDIAN
630 PushBytes(reinterpret_cast<const uint8_t *>(v), len * sizeof(T));
631 #else
632 if (sizeof(T) == 1) {
633 PushBytes(reinterpret_cast<const uint8_t *>(v), len);
634 } else {
635 for (auto i = len; i > 0; ) {
636 PushElement(v[--i]);
637 }
638 }
639 #endif
640 // clang-format on
641 return Offset<Vector<T>>(EndVector(len));
642 }
643
644 /// @brief Serialize an array like object into a FlatBuffer `vector`.
645 /// @tparam T The data type of the array elements.
646 /// @tparam C The type of the array.
647 /// @param[in] array A reference to an array like object of type `T` to
648 /// serialize into the buffer as a `vector`.
649 /// @return Returns a typed `Offset` into the serialized data indicating
650 /// where the vector is stored.
651 template<typename T, class C> Offset<Vector<T>> CreateVector(const C &array) {
652 return CreateVector(array.data(), array.size());
653 }
654
655 template<typename T>
656 Offset<Vector<Offset<T>>> CreateVector(const Offset<T> *v, size_t len) {
657 StartVector(len, sizeof(Offset<T>));
658 for (auto i = len; i > 0;) { PushElement(v[--i]); }
659 return Offset<Vector<Offset<T>>>(EndVector(len));
660 }
661
662 /// @brief Serialize a `std::vector` into a FlatBuffer `vector`.
663 /// @tparam T The data type of the `std::vector` elements.
664 /// @param v A const reference to the `std::vector` to serialize into the
665 /// buffer as a `vector`.
666 /// @return Returns a typed `Offset` into the serialized data indicating
667 /// where the vector is stored.
668 template<typename T, typename Alloc = std::allocator<T>>
669 Offset<Vector<T>> CreateVector(const std::vector<T, Alloc> &v) {
670 return CreateVector(data(v), v.size());
671 }
672
673 // vector<bool> may be implemented using a bit-set, so we can't access it as
674 // an array. Instead, read elements manually.
675 // Background: https://isocpp.org/blog/2012/11/on-vectorbool
676 Offset<Vector<uint8_t>> CreateVector(const std::vector<bool> &v) {
677 StartVector(v.size(), sizeof(uint8_t));
678 for (auto i = v.size(); i > 0;) {
679 PushElement(static_cast<uint8_t>(v[--i]));
680 }
681 return Offset<Vector<uint8_t>>(EndVector(v.size()));
682 }
683
684 /// @brief Serialize values returned by a function into a FlatBuffer `vector`.
685 /// This is a convenience function that takes care of iteration for you.
686 /// @tparam T The data type of the `std::vector` elements.
687 /// @param f A function that takes the current iteration 0..vector_size-1 and
688 /// returns any type that you can construct a FlatBuffers vector out of.
689 /// @return Returns a typed `Offset` into the serialized data indicating
690 /// where the vector is stored.
691 template<typename T>
692 Offset<Vector<T>> CreateVector(size_t vector_size,
693 const std::function<T(size_t i)> &f) {
694 FLATBUFFERS_ASSERT(FLATBUFFERS_GENERAL_HEAP_ALLOC_OK);
695 std::vector<T> elems(vector_size);
696 for (size_t i = 0; i < vector_size; i++) elems[i] = f(i);
697 return CreateVector(elems);
698 }
699
700 /// @brief Serialize values returned by a function into a FlatBuffer `vector`.
701 /// This is a convenience function that takes care of iteration for you. This
702 /// uses a vector stored on the heap to store the intermediate results of the
703 /// iteration.
704 /// @tparam T The data type of the `std::vector` elements.
705 /// @param f A function that takes the current iteration 0..vector_size-1,
706 /// and the state parameter returning any type that you can construct a
707 /// FlatBuffers vector out of.
708 /// @param state State passed to f.
709 /// @return Returns a typed `Offset` into the serialized data indicating
710 /// where the vector is stored.
711 template<typename T, typename F, typename S>
712 Offset<Vector<T>> CreateVector(size_t vector_size, F f, S *state) {
713 FLATBUFFERS_ASSERT(FLATBUFFERS_GENERAL_HEAP_ALLOC_OK);
714 std::vector<T> elems(vector_size);
715 for (size_t i = 0; i < vector_size; i++) elems[i] = f(i, state);
716 return CreateVector(elems);
717 }
718
719 /// @brief Serialize a `std::vector<std::string>` into a FlatBuffer `vector`.
720 /// This is a convenience function for a common case.
721 /// @param v A const reference to the `std::vector` to serialize into the
722 /// buffer as a `vector`.
723 /// @return Returns a typed `Offset` into the serialized data indicating
724 /// where the vector is stored.
725 template<typename Alloc = std::allocator<std::string>>
726 Offset<Vector<Offset<String>>> CreateVectorOfStrings(
727 const std::vector<std::string, Alloc> &v) {
728 return CreateVectorOfStrings(v.cbegin(), v.cend());
729 }
730
731 /// @brief Serialize a collection of Strings into a FlatBuffer `vector`.
732 /// This is a convenience function for a common case.
733 /// @param begin The begining iterator of the collection
734 /// @param end The ending iterator of the collection
735 /// @return Returns a typed `Offset` into the serialized data indicating
736 /// where the vector is stored.
737 template<class It>
738 Offset<Vector<Offset<String>>> CreateVectorOfStrings(It begin, It end) {
739 auto size = std::distance(begin, end);
740 auto scratch_buffer_usage = size * sizeof(Offset<String>);
741 // If there is not enough space to store the offsets, there definitely won't
742 // be enough space to store all the strings. So ensuring space for the
743 // scratch region is OK, for it it fails, it would have failed later.
744 buf_.ensure_space(scratch_buffer_usage);
745 for (auto it = begin; it != end; ++it) {
746 buf_.scratch_push_small(CreateString(*it));
747 }
748 StartVector(size, sizeof(Offset<String>));
749 for (auto i = 1; i <= size; i++) {
750 // Note we re-evaluate the buf location each iteration to account for any
751 // underlying buffer resizing that may occur.
752 PushElement(*reinterpret_cast<Offset<String> *>(
753 buf_.scratch_end() - i * sizeof(Offset<String>)));
754 }
755 buf_.scratch_pop(scratch_buffer_usage);
756 return Offset<Vector<Offset<String>>>(EndVector(size));
757 }
758
759 /// @brief Serialize an array of structs into a FlatBuffer `vector`.
760 /// @tparam T The data type of the struct array elements.
761 /// @param[in] v A pointer to the array of type `T` to serialize into the
762 /// buffer as a `vector`.
763 /// @param[in] len The number of elements to serialize.
764 /// @return Returns a typed `Offset` into the serialized data indicating
765 /// where the vector is stored.
766 template<typename T>
767 Offset<Vector<const T *>> CreateVectorOfStructs(const T *v, size_t len) {
768 StartVector(len * sizeof(T) / AlignOf<T>(), AlignOf<T>());
769 if (len > 0) {
770 PushBytes(reinterpret_cast<const uint8_t *>(v), sizeof(T) * len);
771 }
772 return Offset<Vector<const T *>>(EndVector(len));
773 }
774
775 /// @brief Serialize an array of native structs into a FlatBuffer `vector`.
776 /// @tparam T The data type of the struct array elements.
777 /// @tparam S The data type of the native struct array elements.
778 /// @param[in] v A pointer to the array of type `S` to serialize into the
779 /// buffer as a `vector`.
780 /// @param[in] len The number of elements to serialize.
781 /// @param[in] pack_func Pointer to a function to convert the native struct
782 /// to the FlatBuffer struct.
783 /// @return Returns a typed `Offset` into the serialized data indicating
784 /// where the vector is stored.
785 template<typename T, typename S>
786 Offset<Vector<const T *>> CreateVectorOfNativeStructs(
787 const S *v, size_t len, T (*const pack_func)(const S &)) {
788 FLATBUFFERS_ASSERT(pack_func);
789 auto structs = StartVectorOfStructs<T>(len);
790 for (size_t i = 0; i < len; i++) { structs[i] = pack_func(v[i]); }
791 return EndVectorOfStructs<T>(len);
792 }
793
794 /// @brief Serialize an array of native structs into a FlatBuffer `vector`.
795 /// @tparam T The data type of the struct array elements.
796 /// @tparam S The data type of the native struct array elements.
797 /// @param[in] v A pointer to the array of type `S` to serialize into the
798 /// buffer as a `vector`.
799 /// @param[in] len The number of elements to serialize.
800 /// @return Returns a typed `Offset` into the serialized data indicating
801 /// where the vector is stored.
802 template<typename T, typename S>
803 Offset<Vector<const T *>> CreateVectorOfNativeStructs(const S *v,
804 size_t len) {
805 extern T Pack(const S &);
806 return CreateVectorOfNativeStructs(v, len, Pack);
807 }
808
809 /// @brief Serialize an array of structs into a FlatBuffer `vector`.
810 /// @tparam T The data type of the struct array elements.
811 /// @param[in] filler A function that takes the current iteration
812 /// 0..vector_size-1 and a pointer to the struct that must be filled.
813 /// @return Returns a typed `Offset` into the serialized data indicating
814 /// where the vector is stored.
815 /// This is mostly useful when flatbuffers are generated with mutation
816 /// accessors.
817 template<typename T>
818 Offset<Vector<const T *>> CreateVectorOfStructs(
819 size_t vector_size, const std::function<void(size_t i, T *)> &filler) {
820 T *structs = StartVectorOfStructs<T>(vector_size);
821 for (size_t i = 0; i < vector_size; i++) {
822 filler(i, structs);
823 structs++;
824 }
825 return EndVectorOfStructs<T>(vector_size);
826 }
827
828 /// @brief Serialize an array of structs into a FlatBuffer `vector`.
829 /// @tparam T The data type of the struct array elements.
830 /// @param[in] f A function that takes the current iteration 0..vector_size-1,
831 /// a pointer to the struct that must be filled and the state argument.
832 /// @param[in] state Arbitrary state to pass to f.
833 /// @return Returns a typed `Offset` into the serialized data indicating
834 /// where the vector is stored.
835 /// This is mostly useful when flatbuffers are generated with mutation
836 /// accessors.
837 template<typename T, typename F, typename S>
838 Offset<Vector<const T *>> CreateVectorOfStructs(size_t vector_size, F f,
839 S *state) {
840 T *structs = StartVectorOfStructs<T>(vector_size);
841 for (size_t i = 0; i < vector_size; i++) {
842 f(i, structs, state);
843 structs++;
844 }
845 return EndVectorOfStructs<T>(vector_size);
846 }
847
848 /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`.
849 /// @tparam T The data type of the `std::vector` struct elements.
850 /// @param[in] v A const reference to the `std::vector` of structs to
851 /// serialize into the buffer as a `vector`.
852 /// @return Returns a typed `Offset` into the serialized data indicating
853 /// where the vector is stored.
854 template<typename T, typename Alloc = std::allocator<T>>
855 Offset<Vector<const T *>> CreateVectorOfStructs(
856 const std::vector<T, Alloc> &v) {
857 return CreateVectorOfStructs(data(v), v.size());
858 }
859
860 /// @brief Serialize a `std::vector` of native structs into a FlatBuffer
861 /// `vector`.
862 /// @tparam T The data type of the `std::vector` struct elements.
863 /// @tparam S The data type of the `std::vector` native struct elements.
864 /// @param[in] v A const reference to the `std::vector` of structs to
865 /// serialize into the buffer as a `vector`.
866 /// @param[in] pack_func Pointer to a function to convert the native struct
867 /// to the FlatBuffer struct.
868 /// @return Returns a typed `Offset` into the serialized data indicating
869 /// where the vector is stored.
870 template<typename T, typename S, typename Alloc = std::allocator<T>>
871 Offset<Vector<const T *>> CreateVectorOfNativeStructs(
872 const std::vector<S, Alloc> &v, T (*const pack_func)(const S &)) {
873 return CreateVectorOfNativeStructs<T, S>(data(v), v.size(), pack_func);
874 }
875
876 /// @brief Serialize a `std::vector` of native structs into a FlatBuffer
877 /// `vector`.
878 /// @tparam T The data type of the `std::vector` struct elements.
879 /// @tparam S The data type of the `std::vector` native struct elements.
880 /// @param[in] v A const reference to the `std::vector` of structs to
881 /// serialize into the buffer as a `vector`.
882 /// @return Returns a typed `Offset` into the serialized data indicating
883 /// where the vector is stored.
884 template<typename T, typename S, typename Alloc = std::allocator<S>>
885 Offset<Vector<const T *>> CreateVectorOfNativeStructs(
886 const std::vector<S, Alloc> &v) {
887 return CreateVectorOfNativeStructs<T, S>(data(v), v.size());
888 }
889
890 /// @cond FLATBUFFERS_INTERNAL
891 template<typename T> struct StructKeyComparator {
892 bool operator()(const T &a, const T &b) const {
893 return a.KeyCompareLessThan(&b);
894 }
895 };
896 /// @endcond
897
898 /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`
899 /// in sorted order.
900 /// @tparam T The data type of the `std::vector` struct elements.
901 /// @param[in] v A const reference to the `std::vector` of structs to
902 /// serialize into the buffer as a `vector`.
903 /// @return Returns a typed `Offset` into the serialized data indicating
904 /// where the vector is stored.
905 template<typename T, typename Alloc = std::allocator<T>>
906 Offset<Vector<const T *>> CreateVectorOfSortedStructs(
907 std::vector<T, Alloc> *v) {
908 return CreateVectorOfSortedStructs(data(*v), v->size());
909 }
910
911 /// @brief Serialize a `std::vector` of native structs into a FlatBuffer
912 /// `vector` in sorted order.
913 /// @tparam T The data type of the `std::vector` struct elements.
914 /// @tparam S The data type of the `std::vector` native struct elements.
915 /// @param[in] v A const reference to the `std::vector` of structs to
916 /// serialize into the buffer as a `vector`.
917 /// @return Returns a typed `Offset` into the serialized data indicating
918 /// where the vector is stored.
919 template<typename T, typename S, typename Alloc = std::allocator<T>>
920 Offset<Vector<const T *>> CreateVectorOfSortedNativeStructs(
921 std::vector<S, Alloc> *v) {
922 return CreateVectorOfSortedNativeStructs<T, S>(data(*v), v->size());
923 }
924
925 /// @brief Serialize an array of structs into a FlatBuffer `vector` in sorted
926 /// order.
927 /// @tparam T The data type of the struct array elements.
928 /// @param[in] v A pointer to the array of type `T` to serialize into the
929 /// buffer as a `vector`.
930 /// @param[in] len The number of elements to serialize.
931 /// @return Returns a typed `Offset` into the serialized data indicating
932 /// where the vector is stored.
933 template<typename T>
934 Offset<Vector<const T *>> CreateVectorOfSortedStructs(T *v, size_t len) {
935 std::stable_sort(v, v + len, StructKeyComparator<T>());
936 return CreateVectorOfStructs(v, len);
937 }
938
939 /// @brief Serialize an array of native structs into a FlatBuffer `vector` in
940 /// sorted order.
941 /// @tparam T The data type of the struct array elements.
942 /// @tparam S The data type of the native struct array elements.
943 /// @param[in] v A pointer to the array of type `S` to serialize into the
944 /// buffer as a `vector`.
945 /// @param[in] len The number of elements to serialize.
946 /// @return Returns a typed `Offset` into the serialized data indicating
947 /// where the vector is stored.
948 template<typename T, typename S>
949 Offset<Vector<const T *>> CreateVectorOfSortedNativeStructs(S *v,
950 size_t len) {
951 extern T Pack(const S &);
952 auto structs = StartVectorOfStructs<T>(len);
953 for (size_t i = 0; i < len; i++) { structs[i] = Pack(v[i]); }
954 std::stable_sort(structs, structs + len, StructKeyComparator<T>());
955 return EndVectorOfStructs<T>(len);
956 }
957
958 /// @cond FLATBUFFERS_INTERNAL
959 template<typename T> struct TableKeyComparator {
960 TableKeyComparator(vector_downward &buf) : buf_(buf) {}
961 TableKeyComparator(const TableKeyComparator &other) : buf_(other.buf_) {}
962 bool operator()(const Offset<T> &a, const Offset<T> &b) const {
963 auto table_a = reinterpret_cast<T *>(buf_.data_at(a.o));
964 auto table_b = reinterpret_cast<T *>(buf_.data_at(b.o));
965 return table_a->KeyCompareLessThan(table_b);
966 }
967 vector_downward &buf_;
968
969 private:
970 FLATBUFFERS_DELETE_FUNC(
971 TableKeyComparator &operator=(const TableKeyComparator &other));
972 };
973 /// @endcond
974
975 /// @brief Serialize an array of `table` offsets as a `vector` in the buffer
976 /// in sorted order.
977 /// @tparam T The data type that the offset refers to.
978 /// @param[in] v An array of type `Offset<T>` that contains the `table`
979 /// offsets to store in the buffer in sorted order.
980 /// @param[in] len The number of elements to store in the `vector`.
981 /// @return Returns a typed `Offset` into the serialized data indicating
982 /// where the vector is stored.
983 template<typename T>
984 Offset<Vector<Offset<T>>> CreateVectorOfSortedTables(Offset<T> *v,
985 size_t len) {
986 std::stable_sort(v, v + len, TableKeyComparator<T>(buf_));
987 return CreateVector(v, len);
988 }
989
990 /// @brief Serialize an array of `table` offsets as a `vector` in the buffer
991 /// in sorted order.
992 /// @tparam T The data type that the offset refers to.
993 /// @param[in] v An array of type `Offset<T>` that contains the `table`
994 /// offsets to store in the buffer in sorted order.
995 /// @return Returns a typed `Offset` into the serialized data indicating
996 /// where the vector is stored.
997 template<typename T, typename Alloc = std::allocator<T>>
998 Offset<Vector<Offset<T>>> CreateVectorOfSortedTables(
999 std::vector<Offset<T>, Alloc> *v) {
1000 return CreateVectorOfSortedTables(data(*v), v->size());
1001 }
1002
1003 /// @brief Specialized version of `CreateVector` for non-copying use cases.
1004 /// Write the data any time later to the returned buffer pointer `buf`.
1005 /// @param[in] len The number of elements to store in the `vector`.
1006 /// @param[in] elemsize The size of each element in the `vector`.
1007 /// @param[out] buf A pointer to a `uint8_t` pointer that can be
1008 /// written to at a later time to serialize the data into a `vector`
1009 /// in the buffer.
1010 uoffset_t CreateUninitializedVector(size_t len, size_t elemsize,
1011 uint8_t **buf) {
1012 NotNested();
1013 StartVector(len, elemsize);
1014 buf_.make_space(len * elemsize);
1015 auto vec_start = GetSize();
1016 auto vec_end = EndVector(len);
1017 *buf = buf_.data_at(vec_start);
1018 return vec_end;
1019 }
1020
1021 /// @brief Specialized version of `CreateVector` for non-copying use cases.
1022 /// Write the data any time later to the returned buffer pointer `buf`.
1023 /// @tparam T The data type of the data that will be stored in the buffer
1024 /// as a `vector`.
1025 /// @param[in] len The number of elements to store in the `vector`.
1026 /// @param[out] buf A pointer to a pointer of type `T` that can be
1027 /// written to at a later time to serialize the data into a `vector`
1028 /// in the buffer.
1029 template<typename T>
1030 Offset<Vector<T>> CreateUninitializedVector(size_t len, T **buf) {
1031 AssertScalarT<T>();
1032 return CreateUninitializedVector(len, sizeof(T),
1033 reinterpret_cast<uint8_t **>(buf));
1034 }
1035
1036 template<typename T>
1037 Offset<Vector<const T *>> CreateUninitializedVectorOfStructs(size_t len,
1038 T **buf) {
1039 return CreateUninitializedVector(len, sizeof(T),
1040 reinterpret_cast<uint8_t **>(buf));
1041 }
1042
1043 // @brief Create a vector of scalar type T given as input a vector of scalar
1044 // type U, useful with e.g. pre "enum class" enums, or any existing scalar
1045 // data of the wrong type.
1046 template<typename T, typename U>
1047 Offset<Vector<T>> CreateVectorScalarCast(const U *v, size_t len) {
1048 AssertScalarT<T>();
1049 AssertScalarT<U>();
1050 StartVector(len, sizeof(T));
1051 for (auto i = len; i > 0;) { PushElement(static_cast<T>(v[--i])); }
1052 return Offset<Vector<T>>(EndVector(len));
1053 }
1054
1055 /// @brief Write a struct by itself, typically to be part of a union.
1056 template<typename T> Offset<const T *> CreateStruct(const T &structobj) {
1057 NotNested();
1058 Align(AlignOf<T>());
1059 buf_.push_small(structobj);
1060 return Offset<const T *>(GetSize());
1061 }
1062
1063 /// @brief Finish serializing a buffer by writing the root offset.
1064 /// @param[in] file_identifier If a `file_identifier` is given, the buffer
1065 /// will be prefixed with a standard FlatBuffers file header.
1066 template<typename T>
1067 void Finish(Offset<T> root, const char *file_identifier = nullptr) {
1068 Finish(root.o, file_identifier, false);
1069 }
1070
1071 /// @brief Finish a buffer with a 32 bit size field pre-fixed (size of the
1072 /// buffer following the size field). These buffers are NOT compatible
1073 /// with standard buffers created by Finish, i.e. you can't call GetRoot
1074 /// on them, you have to use GetSizePrefixedRoot instead.
1075 /// All >32 bit quantities in this buffer will be aligned when the whole
1076 /// size pre-fixed buffer is aligned.
1077 /// These kinds of buffers are useful for creating a stream of FlatBuffers.
1078 template<typename T>
1079 void FinishSizePrefixed(Offset<T> root,
1080 const char *file_identifier = nullptr) {
1081 Finish(root.o, file_identifier, true);
1082 }
1083
1084 void SwapBufAllocator(FlatBufferBuilder &other) {
1085 buf_.swap_allocator(other.buf_);
1086 }
1087
1088 /// @brief The length of a FlatBuffer file header.
1089 static const size_t kFileIdentifierLength =
1090 ::flatbuffers::kFileIdentifierLength;
1091
1092 protected:
1093 // You shouldn't really be copying instances of this class.
1094 FlatBufferBuilder(const FlatBufferBuilder &);
1095 FlatBufferBuilder &operator=(const FlatBufferBuilder &);
1096
1097 void Finish(uoffset_t root, const char *file_identifier, bool size_prefix) {
1098 NotNested();
1099 buf_.clear_scratch();
1100 // This will cause the whole buffer to be aligned.
1101 PreAlign((size_prefix ? sizeof(uoffset_t) : 0) + sizeof(uoffset_t) +
1102 (file_identifier ? kFileIdentifierLength : 0),
1103 minalign_);
1104 if (file_identifier) {
1105 FLATBUFFERS_ASSERT(strlen(file_identifier) == kFileIdentifierLength);
1106 PushBytes(reinterpret_cast<const uint8_t *>(file_identifier),
1107 kFileIdentifierLength);
1108 }
1109 PushElement(ReferTo(root)); // Location of root.
1110 if (size_prefix) { PushElement(GetSize()); }
1111 finished = true;
1112 }
1113
1114 struct FieldLoc {
1115 uoffset_t off;
1116 voffset_t id;
1117 };
1118
1119 vector_downward buf_;
1120
1121 // Accumulating offsets of table members while it is being built.
1122 // We store these in the scratch pad of buf_, after the vtable offsets.
1123 uoffset_t num_field_loc;
1124 // Track how much of the vtable is in use, so we can output the most compact
1125 // possible vtable.
1126 voffset_t max_voffset_;
1127
1128 // Ensure objects are not nested.
1129 bool nested;
1130
1131 // Ensure the buffer is finished before it is being accessed.
1132 bool finished;
1133
1134 size_t minalign_;
1135
1136 bool force_defaults_; // Serialize values equal to their defaults anyway.
1137
1138 bool dedup_vtables_;
1139
1140 struct StringOffsetCompare {
1141 StringOffsetCompare(const vector_downward &buf) : buf_(&buf) {}
1142 bool operator()(const Offset<String> &a, const Offset<String> &b) const {
1143 auto stra = reinterpret_cast<const String *>(buf_->data_at(a.o));
1144 auto strb = reinterpret_cast<const String *>(buf_->data_at(b.o));
1145 return StringLessThan(stra->data(), stra->size(), strb->data(),
1146 strb->size());
1147 }
1148 const vector_downward *buf_;
1149 };
1150
1151 // For use with CreateSharedString. Instantiated on first use only.
1152 typedef std::set<Offset<String>, StringOffsetCompare> StringOffsetMap;
1153 StringOffsetMap *string_pool;
1154
1155 private:
1156 // Allocates space for a vector of structures.
1157 // Must be completed with EndVectorOfStructs().
1158 template<typename T> T *StartVectorOfStructs(size_t vector_size) {
1159 StartVector(vector_size * sizeof(T) / AlignOf<T>(), AlignOf<T>());
1160 return reinterpret_cast<T *>(buf_.make_space(vector_size * sizeof(T)));
1161 }
1162
1163 // End the vector of structures in the flatbuffers.
1164 // Vector should have previously be started with StartVectorOfStructs().
1165 template<typename T>
1166 Offset<Vector<const T *>> EndVectorOfStructs(size_t vector_size) {
1167 return Offset<Vector<const T *>>(EndVector(vector_size));
1168 }
1169};
1170/// @}
1171
1172/// Helpers to get a typed pointer to objects that are currently being built.
1173/// @warning Creating new objects will lead to reallocations and invalidates
1174/// the pointer!
1175template<typename T>
1176T *GetMutableTemporaryPointer(FlatBufferBuilder &fbb, Offset<T> offset) {
1177 return reinterpret_cast<T *>(fbb.GetCurrentBufferPointer() + fbb.GetSize() -
1178 offset.o);
1179}
1180
1181template<typename T>
1182const T *GetTemporaryPointer(FlatBufferBuilder &fbb, Offset<T> offset) {
1183 return GetMutableTemporaryPointer<T>(fbb, offset);
1184}
1185
1186template<typename T>
1187void FlatBufferBuilder::Required(Offset<T> table, voffset_t field) {
1188 auto table_ptr = reinterpret_cast<const Table *>(buf_.data_at(table.o));
1189 bool ok = table_ptr->GetOptionalFieldOffset(field) != 0;
1190 // If this fails, the caller will show what field needs to be set.
1191 FLATBUFFERS_ASSERT(ok);
1192 (void)ok;
1193}
1194
1195} // namespace flatbuffers
1196
1197#endif // FLATBUFFERS_VECTOR_DOWNWARD_H_