github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/executor/_include/flatbuffers/flatbuffer_builder.h (about)

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