Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-08-27 09:30:25

0001 /*
0002  * Copyright 2021 Google Inc. All rights reserved.
0003  *
0004  * Licensed under the Apache License, Version 2.0 (the "License");
0005  * you may not use this file except in compliance with the License.
0006  * You may obtain a copy of the License at
0007  *
0008  *     http://www.apache.org/licenses/LICENSE-2.0
0009  *
0010  * Unless required by applicable law or agreed to in writing, software
0011  * distributed under the License is distributed on an "AS IS" BASIS,
0012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013  * See the License for the specific language governing permissions and
0014  * limitations under the License.
0015  */
0016 
0017 #ifndef FLATBUFFERS_FLATBUFFER_BUILDER_H_
0018 #define FLATBUFFERS_FLATBUFFER_BUILDER_H_
0019 
0020 #include <algorithm>
0021 #include <cstdint>
0022 #include <functional>
0023 #include <initializer_list>
0024 #include <type_traits>
0025 
0026 #include "flatbuffers/allocator.h"
0027 #include "flatbuffers/array.h"
0028 #include "flatbuffers/base.h"
0029 #include "flatbuffers/buffer.h"
0030 #include "flatbuffers/buffer_ref.h"
0031 #include "flatbuffers/default_allocator.h"
0032 #include "flatbuffers/detached_buffer.h"
0033 #include "flatbuffers/stl_emulation.h"
0034 #include "flatbuffers/string.h"
0035 #include "flatbuffers/struct.h"
0036 #include "flatbuffers/table.h"
0037 #include "flatbuffers/vector.h"
0038 #include "flatbuffers/vector_downward.h"
0039 #include "flatbuffers/verifier.h"
0040 
0041 namespace flatbuffers {
0042 
0043 // Converts a Field ID to a virtual table offset.
0044 inline voffset_t FieldIndexToOffset(voffset_t field_id) {
0045   // Should correspond to what EndTable() below builds up.
0046   const voffset_t fixed_fields =
0047       2 * sizeof(voffset_t);  // Vtable size and Object Size.
0048   size_t offset = fixed_fields + field_id * sizeof(voffset_t);
0049   FLATBUFFERS_ASSERT(offset < std::numeric_limits<voffset_t>::max());
0050   return static_cast<voffset_t>(offset);
0051 }
0052 
0053 template<typename T, typename Alloc = std::allocator<T>>
0054 const T *data(const std::vector<T, Alloc> &v) {
0055   // Eventually the returned pointer gets passed down to memcpy, so
0056   // we need it to be non-null to avoid undefined behavior.
0057   static uint8_t t;
0058   return v.empty() ? reinterpret_cast<const T *>(&t) : &v.front();
0059 }
0060 template<typename T, typename Alloc = std::allocator<T>>
0061 T *data(std::vector<T, Alloc> &v) {
0062   // Eventually the returned pointer gets passed down to memcpy, so
0063   // we need it to be non-null to avoid undefined behavior.
0064   static uint8_t t;
0065   return v.empty() ? reinterpret_cast<T *>(&t) : &v.front();
0066 }
0067 
0068 /// @addtogroup flatbuffers_cpp_api
0069 /// @{
0070 /// @class FlatBufferBuilder
0071 /// @brief Helper class to hold data needed in creation of a FlatBuffer.
0072 /// To serialize data, you typically call one of the `Create*()` functions in
0073 /// the generated code, which in turn call a sequence of `StartTable`/
0074 /// `PushElement`/`AddElement`/`EndTable`, or the builtin `CreateString`/
0075 /// `CreateVector` functions. Do this is depth-first order to build up a tree to
0076 /// the root. `Finish()` wraps up the buffer ready for transport.
0077 template<bool Is64Aware = false> class FlatBufferBuilderImpl {
0078  public:
0079   // This switches the size type of the builder, based on if its 64-bit aware
0080   // (uoffset64_t) or not (uoffset_t).
0081   typedef
0082       typename std::conditional<Is64Aware, uoffset64_t, uoffset_t>::type SizeT;
0083 
0084   /// @brief Default constructor for FlatBufferBuilder.
0085   /// @param[in] initial_size The initial size of the buffer, in bytes. Defaults
0086   /// to `1024`.
0087   /// @param[in] allocator An `Allocator` to use. If null will use
0088   /// `DefaultAllocator`.
0089   /// @param[in] own_allocator Whether the builder/vector should own the
0090   /// allocator. Defaults to / `false`.
0091   /// @param[in] buffer_minalign Force the buffer to be aligned to the given
0092   /// minimum alignment upon reallocation. Only needed if you intend to store
0093   /// types with custom alignment AND you wish to read the buffer in-place
0094   /// directly after creation.
0095   explicit FlatBufferBuilderImpl(
0096       size_t initial_size = 1024, Allocator *allocator = nullptr,
0097       bool own_allocator = false,
0098       size_t buffer_minalign = AlignOf<largest_scalar_t>())
0099       : buf_(initial_size, allocator, own_allocator, buffer_minalign,
0100              static_cast<SizeT>(Is64Aware ? FLATBUFFERS_MAX_64_BUFFER_SIZE
0101                                           : FLATBUFFERS_MAX_BUFFER_SIZE)),
0102         num_field_loc(0),
0103         max_voffset_(0),
0104         length_of_64_bit_region_(0),
0105         nested(false),
0106         finished(false),
0107         minalign_(1),
0108         force_defaults_(false),
0109         dedup_vtables_(true),
0110         string_pool(nullptr) {
0111     EndianCheck();
0112   }
0113 
0114   /// @brief Move constructor for FlatBufferBuilder.
0115   FlatBufferBuilderImpl(FlatBufferBuilderImpl &&other) noexcept
0116       : buf_(1024, nullptr, false, AlignOf<largest_scalar_t>(),
0117              static_cast<SizeT>(Is64Aware ? FLATBUFFERS_MAX_64_BUFFER_SIZE
0118                                           : FLATBUFFERS_MAX_BUFFER_SIZE)),
0119         num_field_loc(0),
0120         max_voffset_(0),
0121         length_of_64_bit_region_(0),
0122         nested(false),
0123         finished(false),
0124         minalign_(1),
0125         force_defaults_(false),
0126         dedup_vtables_(true),
0127         string_pool(nullptr) {
0128     EndianCheck();
0129     // Default construct and swap idiom.
0130     // Lack of delegating constructors in vs2010 makes it more verbose than
0131     // needed.
0132     Swap(other);
0133   }
0134 
0135   /// @brief Move assignment operator for FlatBufferBuilder.
0136   FlatBufferBuilderImpl &operator=(FlatBufferBuilderImpl &&other) noexcept {
0137     // Move construct a temporary and swap idiom
0138     FlatBufferBuilderImpl temp(std::move(other));
0139     Swap(temp);
0140     return *this;
0141   }
0142 
0143   void Swap(FlatBufferBuilderImpl &other) {
0144     using std::swap;
0145     buf_.swap(other.buf_);
0146     swap(num_field_loc, other.num_field_loc);
0147     swap(max_voffset_, other.max_voffset_);
0148     swap(length_of_64_bit_region_, other.length_of_64_bit_region_);
0149     swap(nested, other.nested);
0150     swap(finished, other.finished);
0151     swap(minalign_, other.minalign_);
0152     swap(force_defaults_, other.force_defaults_);
0153     swap(dedup_vtables_, other.dedup_vtables_);
0154     swap(string_pool, other.string_pool);
0155   }
0156 
0157   ~FlatBufferBuilderImpl() {
0158     if (string_pool) delete string_pool;
0159   }
0160 
0161   void Reset() {
0162     Clear();       // clear builder state
0163     buf_.reset();  // deallocate buffer
0164   }
0165 
0166   /// @brief Reset all the state in this FlatBufferBuilder so it can be reused
0167   /// to construct another buffer.
0168   void Clear() {
0169     ClearOffsets();
0170     buf_.clear();
0171     nested = false;
0172     finished = false;
0173     minalign_ = 1;
0174     length_of_64_bit_region_ = 0;
0175     if (string_pool) string_pool->clear();
0176   }
0177 
0178   /// @brief The current size of the serialized buffer, counting from the end.
0179   /// @return Returns an `SizeT` with the current size of the buffer.
0180   SizeT GetSize() const { return buf_.size(); }
0181 
0182   /// @brief The current size of the serialized buffer relative to the end of
0183   /// the 32-bit region.
0184   /// @return Returns an `uoffset_t` with the current size of the buffer.
0185   template<bool is_64 = Is64Aware>
0186   // Only enable this method for the 64-bit builder, as only that builder is
0187   // concerned with the 32/64-bit boundary, and should be the one to bare any
0188   // run time costs.
0189   typename std::enable_if<is_64, uoffset_t>::type GetSizeRelative32BitRegion()
0190       const {
0191     //[32-bit region][64-bit region]
0192     //         [XXXXXXXXXXXXXXXXXXX] GetSize()
0193     //               [YYYYYYYYYYYYY] length_of_64_bit_region_
0194     //         [ZZZZ]                return size
0195     return static_cast<uoffset_t>(GetSize() - length_of_64_bit_region_);
0196   }
0197 
0198   template<bool is_64 = Is64Aware>
0199   // Only enable this method for the 32-bit builder.
0200   typename std::enable_if<!is_64, uoffset_t>::type GetSizeRelative32BitRegion()
0201       const {
0202     return static_cast<uoffset_t>(GetSize());
0203   }
0204 
0205   /// @brief Get the serialized buffer (after you call `Finish()`).
0206   /// @return Returns an `uint8_t` pointer to the FlatBuffer data inside the
0207   /// buffer.
0208   uint8_t *GetBufferPointer() const {
0209     Finished();
0210     return buf_.data();
0211   }
0212 
0213   /// @brief Get the serialized buffer (after you call `Finish()`) as a span.
0214   /// @return Returns a constructed flatbuffers::span that is a view over the
0215   /// FlatBuffer data inside the buffer.
0216   flatbuffers::span<uint8_t> GetBufferSpan() const {
0217     Finished();
0218     return flatbuffers::span<uint8_t>(buf_.data(), buf_.size());
0219   }
0220 
0221   /// @brief Get a pointer to an unfinished buffer.
0222   /// @return Returns a `uint8_t` pointer to the unfinished buffer.
0223   uint8_t *GetCurrentBufferPointer() const { return buf_.data(); }
0224 
0225   /// @brief Get the released DetachedBuffer.
0226   /// @return A `DetachedBuffer` that owns the buffer and its allocator.
0227   DetachedBuffer Release() {
0228     Finished();
0229     DetachedBuffer buffer = buf_.release();
0230     Clear();
0231     return buffer;
0232   }
0233 
0234   /// @brief Get the released pointer to the serialized buffer.
0235   /// @param size The size of the memory block containing
0236   /// the serialized `FlatBuffer`.
0237   /// @param offset The offset from the released pointer where the finished
0238   /// `FlatBuffer` starts.
0239   /// @return A raw pointer to the start of the memory block containing
0240   /// the serialized `FlatBuffer`.
0241   /// @remark If the allocator is owned, it gets deleted when the destructor is
0242   /// called.
0243   uint8_t *ReleaseRaw(size_t &size, size_t &offset) {
0244     Finished();
0245     uint8_t *raw = buf_.release_raw(size, offset);
0246     Clear();
0247     return raw;
0248   }
0249 
0250   /// @brief get the minimum alignment this buffer needs to be accessed
0251   /// properly. This is only known once all elements have been written (after
0252   /// you call Finish()). You can use this information if you need to embed
0253   /// a FlatBuffer in some other buffer, such that you can later read it
0254   /// without first having to copy it into its own buffer.
0255   size_t GetBufferMinAlignment() const {
0256     Finished();
0257     return minalign_;
0258   }
0259 
0260   /// @cond FLATBUFFERS_INTERNAL
0261   void Finished() const {
0262     // If you get this assert, you're attempting to get access a buffer
0263     // which hasn't been finished yet. Be sure to call
0264     // FlatBufferBuilder::Finish with your root table.
0265     // If you really need to access an unfinished buffer, call
0266     // GetCurrentBufferPointer instead.
0267     FLATBUFFERS_ASSERT(finished);
0268   }
0269   /// @endcond
0270 
0271   /// @brief In order to save space, fields that are set to their default value
0272   /// don't get serialized into the buffer.
0273   /// @param[in] fd When set to `true`, always serializes default values that
0274   /// are set. Optional fields which are not set explicitly, will still not be
0275   /// serialized.
0276   void ForceDefaults(bool fd) { force_defaults_ = fd; }
0277 
0278   /// @brief By default vtables are deduped in order to save space.
0279   /// @param[in] dedup When set to `true`, dedup vtables.
0280   void DedupVtables(bool dedup) { dedup_vtables_ = dedup; }
0281 
0282   /// @cond FLATBUFFERS_INTERNAL
0283   void Pad(size_t num_bytes) { buf_.fill(num_bytes); }
0284 
0285   void TrackMinAlign(size_t elem_size) {
0286     if (elem_size > minalign_) minalign_ = elem_size;
0287   }
0288 
0289   void Align(size_t elem_size) {
0290     TrackMinAlign(elem_size);
0291     buf_.fill(PaddingBytes(buf_.size(), elem_size));
0292   }
0293 
0294   void PushFlatBuffer(const uint8_t *bytes, size_t size) {
0295     PushBytes(bytes, size);
0296     finished = true;
0297   }
0298 
0299   void PushBytes(const uint8_t *bytes, size_t size) { buf_.push(bytes, size); }
0300 
0301   void PopBytes(size_t amount) { buf_.pop(amount); }
0302 
0303   template<typename T> void AssertScalarT() {
0304     // The code assumes power of 2 sizes and endian-swap-ability.
0305     static_assert(flatbuffers::is_scalar<T>::value, "T must be a scalar type");
0306   }
0307 
0308   // Write a single aligned scalar to the buffer
0309   template<typename T, typename ReturnT = uoffset_t>
0310   ReturnT PushElement(T element) {
0311     AssertScalarT<T>();
0312     Align(sizeof(T));
0313     buf_.push_small(EndianScalar(element));
0314     return CalculateOffset<ReturnT>();
0315   }
0316 
0317   template<typename T, template<typename> class OffsetT = Offset>
0318   uoffset_t PushElement(OffsetT<T> off) {
0319     // Special case for offsets: see ReferTo below.
0320     return PushElement(ReferTo(off.o));
0321   }
0322 
0323   // When writing fields, we track where they are, so we can create correct
0324   // vtables later.
0325   void TrackField(voffset_t field, uoffset_t off) {
0326     FieldLoc fl = { off, field };
0327     buf_.scratch_push_small(fl);
0328     num_field_loc++;
0329     if (field > max_voffset_) { max_voffset_ = field; }
0330   }
0331 
0332   // Like PushElement, but additionally tracks the field this represents.
0333   template<typename T> void AddElement(voffset_t field, T e, T def) {
0334     // We don't serialize values equal to the default.
0335     if (IsTheSameAs(e, def) && !force_defaults_) return;
0336     TrackField(field, PushElement(e));
0337   }
0338 
0339   template<typename T> void AddElement(voffset_t field, T e) {
0340     TrackField(field, PushElement(e));
0341   }
0342 
0343   template<typename T> void AddOffset(voffset_t field, Offset<T> off) {
0344     if (off.IsNull()) return;  // Don't store.
0345     AddElement(field, ReferTo(off.o), static_cast<uoffset_t>(0));
0346   }
0347 
0348   template<typename T> void AddOffset(voffset_t field, Offset64<T> off) {
0349     if (off.IsNull()) return;  // Don't store.
0350     AddElement(field, ReferTo(off.o), static_cast<uoffset64_t>(0));
0351   }
0352 
0353   template<typename T> void AddStruct(voffset_t field, const T *structptr) {
0354     if (!structptr) return;  // Default, don't store.
0355     Align(AlignOf<T>());
0356     buf_.push_small(*structptr);
0357     TrackField(field, CalculateOffset<uoffset_t>());
0358   }
0359 
0360   void AddStructOffset(voffset_t field, uoffset_t off) {
0361     TrackField(field, off);
0362   }
0363 
0364   // Offsets initially are relative to the end of the buffer (downwards).
0365   // This function converts them to be relative to the current location
0366   // in the buffer (when stored here), pointing upwards.
0367   uoffset_t ReferTo(uoffset_t off) {
0368     // Align to ensure GetSizeRelative32BitRegion() below is correct.
0369     Align(sizeof(uoffset_t));
0370     // 32-bit offsets are relative to the tail of the 32-bit region of the
0371     // buffer. For most cases (without 64-bit entities) this is equivalent to
0372     // size of the whole buffer (e.g. GetSize())
0373     return ReferTo(off, GetSizeRelative32BitRegion());
0374   }
0375 
0376   uoffset64_t ReferTo(uoffset64_t off) {
0377     // Align to ensure GetSize() below is correct.
0378     Align(sizeof(uoffset64_t));
0379     // 64-bit offsets are relative to tail of the whole buffer
0380     return ReferTo(off, GetSize());
0381   }
0382 
0383   template<typename T, typename T2> T ReferTo(const T off, const T2 size) {
0384     FLATBUFFERS_ASSERT(off && off <= size);
0385     return size - off + static_cast<T>(sizeof(T));
0386   }
0387 
0388   template<typename T> T ReferTo(const T off, const T size) {
0389     FLATBUFFERS_ASSERT(off && off <= size);
0390     return size - off + static_cast<T>(sizeof(T));
0391   }
0392 
0393   void NotNested() {
0394     // If you hit this, you're trying to construct a Table/Vector/String
0395     // during the construction of its parent table (between the MyTableBuilder
0396     // and table.Finish().
0397     // Move the creation of these sub-objects to above the MyTableBuilder to
0398     // not get this assert.
0399     // Ignoring this assert may appear to work in simple cases, but the reason
0400     // it is here is that storing objects in-line may cause vtable offsets
0401     // to not fit anymore. It also leads to vtable duplication.
0402     FLATBUFFERS_ASSERT(!nested);
0403     // If you hit this, fields were added outside the scope of a table.
0404     FLATBUFFERS_ASSERT(!num_field_loc);
0405   }
0406 
0407   // From generated code (or from the parser), we call StartTable/EndTable
0408   // with a sequence of AddElement calls in between.
0409   uoffset_t StartTable() {
0410     NotNested();
0411     nested = true;
0412     return GetSizeRelative32BitRegion();
0413   }
0414 
0415   // This finishes one serialized object by generating the vtable if it's a
0416   // table, comparing it against existing vtables, and writing the
0417   // resulting vtable offset.
0418   uoffset_t EndTable(uoffset_t start) {
0419     // If you get this assert, a corresponding StartTable wasn't called.
0420     FLATBUFFERS_ASSERT(nested);
0421     // Write the vtable offset, which is the start of any Table.
0422     // We fill its value later.
0423     // This is relative to the end of the 32-bit region.
0424     const uoffset_t vtable_offset_loc =
0425         static_cast<uoffset_t>(PushElement<soffset_t>(0));
0426     // Write a vtable, which consists entirely of voffset_t elements.
0427     // It starts with the number of offsets, followed by a type id, followed
0428     // by the offsets themselves. In reverse:
0429     // Include space for the last offset and ensure empty tables have a
0430     // minimum size.
0431     max_voffset_ =
0432         (std::max)(static_cast<voffset_t>(max_voffset_ + sizeof(voffset_t)),
0433                    FieldIndexToOffset(0));
0434     buf_.fill_big(max_voffset_);
0435     const uoffset_t table_object_size = vtable_offset_loc - start;
0436     // Vtable use 16bit offsets.
0437     FLATBUFFERS_ASSERT(table_object_size < 0x10000);
0438     WriteScalar<voffset_t>(buf_.data() + sizeof(voffset_t),
0439                            static_cast<voffset_t>(table_object_size));
0440     WriteScalar<voffset_t>(buf_.data(), max_voffset_);
0441     // Write the offsets into the table
0442     for (auto it = buf_.scratch_end() - num_field_loc * sizeof(FieldLoc);
0443          it < buf_.scratch_end(); it += sizeof(FieldLoc)) {
0444       auto field_location = reinterpret_cast<FieldLoc *>(it);
0445       const voffset_t pos =
0446           static_cast<voffset_t>(vtable_offset_loc - field_location->off);
0447       // If this asserts, it means you've set a field twice.
0448       FLATBUFFERS_ASSERT(
0449           !ReadScalar<voffset_t>(buf_.data() + field_location->id));
0450       WriteScalar<voffset_t>(buf_.data() + field_location->id, pos);
0451     }
0452     ClearOffsets();
0453     auto vt1 = reinterpret_cast<voffset_t *>(buf_.data());
0454     auto vt1_size = ReadScalar<voffset_t>(vt1);
0455     auto vt_use = GetSizeRelative32BitRegion();
0456     // See if we already have generated a vtable with this exact same
0457     // layout before. If so, make it point to the old one, remove this one.
0458     if (dedup_vtables_) {
0459       for (auto it = buf_.scratch_data(); it < buf_.scratch_end();
0460            it += sizeof(uoffset_t)) {
0461         auto vt_offset_ptr = reinterpret_cast<uoffset_t *>(it);
0462         auto vt2 = reinterpret_cast<voffset_t *>(buf_.data_at(*vt_offset_ptr));
0463         auto vt2_size = ReadScalar<voffset_t>(vt2);
0464         if (vt1_size != vt2_size || 0 != memcmp(vt2, vt1, vt1_size)) continue;
0465         vt_use = *vt_offset_ptr;
0466         buf_.pop(GetSizeRelative32BitRegion() - vtable_offset_loc);
0467         break;
0468       }
0469     }
0470     // If this is a new vtable, remember it.
0471     if (vt_use == GetSizeRelative32BitRegion()) {
0472       buf_.scratch_push_small(vt_use);
0473     }
0474     // Fill the vtable offset we created above.
0475     // The offset points from the beginning of the object to where the vtable is
0476     // stored.
0477     // Offsets default direction is downward in memory for future format
0478     // flexibility (storing all vtables at the start of the file).
0479     WriteScalar(buf_.data_at(vtable_offset_loc + length_of_64_bit_region_),
0480                 static_cast<soffset_t>(vt_use) -
0481                     static_cast<soffset_t>(vtable_offset_loc));
0482     nested = false;
0483     return vtable_offset_loc;
0484   }
0485 
0486   FLATBUFFERS_ATTRIBUTE([[deprecated("call the version above instead")]])
0487   uoffset_t EndTable(uoffset_t start, voffset_t /*numfields*/) {
0488     return EndTable(start);
0489   }
0490 
0491   // This checks a required field has been set in a given table that has
0492   // just been constructed.
0493   template<typename T> void Required(Offset<T> table, voffset_t field) {
0494     auto table_ptr = reinterpret_cast<const Table *>(buf_.data_at(table.o));
0495     bool ok = table_ptr->GetOptionalFieldOffset(field) != 0;
0496     // If this fails, the caller will show what field needs to be set.
0497     FLATBUFFERS_ASSERT(ok);
0498     (void)ok;
0499   }
0500 
0501   uoffset_t StartStruct(size_t alignment) {
0502     Align(alignment);
0503     return GetSizeRelative32BitRegion();
0504   }
0505 
0506   uoffset_t EndStruct() { return GetSizeRelative32BitRegion(); }
0507 
0508   void ClearOffsets() {
0509     buf_.scratch_pop(num_field_loc * sizeof(FieldLoc));
0510     num_field_loc = 0;
0511     max_voffset_ = 0;
0512   }
0513 
0514   // Aligns such that when "len" bytes are written, an object can be written
0515   // after it (forward in the buffer) with "alignment" without padding.
0516   void PreAlign(size_t len, size_t alignment) {
0517     if (len == 0) return;
0518     TrackMinAlign(alignment);
0519     buf_.fill(PaddingBytes(GetSize() + len, alignment));
0520   }
0521 
0522   // Aligns such than when "len" bytes are written, an object of type `AlignT`
0523   // can be written after it (forward in the buffer) without padding.
0524   template<typename AlignT> void PreAlign(size_t len) {
0525     AssertScalarT<AlignT>();
0526     PreAlign(len, AlignOf<AlignT>());
0527   }
0528   /// @endcond
0529 
0530   /// @brief Store a string in the buffer, which can contain any binary data.
0531   /// @param[in] str A const char pointer to the data to be stored as a string.
0532   /// @param[in] len The number of bytes that should be stored from `str`.
0533   /// @return Returns the offset in the buffer where the string starts.
0534   template<template<typename> class OffsetT = Offset>
0535   OffsetT<String> CreateString(const char *str, size_t len) {
0536     CreateStringImpl(str, len);
0537     return OffsetT<String>(
0538         CalculateOffset<typename OffsetT<String>::offset_type>());
0539   }
0540 
0541   /// @brief Store a string in the buffer, which is null-terminated.
0542   /// @param[in] str A const char pointer to a C-string to add to the buffer.
0543   /// @return Returns the offset in the buffer where the string starts.
0544   template<template<typename> class OffsetT = Offset>
0545   OffsetT<String> CreateString(const char *str) {
0546     return CreateString<OffsetT>(str, strlen(str));
0547   }
0548 
0549   /// @brief Store a string in the buffer, which is null-terminated.
0550   /// @param[in] str A char pointer to a C-string to add to the buffer.
0551   /// @return Returns the offset in the buffer where the string starts.
0552   template<template<typename> class OffsetT = Offset>
0553   OffsetT<String> CreateString(char *str) {
0554     return CreateString<OffsetT>(str, strlen(str));
0555   }
0556 
0557   /// @brief Store a string in the buffer, which can contain any binary data.
0558   /// @param[in] str A const reference to a std::string to store in the buffer.
0559   /// @return Returns the offset in the buffer where the string starts.
0560   template<template<typename> class OffsetT = Offset>
0561   OffsetT<String> CreateString(const std::string &str) {
0562     return CreateString<OffsetT>(str.c_str(), str.length());
0563   }
0564 
0565   // clang-format off
0566   #ifdef FLATBUFFERS_HAS_STRING_VIEW
0567   /// @brief Store a string in the buffer, which can contain any binary data.
0568   /// @param[in] str A const string_view to copy in to the buffer.
0569   /// @return Returns the offset in the buffer where the string starts.
0570   template<template <typename> class OffsetT = Offset>
0571   OffsetT<String>CreateString(flatbuffers::string_view str) {
0572     return CreateString<OffsetT>(str.data(), str.size());
0573   }
0574   #endif // FLATBUFFERS_HAS_STRING_VIEW
0575   // clang-format on
0576 
0577   /// @brief Store a string in the buffer, which can contain any binary data.
0578   /// @param[in] str A const pointer to a `String` struct to add to the buffer.
0579   /// @return Returns the offset in the buffer where the string starts
0580   template<template<typename> class OffsetT = Offset>
0581   OffsetT<String> CreateString(const String *str) {
0582     return str ? CreateString<OffsetT>(str->c_str(), str->size()) : 0;
0583   }
0584 
0585   /// @brief Store a string in the buffer, which can contain any binary data.
0586   /// @param[in] str A const reference to a std::string like type with support
0587   /// of T::data() and T::length() to store in the buffer.
0588   /// @return Returns the offset in the buffer where the string starts.
0589   template<template<typename> class OffsetT = Offset,
0590            // No need to explicitly declare the T type, let the compiler deduce
0591            // it.
0592            int &...ExplicitArgumentBarrier, typename T>
0593   OffsetT<String> CreateString(const T &str) {
0594     return CreateString<OffsetT>(str.data(), str.length());
0595   }
0596 
0597   /// @brief Store a string in the buffer, which can contain any binary data.
0598   /// If a string with this exact contents has already been serialized before,
0599   /// instead simply returns the offset of the existing string. This uses a map
0600   /// stored on the heap, but only stores the numerical offsets.
0601   /// @param[in] str A const char pointer to the data to be stored as a string.
0602   /// @param[in] len The number of bytes that should be stored from `str`.
0603   /// @return Returns the offset in the buffer where the string starts.
0604   Offset<String> CreateSharedString(const char *str, size_t len) {
0605     FLATBUFFERS_ASSERT(FLATBUFFERS_GENERAL_HEAP_ALLOC_OK);
0606     if (!string_pool) {
0607       string_pool = new StringOffsetMap(StringOffsetCompare(buf_));
0608     }
0609 
0610     const size_t size_before_string = buf_.size();
0611     // Must first serialize the string, since the set is all offsets into
0612     // buffer.
0613     const Offset<String> off = CreateString<Offset>(str, len);
0614     auto it = string_pool->find(off);
0615     // If it exists we reuse existing serialized data!
0616     if (it != string_pool->end()) {
0617       // We can remove the string we serialized.
0618       buf_.pop(buf_.size() - size_before_string);
0619       return *it;
0620     }
0621     // Record this string for future use.
0622     string_pool->insert(off);
0623     return off;
0624   }
0625 
0626 #ifdef FLATBUFFERS_HAS_STRING_VIEW
0627   /// @brief Store a string in the buffer, which can contain any binary data.
0628   /// If a string with this exact contents has already been serialized before,
0629   /// instead simply returns the offset of the existing string. This uses a map
0630   /// stored on the heap, but only stores the numerical offsets.
0631   /// @param[in] str A const std::string_view to store in the buffer.
0632   /// @return Returns the offset in the buffer where the string starts
0633   Offset<String> CreateSharedString(const flatbuffers::string_view str) {
0634     return CreateSharedString(str.data(), str.size());
0635   }
0636 #else
0637   /// @brief Store a string in the buffer, which null-terminated.
0638   /// If a string with this exact contents has already been serialized before,
0639   /// instead simply returns the offset of the existing string. This uses a map
0640   /// stored on the heap, but only stores the numerical offsets.
0641   /// @param[in] str A const char pointer to a C-string to add to the buffer.
0642   /// @return Returns the offset in the buffer where the string starts.
0643   Offset<String> CreateSharedString(const char *str) {
0644     return CreateSharedString(str, strlen(str));
0645   }
0646 
0647   /// @brief Store a string in the buffer, which can contain any binary data.
0648   /// If a string with this exact contents has already been serialized before,
0649   /// instead simply returns the offset of the existing string. This uses a map
0650   /// stored on the heap, but only stores the numerical offsets.
0651   /// @param[in] str A const reference to a std::string to store in the buffer.
0652   /// @return Returns the offset in the buffer where the string starts.
0653   Offset<String> CreateSharedString(const std::string &str) {
0654     return CreateSharedString(str.c_str(), str.length());
0655   }
0656 #endif
0657 
0658   /// @brief Store a string in the buffer, which can contain any binary data.
0659   /// If a string with this exact contents has already been serialized before,
0660   /// instead simply returns the offset of the existing string. This uses a map
0661   /// stored on the heap, but only stores the numerical offsets.
0662   /// @param[in] str A const pointer to a `String` struct to add to the buffer.
0663   /// @return Returns the offset in the buffer where the string starts
0664   Offset<String> CreateSharedString(const String *str) {
0665     return str ? CreateSharedString(str->c_str(), str->size()) : 0;
0666   }
0667 
0668   /// @cond FLATBUFFERS_INTERNAL
0669   template<typename LenT = uoffset_t, typename ReturnT = uoffset_t>
0670   ReturnT EndVector(size_t len) {
0671     FLATBUFFERS_ASSERT(nested);  // Hit if no corresponding StartVector.
0672     nested = false;
0673     return PushElement<LenT, ReturnT>(static_cast<LenT>(len));
0674   }
0675 
0676   template<template<typename> class OffsetT = Offset, typename LenT = uint32_t>
0677   void StartVector(size_t len, size_t elemsize, size_t alignment) {
0678     NotNested();
0679     nested = true;
0680     // Align to the Length type of the vector (either 32-bit or 64-bit), so
0681     // that the length of the buffer can be added without padding.
0682     PreAlign<LenT>(len * elemsize);
0683     PreAlign(len * elemsize, alignment);  // Just in case elemsize > uoffset_t.
0684   }
0685 
0686   template<typename T, template<typename> class OffsetT = Offset,
0687            typename LenT = uint32_t>
0688   void StartVector(size_t len) {
0689     return StartVector<OffsetT, LenT>(len, sizeof(T), AlignOf<T>());
0690   }
0691 
0692   // Call this right before StartVector/CreateVector if you want to force the
0693   // alignment to be something different than what the element size would
0694   // normally dictate.
0695   // This is useful when storing a nested_flatbuffer in a vector of bytes,
0696   // or when storing SIMD floats, etc.
0697   void ForceVectorAlignment(const size_t len, const size_t elemsize,
0698                             const size_t alignment) {
0699     if (len == 0) return;
0700     FLATBUFFERS_ASSERT(VerifyAlignmentRequirements(alignment));
0701     PreAlign(len * elemsize, alignment);
0702   }
0703 
0704   template<bool is_64 = Is64Aware>
0705   typename std::enable_if<is_64, void>::type ForceVectorAlignment64(
0706       const size_t len, const size_t elemsize, const size_t alignment) {
0707     // If you hit this assertion, you are trying to force alignment on a
0708     // vector with offset64 after serializing a 32-bit offset.
0709     FLATBUFFERS_ASSERT(GetSize() == length_of_64_bit_region_);
0710 
0711     // Call through.
0712     ForceVectorAlignment(len, elemsize, alignment);
0713 
0714     // Update the 64 bit region.
0715     length_of_64_bit_region_ = GetSize();
0716   }
0717 
0718   // Similar to ForceVectorAlignment but for String fields.
0719   void ForceStringAlignment(size_t len, size_t alignment) {
0720     if (len == 0) return;
0721     FLATBUFFERS_ASSERT(VerifyAlignmentRequirements(alignment));
0722     PreAlign((len + 1) * sizeof(char), alignment);
0723   }
0724 
0725   /// @endcond
0726 
0727   /// @brief Serialize an array into a FlatBuffer `vector`.
0728   /// @tparam T The data type of the array elements.
0729   /// @tparam OffsetT the type of offset to return
0730   /// @tparam VectorT the type of vector to cast to.
0731   /// @param[in] v A pointer to the array of type `T` to serialize into the
0732   /// buffer as a `vector`.
0733   /// @param[in] len The number of elements to serialize.
0734   /// @return Returns a typed `TOffset` into the serialized data indicating
0735   /// where the vector is stored.
0736   template<typename T, template<typename...> class OffsetT = Offset,
0737            template<typename...> class VectorT = Vector>
0738   OffsetT<VectorT<T>> CreateVector(const T *v, size_t len) {
0739     // The type of the length field in the vector.
0740     typedef typename VectorT<T>::size_type LenT;
0741     typedef typename OffsetT<VectorT<T>>::offset_type offset_type;
0742     // If this assert hits, you're specifying a template argument that is
0743     // causing the wrong overload to be selected, remove it.
0744     AssertScalarT<T>();
0745     StartVector<T, OffsetT, LenT>(len);
0746     if (len > 0) {
0747       // clang-format off
0748       #if FLATBUFFERS_LITTLEENDIAN
0749         PushBytes(reinterpret_cast<const uint8_t *>(v), len * sizeof(T));
0750       #else
0751         if (sizeof(T) == 1) {
0752           PushBytes(reinterpret_cast<const uint8_t *>(v), len);
0753         } else {
0754           for (auto i = len; i > 0; ) {
0755             PushElement(v[--i]);
0756           }
0757         }
0758       #endif
0759       // clang-format on
0760     }
0761     return OffsetT<VectorT<T>>(EndVector<LenT, offset_type>(len));
0762   }
0763 
0764   /// @brief Serialize an array like object into a FlatBuffer `vector`.
0765   /// @tparam T The data type of the array elements.
0766   /// @tparam C The type of the array.
0767   /// @param[in] array A reference to an array like object of type `T` to
0768   /// serialize into the buffer as a `vector`.
0769   /// @return Returns a typed `Offset` into the serialized data indicating
0770   /// where the vector is stored.
0771   template<typename T, class C> Offset<Vector<T>> CreateVector(const C &array) {
0772     return CreateVector(array.data(), array.size());
0773   }
0774 
0775   /// @brief Serialize an initializer list into a FlatBuffer `vector`.
0776   /// @tparam T The data type of the initializer list elements.
0777   /// @param[in] v The value of the initializer list.
0778   /// @return Returns a typed `Offset` into the serialized data indicating
0779   /// where the vector is stored.
0780   template<typename T>
0781   Offset<Vector<T>> CreateVector(std::initializer_list<T> v) {
0782     return CreateVector(v.begin(), v.size());
0783   }
0784 
0785   template<typename T>
0786   Offset<Vector<Offset<T>>> CreateVector(const Offset<T> *v, size_t len) {
0787     StartVector<Offset<T>>(len);
0788     for (auto i = len; i > 0;) { PushElement(v[--i]); }
0789     return Offset<Vector<Offset<T>>>(EndVector(len));
0790   }
0791 
0792   /// @brief Serialize a `std::vector` into a FlatBuffer `vector`.
0793   /// @tparam T The data type of the `std::vector` elements.
0794   /// @param v A const reference to the `std::vector` to serialize into the
0795   /// buffer as a `vector`.
0796   /// @return Returns a typed `Offset` into the serialized data indicating
0797   /// where the vector is stored.
0798   template<typename T, typename Alloc = std::allocator<T>>
0799   Offset<Vector<T>> CreateVector(const std::vector<T, Alloc> &v) {
0800     return CreateVector(data(v), v.size());
0801   }
0802 
0803   template<template<typename...> class VectorT = Vector64,
0804            int &...ExplicitArgumentBarrier, typename T>
0805   Offset64<VectorT<T>> CreateVector64(const std::vector<T> &v) {
0806     return CreateVector<T, Offset64, VectorT>(data(v), v.size());
0807   }
0808 
0809   // vector<bool> may be implemented using a bit-set, so we can't access it as
0810   // an array. Instead, read elements manually.
0811   // Background: https://isocpp.org/blog/2012/11/on-vectorbool
0812   Offset<Vector<uint8_t>> CreateVector(const std::vector<bool> &v) {
0813     StartVector<uint8_t>(v.size());
0814     for (auto i = v.size(); i > 0;) {
0815       PushElement(static_cast<uint8_t>(v[--i]));
0816     }
0817     return Offset<Vector<uint8_t>>(EndVector(v.size()));
0818   }
0819 
0820   /// @brief Serialize values returned by a function into a FlatBuffer `vector`.
0821   /// This is a convenience function that takes care of iteration for you.
0822   /// @tparam T The data type of the `std::vector` elements.
0823   /// @param f A function that takes the current iteration 0..vector_size-1 and
0824   /// returns any type that you can construct a FlatBuffers vector out of.
0825   /// @return Returns a typed `Offset` into the serialized data indicating
0826   /// where the vector is stored.
0827   template<typename T>
0828   Offset<Vector<T>> CreateVector(size_t vector_size,
0829                                  const std::function<T(size_t i)> &f) {
0830     FLATBUFFERS_ASSERT(FLATBUFFERS_GENERAL_HEAP_ALLOC_OK);
0831     std::vector<T> elems(vector_size);
0832     for (size_t i = 0; i < vector_size; i++) elems[i] = f(i);
0833     return CreateVector(elems);
0834   }
0835 
0836   /// @brief Serialize values returned by a function into a FlatBuffer `vector`.
0837   /// This is a convenience function that takes care of iteration for you. This
0838   /// uses a vector stored on the heap to store the intermediate results of the
0839   /// iteration.
0840   /// @tparam T The data type of the `std::vector` elements.
0841   /// @param f A function that takes the current iteration 0..vector_size-1,
0842   /// and the state parameter returning any type that you can construct a
0843   /// FlatBuffers vector out of.
0844   /// @param state State passed to f.
0845   /// @return Returns a typed `Offset` into the serialized data indicating
0846   /// where the vector is stored.
0847   template<typename T, typename F, typename S>
0848   Offset<Vector<T>> CreateVector(size_t vector_size, F f, S *state) {
0849     FLATBUFFERS_ASSERT(FLATBUFFERS_GENERAL_HEAP_ALLOC_OK);
0850     std::vector<T> elems(vector_size);
0851     for (size_t i = 0; i < vector_size; i++) elems[i] = f(i, state);
0852     return CreateVector(elems);
0853   }
0854 
0855   /// @brief Serialize a `std::vector<StringType>` into a FlatBuffer `vector`.
0856   /// whereas StringType is any type that is accepted by the CreateString()
0857   /// overloads.
0858   /// This is a convenience function for a common case.
0859   /// @param v A const reference to the `std::vector` to serialize into the
0860   /// buffer as a `vector`.
0861   /// @return Returns a typed `Offset` into the serialized data indicating
0862   /// where the vector is stored.
0863   template<typename StringType = std::string,
0864            typename Alloc = std::allocator<StringType>>
0865   Offset<Vector<Offset<String>>> CreateVectorOfStrings(
0866       const std::vector<StringType, Alloc> &v) {
0867     return CreateVectorOfStrings(v.cbegin(), v.cend());
0868   }
0869 
0870   /// @brief Serialize a collection of Strings into a FlatBuffer `vector`.
0871   /// This is a convenience function for a common case.
0872   /// @param begin The beginning iterator of the collection
0873   /// @param end The ending iterator of the collection
0874   /// @return Returns a typed `Offset` into the serialized data indicating
0875   /// where the vector is stored.
0876   template<class It>
0877   Offset<Vector<Offset<String>>> CreateVectorOfStrings(It begin, It end) {
0878     auto distance = std::distance(begin, end);
0879     FLATBUFFERS_ASSERT(distance >= 0);
0880     auto size = static_cast<size_t>(distance);
0881     auto scratch_buffer_usage = size * sizeof(Offset<String>);
0882     // If there is not enough space to store the offsets, there definitely won't
0883     // be enough space to store all the strings. So ensuring space for the
0884     // scratch region is OK, for if it fails, it would have failed later.
0885     buf_.ensure_space(scratch_buffer_usage);
0886     for (auto it = begin; it != end; ++it) {
0887       buf_.scratch_push_small(CreateString(*it));
0888     }
0889     StartVector<Offset<String>>(size);
0890     for (size_t i = 1; i <= size; i++) {
0891       // Note we re-evaluate the buf location each iteration to account for any
0892       // underlying buffer resizing that may occur.
0893       PushElement(*reinterpret_cast<Offset<String> *>(
0894           buf_.scratch_end() - i * sizeof(Offset<String>)));
0895     }
0896     buf_.scratch_pop(scratch_buffer_usage);
0897     return Offset<Vector<Offset<String>>>(EndVector(size));
0898   }
0899 
0900   /// @brief Serialize an array of structs into a FlatBuffer `vector`.
0901   /// @tparam T The data type of the struct array elements.
0902   /// @param[in] v A pointer to the array of type `T` to serialize into the
0903   /// buffer as a `vector`.
0904   /// @param[in] len The number of elements to serialize.
0905   /// @return Returns a typed `Offset` into the serialized data indicating
0906   /// where the vector is stored.
0907   template<typename T, template<typename...> class OffsetT = Offset,
0908            template<typename...> class VectorT = Vector>
0909   OffsetT<VectorT<const T *>> CreateVectorOfStructs(const T *v, size_t len) {
0910     // The type of the length field in the vector.
0911     typedef typename VectorT<T>::size_type LenT;
0912     typedef typename OffsetT<VectorT<const T *>>::offset_type offset_type;
0913 
0914     StartVector<OffsetT, LenT>(len, sizeof(T), AlignOf<T>());
0915     if (len > 0) {
0916       PushBytes(reinterpret_cast<const uint8_t *>(v), sizeof(T) * len);
0917     }
0918     return OffsetT<VectorT<const T *>>(EndVector<LenT, offset_type>(len));
0919   }
0920 
0921   /// @brief Serialize an array of structs into a FlatBuffer `vector`.
0922   /// @tparam T The data type of the struct array elements.
0923   /// @param[in] filler A function that takes the current iteration
0924   /// 0..vector_size-1 and a pointer to the struct that must be filled.
0925   /// @return Returns a typed `Offset` into the serialized data indicating
0926   /// where the vector is stored.
0927   /// This is mostly useful when flatbuffers are generated with mutation
0928   /// accessors.
0929   template<typename T>
0930   Offset<Vector<const T *>> CreateVectorOfStructs(
0931       size_t vector_size, const std::function<void(size_t i, T *)> &filler) {
0932     T *structs = StartVectorOfStructs<T>(vector_size);
0933     for (size_t i = 0; i < vector_size; i++) {
0934       filler(i, structs);
0935       structs++;
0936     }
0937     return EndVectorOfStructs<T>(vector_size);
0938   }
0939 
0940   /// @brief Serialize an array of structs into a FlatBuffer `vector`.
0941   /// @tparam T The data type of the struct array elements.
0942   /// @param[in] f A function that takes the current iteration 0..vector_size-1,
0943   /// a pointer to the struct that must be filled and the state argument.
0944   /// @param[in] state Arbitrary state to pass to f.
0945   /// @return Returns a typed `Offset` into the serialized data indicating
0946   /// where the vector is stored.
0947   /// This is mostly useful when flatbuffers are generated with mutation
0948   /// accessors.
0949   template<typename T, typename F, typename S>
0950   Offset<Vector<const T *>> CreateVectorOfStructs(size_t vector_size, F f,
0951                                                   S *state) {
0952     T *structs = StartVectorOfStructs<T>(vector_size);
0953     for (size_t i = 0; i < vector_size; i++) {
0954       f(i, structs, state);
0955       structs++;
0956     }
0957     return EndVectorOfStructs<T>(vector_size);
0958   }
0959 
0960   /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`.
0961   /// @tparam T The data type of the `std::vector` struct elements.
0962   /// @param[in] v A const reference to the `std::vector` of structs to
0963   /// serialize into the buffer as a `vector`.
0964   /// @return Returns a typed `Offset` into the serialized data indicating
0965   /// where the vector is stored.
0966   template<typename T, template<typename...> class OffsetT = Offset,
0967            template<typename...> class VectorT = Vector,
0968            typename Alloc = std::allocator<T>>
0969   OffsetT<VectorT<const T *>> CreateVectorOfStructs(
0970       const std::vector<T, Alloc> &v) {
0971     return CreateVectorOfStructs<T, OffsetT, VectorT>(data(v), v.size());
0972   }
0973 
0974   template<template<typename...> class VectorT = Vector64, int &..., typename T>
0975   Offset64<VectorT<const T *>> CreateVectorOfStructs64(
0976       const std::vector<T> &v) {
0977     return CreateVectorOfStructs<T, Offset64, VectorT>(data(v), v.size());
0978   }
0979 
0980   /// @brief Serialize an array of native structs into a FlatBuffer `vector`.
0981   /// @tparam T The data type of the struct array elements.
0982   /// @tparam S The data type of the native struct array elements.
0983   /// @param[in] v A pointer to the array of type `S` to serialize into the
0984   /// buffer as a `vector`.
0985   /// @param[in] len The number of elements to serialize.
0986   /// @param[in] pack_func Pointer to a function to convert the native struct
0987   /// to the FlatBuffer struct.
0988   /// @return Returns a typed `Offset` into the serialized data indicating
0989   /// where the vector is stored.
0990   template<typename T, typename S>
0991   Offset<Vector<const T *>> CreateVectorOfNativeStructs(
0992       const S *v, size_t len, T (*const pack_func)(const S &)) {
0993     FLATBUFFERS_ASSERT(pack_func);
0994     auto structs = StartVectorOfStructs<T>(len);
0995     for (size_t i = 0; i < len; i++) { structs[i] = pack_func(v[i]); }
0996     return EndVectorOfStructs<T>(len);
0997   }
0998 
0999   /// @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>
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>>
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>>
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 {
1046     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>>
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>>
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>
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>
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 {
1114     explicit TableKeyComparator(vector_downward<SizeT> &buf) : buf_(buf) {}
1115     TableKeyComparator(const TableKeyComparator &other) : buf_(other.buf_) {}
1116     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>
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>>
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.
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 
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>
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>
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>
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.
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 
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 
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 {
1332     explicit StringOffsetCompare(const vector_downward<SizeT> &buf)
1333         : buf_(&buf) {}
1334     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:
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.
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>
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>
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
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
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<>
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>
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>
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_