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