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