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