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