damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

FlatBufferBuilder.swift (30006B)


      1 /*
      2  * Copyright 2023 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 #if !os(WASI)
     18 import Foundation
     19 #else
     20 import SwiftOverlayShims
     21 #endif
     22 
     23 /// ``FlatBufferBuilder`` builds a `FlatBuffer` through manipulating its internal state.
     24 ///
     25 /// This is done by creating a ``ByteBuffer`` that hosts the incoming data and
     26 /// has a hardcoded growth limit of `2GiB` which is set by the Flatbuffers standards.
     27 ///
     28 /// ```swift
     29 /// var builder = FlatBufferBuilder()
     30 /// ```
     31 /// The builder should be always created as a variable, since it would be passed into the writers
     32 ///
     33 @frozen
     34 public struct FlatBufferBuilder {
     35 
     36   /// Storage for the Vtables used in the buffer are stored in here, so they would be written later in EndTable
     37   @usableFromInline internal var _vtableStorage = VTableStorage()
     38   /// Flatbuffer data will be written into
     39   @usableFromInline internal var _bb: ByteBuffer
     40 
     41   /// Reference Vtables that were already written to the buffer
     42   private var _vtables: [UOffset] = []
     43   /// A check if the buffer is being written into by a different table
     44   private var isNested = false
     45   /// Dictonary that stores a map of all the strings that were written to the buffer
     46   private var stringOffsetMap: [String: Offset] = [:]
     47   /// A check to see if finish(::) was ever called to retreive data object
     48   private var finished = false
     49   /// A check to see if the buffer should serialize Default values
     50   private var serializeDefaults: Bool
     51 
     52   /// Current alignment for the buffer
     53   var _minAlignment: Int = 0 {
     54     didSet {
     55       _bb.alignment = _minAlignment
     56     }
     57   }
     58 
     59   /// Gives a read access to the buffer's size
     60   public var size: UOffset { _bb.size }
     61 
     62   #if !os(WASI)
     63   /// Data representation of the buffer
     64   ///
     65   /// Should only be used after ``finish(offset:addPrefix:)`` is called
     66   public var data: Data {
     67     assert(finished, "Data shouldn't be called before finish()")
     68     return Data(
     69       bytes: _bb.memory.advanced(by: _bb.writerIndex),
     70       count: _bb.capacity &- _bb.writerIndex)
     71   }
     72   #endif
     73 
     74   /// Returns the underlying bytes in the ``ByteBuffer``
     75   ///
     76   /// Note: This should be used with caution.
     77   public var fullSizedByteArray: [UInt8] {
     78     let ptr = UnsafeBufferPointer(
     79       start: _bb.memory.assumingMemoryBound(to: UInt8.self),
     80       count: _bb.capacity)
     81     return Array(ptr)
     82   }
     83 
     84   /// Returns the written bytes into the ``ByteBuffer``
     85   ///
     86   /// Should only be used after ``finish(offset:addPrefix:)`` is called
     87   public var sizedByteArray: [UInt8] {
     88     assert(finished, "Data shouldn't be called before finish()")
     89     return _bb.underlyingBytes
     90   }
     91 
     92   /// Returns the original ``ByteBuffer``
     93   ///
     94   /// Returns the current buffer that was just created
     95   /// with the offsets, and data written to it.
     96   public var buffer: ByteBuffer { _bb }
     97 
     98   /// Returns a newly created sized ``ByteBuffer``
     99   ///
    100   /// returns a new buffer that is sized to the data written
    101   /// to the main buffer
    102   public var sizedBuffer: ByteBuffer {
    103     assert(finished, "Data shouldn't be called before finish()")
    104     return ByteBuffer(
    105       memory: _bb.memory.advanced(by: _bb.reader),
    106       count: Int(_bb.size))
    107   }
    108 
    109   // MARK: - Init
    110 
    111   /// Initialize the buffer with a size
    112   /// - Parameters:
    113   ///   - initialSize: Initial size for the buffer
    114   ///   - force: Allows default to be serialized into the buffer
    115   ///
    116   /// This initializes a new builder with an initialSize that would initialize
    117   /// a new ``ByteBuffer``. ``FlatBufferBuilder`` by default doesnt serialize defaults
    118   /// however the builder can be force by passing true for `serializeDefaults`
    119   public init(
    120     initialSize: Int32 = 1024,
    121     serializeDefaults force: Bool = false)
    122   {
    123     assert(initialSize > 0, "Size should be greater than zero!")
    124     guard isLitteEndian else {
    125       fatalError(
    126         "Reading/Writing a buffer in big endian machine is not supported on swift")
    127     }
    128     serializeDefaults = force
    129     _bb = ByteBuffer(initialSize: Int(initialSize))
    130   }
    131 
    132   /// Clears the builder and the buffer from the written data.
    133   mutating public func clear() {
    134     _minAlignment = 0
    135     isNested = false
    136     stringOffsetMap.removeAll(keepingCapacity: true)
    137     _vtables.removeAll(keepingCapacity: true)
    138     _vtableStorage.clear()
    139     _bb.clear()
    140   }
    141 
    142   // MARK: - Create Tables
    143 
    144   /// Checks if the required fields were serialized into the buffer
    145   /// - Parameters:
    146   ///   - table: offset for the table
    147   ///   - fields: Array of all the important fields to be serialized
    148   ///
    149   /// *NOTE: Never call this function, this is only supposed to be called
    150   /// by the generated code*
    151   @inline(__always)
    152   mutating public func require(table: Offset, fields: [Int32]) {
    153     for field in fields {
    154       let start = _bb.capacity &- Int(table.o)
    155       let startTable = start &- Int(_bb.read(def: Int32.self, position: start))
    156       let isOkay = _bb.read(
    157         def: VOffset.self,
    158         position: startTable &+ Int(field)) != 0
    159       assert(isOkay, "Flatbuffers requires the following field")
    160     }
    161   }
    162 
    163   /// Finished the buffer by adding the file id and then calling finish
    164   /// - Parameters:
    165   ///   - offset: Offset of the table
    166   ///   - fileId: Takes the fileId
    167   ///   - prefix: if false it wont add the size of the buffer
    168   ///
    169   /// ``finish(offset:fileId:addPrefix:)`` should be called at the end of creating
    170   /// a table
    171   /// ```swift
    172   /// var root = SomeObject
    173   ///   .createObject(&builder,
    174   ///   name: nameOffset)
    175   /// builder.finish(
    176   ///   offset: root,
    177   ///   fileId: "ax1a",
    178   ///   addPrefix: true)
    179   /// ```
    180   /// File id would append a file id name at the end of the written bytes before,
    181   /// finishing the buffer.
    182   ///
    183   /// Whereas, if `addPrefix` is true, the written bytes would
    184   /// include the size of the current buffer.
    185   mutating public func finish(
    186     offset: Offset,
    187     fileId: String,
    188     addPrefix prefix: Bool = false)
    189   {
    190     let size = MemoryLayout<UOffset>.size
    191     preAlign(
    192       len: size &+ (prefix ? size : 0) &+ FileIdLength,
    193       alignment: _minAlignment)
    194     assert(fileId.count == FileIdLength, "Flatbuffers requires file id to be 4")
    195     _bb.push(string: fileId, len: 4)
    196     finish(offset: offset, addPrefix: prefix)
    197   }
    198 
    199   /// Finished the buffer by adding the file id, offset, and prefix to it.
    200   /// - Parameters:
    201   ///   - offset: Offset of the table
    202   ///   - prefix: if false it wont add the size of the buffer
    203   ///
    204   /// ``finish(offset:addPrefix:)`` should be called at the end of creating
    205   /// a table
    206   /// ```swift
    207   /// var root = SomeObject
    208   ///   .createObject(&builder,
    209   ///   name: nameOffset)
    210   /// builder.finish(
    211   ///   offset: root,
    212   ///   addPrefix: true)
    213   /// ```
    214   /// If `addPrefix` is true, the written bytes would
    215   /// include the size of the current buffer.
    216   mutating public func finish(
    217     offset: Offset,
    218     addPrefix prefix: Bool = false)
    219   {
    220     notNested()
    221     let size = MemoryLayout<UOffset>.size
    222     preAlign(len: size &+ (prefix ? size : 0), alignment: _minAlignment)
    223     push(element: refer(to: offset.o))
    224     if prefix { push(element: _bb.size) }
    225     _vtableStorage.clear()
    226     finished = true
    227   }
    228 
    229   /// ``startTable(with:)`` will let the builder know, that a new object is being serialized.
    230   ///
    231   /// The function will fatalerror if called while there is another object being serialized.
    232   /// ```swift
    233   /// let start = Monster
    234   ///   .startMonster(&fbb)
    235   /// ```
    236   /// - Parameter numOfFields: Number of elements to be written to the buffer
    237   /// - Returns: Offset of the newly started table
    238   @inline(__always)
    239   mutating public func startTable(with numOfFields: Int) -> UOffset {
    240     notNested()
    241     isNested = true
    242     _vtableStorage.start(count: numOfFields)
    243     return _bb.size
    244   }
    245 
    246   /// ``endTable(at:)`` will let the ``FlatBufferBuilder`` know that the
    247   /// object that's written to it is completed
    248   ///
    249   /// This would be called after all the elements are serialized,
    250   /// it will add the current vtable into the ``ByteBuffer``.
    251   /// The functions will `fatalError` in case the object is called
    252   /// without ``startTable(with:)``, or the object has exceeded  the limit of 2GB.
    253   ///
    254   /// - Parameter startOffset:Start point of the object written
    255   /// - returns: The root of the table
    256   mutating public func endTable(at startOffset: UOffset)  -> UOffset {
    257     assert(isNested, "Calling endtable without calling starttable")
    258     let sizeofVoffset = MemoryLayout<VOffset>.size
    259     let vTableOffset = push(element: SOffset(0))
    260 
    261     let tableObjectSize = vTableOffset &- startOffset
    262     assert(tableObjectSize < 0x10000, "Buffer can't grow beyond 2 Gigabytes")
    263     let _max = Int(_vtableStorage.maxOffset) &+ sizeofVoffset
    264 
    265     _bb.fill(padding: _max)
    266     _bb.write(
    267       value: VOffset(tableObjectSize),
    268       index: _bb.writerIndex &+ sizeofVoffset,
    269       direct: true)
    270     _bb.write(value: VOffset(_max), index: _bb.writerIndex, direct: true)
    271 
    272     var itr = 0
    273     while itr < _vtableStorage.writtenIndex {
    274       let loaded = _vtableStorage.load(at: itr)
    275       itr = itr &+ _vtableStorage.size
    276       guard loaded.offset != 0 else { continue }
    277       let _index = (_bb.writerIndex &+ Int(loaded.position))
    278       _bb.write(
    279         value: VOffset(vTableOffset &- loaded.offset),
    280         index: _index,
    281         direct: true)
    282     }
    283 
    284     _vtableStorage.clear()
    285     let vt_use = _bb.size
    286 
    287     var isAlreadyAdded: Int?
    288 
    289     let vt2 = _bb.memory.advanced(by: _bb.writerIndex)
    290     let len2 = vt2.load(fromByteOffset: 0, as: Int16.self)
    291 
    292     for table in _vtables {
    293       let position = _bb.capacity &- Int(table)
    294       let vt1 = _bb.memory.advanced(by: position)
    295       let len1 = _bb.read(def: Int16.self, position: position)
    296       if len2 != len1 || 0 != memcmp(vt1, vt2, Int(len2)) { continue }
    297 
    298       isAlreadyAdded = Int(table)
    299       break
    300     }
    301 
    302     if let offset = isAlreadyAdded {
    303       let vTableOff = Int(vTableOffset)
    304       let space = _bb.capacity &- vTableOff
    305       _bb.write(value: Int32(offset &- vTableOff), index: space, direct: true)
    306       _bb.pop(_bb.capacity &- space)
    307     } else {
    308       _bb.write(value: Int32(vt_use &- vTableOffset), index: Int(vTableOffset))
    309       _vtables.append(_bb.size)
    310     }
    311     isNested = false
    312     return vTableOffset
    313   }
    314 
    315   // MARK: - Builds Buffer
    316 
    317   /// Asserts to see if the object is not nested
    318   @inline(__always)
    319   @usableFromInline
    320   mutating internal func notNested()  {
    321     assert(!isNested, "Object serialization must not be nested")
    322   }
    323 
    324   /// Changes the minimuim alignment of the buffer
    325   /// - Parameter size: size of the current alignment
    326   @inline(__always)
    327   @usableFromInline
    328   mutating internal func minAlignment(size: Int) {
    329     if size > _minAlignment {
    330       _minAlignment = size
    331     }
    332   }
    333 
    334   /// Gets the padding for the current element
    335   /// - Parameters:
    336   ///   - bufSize: Current size of the buffer + the offset of the object to be written
    337   ///   - elementSize: Element size
    338   @inline(__always)
    339   @usableFromInline
    340   mutating internal func padding(
    341     bufSize: UInt32,
    342     elementSize: UInt32) -> UInt32
    343   {
    344     ((~bufSize) &+ 1) & (elementSize - 1)
    345   }
    346 
    347   /// Prealigns the buffer before writting a new object into the buffer
    348   /// - Parameters:
    349   ///   - len:Length of the object
    350   ///   - alignment: Alignment type
    351   @inline(__always)
    352   @usableFromInline
    353   mutating internal func preAlign(len: Int, alignment: Int) {
    354     minAlignment(size: alignment)
    355     _bb.fill(padding: Int(padding(
    356       bufSize: _bb.size &+ UOffset(len),
    357       elementSize: UOffset(alignment))))
    358   }
    359 
    360   /// Prealigns the buffer before writting a new object into the buffer
    361   /// - Parameters:
    362   ///   - len: Length of the object
    363   ///   - type: Type of the object to be written
    364   @inline(__always)
    365   @usableFromInline
    366   mutating internal func preAlign<T: Scalar>(len: Int, type: T.Type) {
    367     preAlign(len: len, alignment: MemoryLayout<T>.size)
    368   }
    369 
    370   /// Refers to an object that's written in the buffer
    371   /// - Parameter off: the objects index value
    372   @inline(__always)
    373   @usableFromInline
    374   mutating internal func refer(to off: UOffset) -> UOffset {
    375     let size = MemoryLayout<UOffset>.size
    376     preAlign(len: size, alignment: size)
    377     return _bb.size &- off &+ UInt32(size)
    378   }
    379 
    380   /// Tracks the elements written into the buffer
    381   /// - Parameters:
    382   ///   - offset: The offset of the element witten
    383   ///   - position: The position of the element
    384   @inline(__always)
    385   @usableFromInline
    386   mutating internal func track(offset: UOffset, at position: VOffset) {
    387     _vtableStorage.add(loc: FieldLoc(offset: offset, position: position))
    388   }
    389 
    390   // MARK: - Inserting Vectors
    391 
    392   /// ``startVector(_:elementSize:)`` creates a new vector within buffer
    393   ///
    394   /// The function checks if there is a current object being written, if
    395   /// the check passes it creates a buffer alignment of `length * elementSize`
    396   /// ```swift
    397   /// builder.startVector(
    398   ///   int32Values.count, elementSize: 4)
    399   /// ```
    400   ///
    401   /// - Parameters:
    402   ///   - len: Length of vector to be created
    403   ///   - elementSize: Size of object type to be written
    404   @inline(__always)
    405   mutating public func startVector(_ len: Int, elementSize: Int) {
    406     notNested()
    407     isNested = true
    408     preAlign(len: len &* elementSize, type: UOffset.self)
    409     preAlign(len: len &* elementSize, alignment: elementSize)
    410   }
    411 
    412   /// ``endVector(len:)`` ends the currently created vector
    413   ///
    414   /// Calling ``endVector(len:)`` requires the length, of the current
    415   /// vector. The length would be pushed to indicate the count of numbers
    416   /// within the vector. If ``endVector(len:)`` is called without
    417   /// ``startVector(_:elementSize:)`` it asserts.
    418   ///
    419   /// ```swift
    420   /// let vectorOffset = builder.
    421   ///   endVector(len: int32Values.count)
    422   /// ```
    423   ///
    424   /// - Parameter len: Length of the buffer
    425   /// - Returns: Returns the current ``Offset`` in the ``ByteBuffer``
    426   @inline(__always)
    427   mutating public func endVector(len: Int) -> Offset {
    428     assert(isNested, "Calling endVector without calling startVector")
    429     isNested = false
    430     return Offset(offset: push(element: Int32(len)))
    431   }
    432 
    433   /// Creates a vector of type ``Scalar`` into the ``ByteBuffer``
    434   ///
    435   /// ``createVector(_:)-4swl0`` writes a vector of type Scalars into
    436   /// ``ByteBuffer``. This is a convenient method instead of calling,
    437   /// ``startVector(_:elementSize:)`` and then ``endVector(len:)``
    438   /// ```swift
    439   /// let vectorOffset = builder.
    440   ///   createVector([1, 2, 3, 4])
    441   /// ```
    442   ///
    443   /// The underlying implementation simply calls ``createVector(_:size:)-4lhrv``
    444   ///
    445   /// - Parameter elements: elements to be written into the buffer
    446   /// - returns: ``Offset`` of the vector
    447   @inline(__always)
    448   mutating public func createVector<T: Scalar>(_ elements: [T]) -> Offset {
    449     createVector(elements, size: elements.count)
    450   }
    451 
    452   ///  Creates a vector of type Scalar in the buffer
    453   ///
    454   /// ``createVector(_:)-4swl0`` writes a vector of type Scalars into
    455   /// ``ByteBuffer``. This is a convenient method instead of calling,
    456   /// ``startVector(_:elementSize:)`` and then ``endVector(len:)``
    457   /// ```swift
    458   /// let vectorOffset = builder.
    459   ///   createVector([1, 2, 3, 4], size: 4)
    460   /// ```
    461   ///
    462   /// - Parameter elements: Elements to be written into the buffer
    463   /// - Parameter size: Count of elements
    464   /// - returns: ``Offset`` of the vector
    465   @inline(__always)
    466   mutating public func createVector<T: Scalar>(
    467     _ elements: [T],
    468     size: Int) -> Offset
    469   {
    470     let size = size
    471     startVector(size, elementSize: MemoryLayout<T>.size)
    472     _bb.push(elements: elements)
    473     return endVector(len: size)
    474   }
    475 
    476   /// Creates a vector of type ``Enum`` into the ``ByteBuffer``
    477   ///
    478   /// ``createVector(_:)-9h189`` writes a vector of type ``Enum`` into
    479   /// ``ByteBuffer``. This is a convenient method instead of calling,
    480   /// ``startVector(_:elementSize:)`` and then ``endVector(len:)``
    481   /// ```swift
    482   /// let vectorOffset = builder.
    483   ///   createVector([.swift, .cpp])
    484   /// ```
    485   ///
    486   /// The underlying implementation simply calls ``createVector(_:size:)-7cx6z``
    487   ///
    488   /// - Parameter elements: elements to be written into the buffer
    489   /// - returns: ``Offset`` of the vector
    490   @inline(__always)
    491   mutating public func createVector<T: Enum>(_ elements: [T]) -> Offset {
    492     createVector(elements, size: elements.count)
    493   }
    494 
    495   /// Creates a vector of type ``Enum`` into the ``ByteBuffer``
    496   ///
    497   /// ``createVector(_:)-9h189`` writes a vector of type ``Enum`` into
    498   /// ``ByteBuffer``. This is a convenient method instead of calling,
    499   /// ``startVector(_:elementSize:)`` and then ``endVector(len:)``
    500   /// ```swift
    501   /// let vectorOffset = builder.
    502   ///   createVector([.swift, .cpp])
    503   /// ```
    504   ///
    505   /// - Parameter elements: Elements to be written into the buffer
    506   /// - Parameter size: Count of elements
    507   /// - returns: ``Offset`` of the vector
    508   @inline(__always)
    509   mutating public func createVector<T: Enum>(
    510     _ elements: [T],
    511     size: Int) -> Offset
    512   {
    513     let size = size
    514     startVector(size, elementSize: T.byteSize)
    515     for e in elements.reversed() {
    516       _bb.push(value: e.value, len: T.byteSize)
    517     }
    518     return endVector(len: size)
    519   }
    520 
    521   /// Creates a vector of already written offsets
    522   ///
    523   /// ``createVector(ofOffsets:)`` creates a vector of ``Offset`` into
    524   /// ``ByteBuffer``. This is a convenient method instead of calling,
    525   /// ``startVector(_:elementSize:)`` and then ``endVector(len:)``.
    526   ///
    527   /// The underlying implementation simply calls ``createVector(ofOffsets:len:)``
    528   ///
    529   /// ```swift
    530   /// let namesOffsets = builder.
    531   ///   createVector(ofOffsets: [name1, name2])
    532   /// ```
    533   /// - Parameter offsets: Array of offsets of type ``Offset``
    534   /// - returns: ``Offset`` of the vector
    535   @inline(__always)
    536   mutating public func createVector(ofOffsets offsets: [Offset]) -> Offset {
    537     createVector(ofOffsets: offsets, len: offsets.count)
    538   }
    539 
    540   /// Creates a vector of already written offsets
    541   ///
    542   /// ``createVector(ofOffsets:)`` creates a vector of ``Offset`` into
    543   /// ``ByteBuffer``. This is a convenient method instead of calling,
    544   /// ``startVector(_:elementSize:)`` and then ``endVector(len:)``
    545   ///
    546   /// ```swift
    547   /// let namesOffsets = builder.
    548   ///   createVector(ofOffsets: [name1, name2])
    549   /// ```
    550   ///
    551   /// - Parameter offsets: Array of offsets of type ``Offset``
    552   /// - Parameter size: Count of elements
    553   /// - returns: ``Offset`` of the vector
    554   @inline(__always)
    555   mutating public func createVector(
    556     ofOffsets offsets: [Offset],
    557     len: Int) -> Offset
    558   {
    559     startVector(len, elementSize: MemoryLayout<Offset>.size)
    560     for o in offsets.reversed() {
    561       push(element: o)
    562     }
    563     return endVector(len: len)
    564   }
    565 
    566   /// Creates a vector of strings
    567   ///
    568   /// ``createVector(ofStrings:)`` creates a vector of `String` into
    569   /// ``ByteBuffer``. This is a convenient method instead of manually
    570   /// creating the string offsets, you simply pass it to this function
    571   /// and it would write the strings into the ``ByteBuffer``.
    572   /// After that it calls ``createVector(ofOffsets:)``
    573   ///
    574   /// ```swift
    575   /// let namesOffsets = builder.
    576   ///   createVector(ofStrings: ["Name", "surname"])
    577   /// ```
    578   ///
    579   /// - Parameter str: Array of string
    580   /// - returns: ``Offset`` of the vector
    581   @inline(__always)
    582   mutating public func createVector(ofStrings str: [String]) -> Offset {
    583     var offsets: [Offset] = []
    584     for s in str {
    585       offsets.append(create(string: s))
    586     }
    587     return createVector(ofOffsets: offsets)
    588   }
    589 
    590   /// Creates a vector of type ``NativeStruct``.
    591   ///
    592   /// Any swift struct in the generated code, should confirm to
    593   /// ``NativeStruct``. Since the generated swift structs are padded
    594   /// to the `FlatBuffers` standards.
    595   ///
    596   /// ```swift
    597   /// let offsets = builder.
    598   ///   createVector(ofStructs: [NativeStr(num: 1), NativeStr(num: 2)])
    599   /// ```
    600   ///
    601   /// - Parameter structs: A vector of ``NativeStruct``
    602   /// - Returns: ``Offset`` of the vector
    603   @inline(__always)
    604   mutating public func createVector<T: NativeStruct>(ofStructs structs: [T])
    605     -> Offset
    606   {
    607     startVector(
    608       structs.count * MemoryLayout<T>.size,
    609       elementSize: MemoryLayout<T>.alignment)
    610     for i in structs.reversed() {
    611       _ = create(struct: i)
    612     }
    613     return endVector(len: structs.count)
    614   }
    615 
    616   // MARK: - Inserting Structs
    617 
    618   /// Writes a ``NativeStruct`` into the ``ByteBuffer``
    619   ///
    620   /// Adds a native struct that's build and padded according
    621   /// to `FlatBuffers` standards. with a predefined position.
    622   ///
    623   /// ```swift
    624   /// let offset = builder.create(
    625   ///   struct: NativeStr(num: 1),
    626   ///   position: 10)
    627   /// ```
    628   ///
    629   /// - Parameters:
    630   ///   - s: ``NativeStruct`` to be inserted into the ``ByteBuffer``
    631   ///   - position: The  predefined position of the object
    632   /// - Returns: ``Offset`` of written struct
    633   @inline(__always)
    634   @discardableResult
    635   mutating public func create<T: NativeStruct>(
    636     struct s: T, position: VOffset) -> Offset
    637   {
    638     let offset = create(struct: s)
    639     _vtableStorage.add(loc: FieldLoc(
    640       offset: _bb.size,
    641       position: VOffset(position)))
    642     return offset
    643   }
    644 
    645   /// Writes a ``NativeStruct`` into the ``ByteBuffer``
    646   ///
    647   /// Adds a native struct that's build and padded according
    648   /// to `FlatBuffers` standards, directly into the buffer without
    649   /// a predefined position.
    650   ///
    651   /// ```swift
    652   /// let offset = builder.create(
    653   ///   struct: NativeStr(num: 1))
    654   /// ```
    655   ///
    656   /// - Parameters:
    657   ///   - s: ``NativeStruct`` to be inserted into the ``ByteBuffer``
    658   /// - Returns: ``Offset`` of written struct
    659   @inline(__always)
    660   @discardableResult
    661   mutating public func create<T: NativeStruct>(
    662     struct s: T) -> Offset
    663   {
    664     let size = MemoryLayout<T>.size
    665     preAlign(len: size, alignment: MemoryLayout<T>.alignment)
    666     _bb.push(struct: s, size: size)
    667     return Offset(offset: _bb.size)
    668   }
    669 
    670   // MARK: - Inserting Strings
    671 
    672   /// Insets a string into the buffer of type `UTF8`
    673   ///
    674   /// Adds a swift string into ``ByteBuffer`` by encoding it
    675   /// using `UTF8`
    676   ///
    677   /// ```swift
    678   /// let nameOffset = builder
    679   ///   .create(string: "welcome")
    680   /// ```
    681   ///
    682   /// - Parameter str: String to be serialized
    683   /// - returns: ``Offset`` of inserted string
    684   @inline(__always)
    685   mutating public func create(string str: String?) -> Offset {
    686     guard let str = str else { return Offset() }
    687     let len = str.utf8.count
    688     notNested()
    689     preAlign(len: len &+ 1, type: UOffset.self)
    690     _bb.fill(padding: 1)
    691     _bb.push(string: str, len: len)
    692     push(element: UOffset(len))
    693     return Offset(offset: _bb.size)
    694   }
    695 
    696   /// Insets a shared string into the buffer of type `UTF8`
    697   ///
    698   /// Adds a swift string into ``ByteBuffer`` by encoding it
    699   /// using `UTF8`. The function will check if the string,
    700   /// is already written to the ``ByteBuffer``
    701   ///
    702   /// ```swift
    703   /// let nameOffset = builder
    704   ///   .createShared(string: "welcome")
    705   ///
    706   ///
    707   /// let secondOffset = builder
    708   ///   .createShared(string: "welcome")
    709   ///
    710   /// assert(nameOffset.o == secondOffset.o)
    711   /// ```
    712   ///
    713   /// - Parameter str: String to be serialized
    714   /// - returns: ``Offset`` of inserted string
    715   @inline(__always)
    716   mutating public func createShared(string str: String?) -> Offset {
    717     guard let str = str else { return Offset() }
    718     if let offset = stringOffsetMap[str] {
    719       return offset
    720     }
    721     let offset = create(string: str)
    722     stringOffsetMap[str] = offset
    723     return offset
    724   }
    725 
    726   // MARK: - Inseting offsets
    727 
    728   /// Writes the ``Offset`` of an already written table
    729   ///
    730   /// Writes the ``Offset`` of a table if not empty into the
    731   /// ``ByteBuffer``
    732   ///
    733   /// - Parameters:
    734   ///   - offset: ``Offset`` of another object to be written
    735   ///   - position: The predefined position of the object
    736   @inline(__always)
    737   mutating public func add(offset: Offset, at position: VOffset) {
    738     if offset.isEmpty { return }
    739     add(element: refer(to: offset.o), def: 0, at: position)
    740   }
    741 
    742   /// Pushes a value of type ``Offset`` into the ``ByteBuffer``
    743   /// - Parameter o: ``Offset``
    744   /// - returns: Current position of the ``Offset``
    745   @inline(__always)
    746   @discardableResult
    747   mutating public func push(element o: Offset) -> UOffset {
    748     push(element: refer(to: o.o))
    749   }
    750 
    751   // MARK: - Inserting Scalars to Buffer
    752 
    753   /// Writes a ``Scalar`` value into ``ByteBuffer``
    754   ///
    755   /// ``add(element:def:at:)`` takes in a default value, and current value
    756   /// and the position within the `VTable`. The default value would not
    757   /// be serialized if the value is the same as the current value or
    758   /// `serializeDefaults` is equal to false.
    759   ///
    760   /// If serializing defaults is important ``init(initialSize:serializeDefaults:)``,
    761   /// passing true for `serializeDefaults` would do the job.
    762   ///
    763   /// ```swift
    764   /// // Adds 10 to the buffer
    765   /// builder.add(element: Int(10), def: 1, position 12)
    766   /// ```
    767   ///
    768   /// *NOTE: Never call this manually*
    769   ///
    770   /// - Parameters:
    771   ///   - element: Element to insert
    772   ///   - def: Default value for that element
    773   ///   - position: The predefined position of the element
    774   @inline(__always)
    775   mutating public func add<T: Scalar>(
    776     element: T,
    777     def: T,
    778     at position: VOffset)
    779   {
    780     if element == def && !serializeDefaults { return }
    781     track(offset: push(element: element), at: position)
    782   }
    783 
    784   /// Writes a optional ``Scalar`` value into ``ByteBuffer``
    785   ///
    786   /// Takes an optional value to be written into the ``ByteBuffer``
    787   ///
    788   /// *NOTE: Never call this manually*
    789   ///
    790   /// - Parameters:
    791   ///   - element: Optional element of type scalar
    792   ///   - position: The predefined position of the element
    793   @inline(__always)
    794   mutating public func add<T: Scalar>(element: T?, at position: VOffset) {
    795     guard let element = element else { return }
    796     track(offset: push(element: element), at: position)
    797   }
    798 
    799   /// Pushes a values of type ``Scalar`` into the ``ByteBuffer``
    800   ///
    801   /// *NOTE: Never call this manually*
    802   ///
    803   /// - Parameter element: Element to insert
    804   /// - returns: Postion of the Element
    805   @inline(__always)
    806   @discardableResult
    807   mutating public func push<T: Scalar>(element: T) -> UOffset {
    808     let size = MemoryLayout<T>.size
    809     preAlign(
    810       len: size,
    811       alignment: size)
    812     _bb.push(value: element, len: size)
    813     return _bb.size
    814   }
    815 
    816 }
    817 
    818 extension FlatBufferBuilder: CustomDebugStringConvertible {
    819 
    820   public var debugDescription: String {
    821     """
    822     buffer debug:
    823     \(_bb)
    824     builder debug:
    825     { finished: \(finished), serializeDefaults: \(serializeDefaults), isNested: \(isNested) }
    826     """
    827   }
    828 
    829   /// VTableStorage is a class to contain the VTable buffer that would be serialized into buffer
    830   @usableFromInline
    831   internal class VTableStorage {
    832     /// Memory check since deallocating each time we want to clear would be expensive
    833     /// and memory leaks would happen if we dont deallocate the first allocated memory.
    834     /// memory is promised to be available before adding `FieldLoc`
    835     private var memoryInUse = false
    836     /// Size of FieldLoc in memory
    837     let size = MemoryLayout<FieldLoc>.stride
    838     /// Memeory buffer
    839     var memory: UnsafeMutableRawBufferPointer!
    840     /// Capacity of the current buffer
    841     var capacity: Int = 0
    842     /// Maximuim offset written to the class
    843     var maxOffset: VOffset = 0
    844     /// number of fields written into the buffer
    845     var numOfFields: Int = 0
    846     /// Last written Index
    847     var writtenIndex: Int = 0
    848 
    849     /// Creates the memory to store the buffer in
    850     @usableFromInline
    851     @inline(__always)
    852     init() {
    853       memory = UnsafeMutableRawBufferPointer.allocate(
    854         byteCount: 0,
    855         alignment: 0)
    856     }
    857 
    858     @inline(__always)
    859     deinit {
    860       memory.deallocate()
    861     }
    862 
    863     /// Builds a buffer with byte count of fieldloc.size * count of field numbers
    864     /// - Parameter count: number of fields to be written
    865     @inline(__always)
    866     func start(count: Int) {
    867       assert(count >= 0, "number of fields should NOT be negative")
    868       let capacity = count &* size
    869       ensure(space: capacity)
    870     }
    871 
    872     /// Adds a FieldLoc into the buffer, which would track how many have been written,
    873     /// and max offset
    874     /// - Parameter loc: Location of encoded element
    875     @inline(__always)
    876     func add(loc: FieldLoc) {
    877       memory.baseAddress?.advanced(by: writtenIndex).storeBytes(
    878         of: loc,
    879         as: FieldLoc.self)
    880       writtenIndex = writtenIndex &+ size
    881       numOfFields = numOfFields &+ 1
    882       maxOffset = max(loc.position, maxOffset)
    883     }
    884 
    885     /// Clears the data stored related to the encoded buffer
    886     @inline(__always)
    887     func clear() {
    888       maxOffset = 0
    889       numOfFields = 0
    890       writtenIndex = 0
    891     }
    892 
    893     /// Ensure that the buffer has enough space instead of recreating the buffer each time.
    894     /// - Parameter space: space required for the new vtable
    895     @inline(__always)
    896     func ensure(space: Int) {
    897       guard space &+ writtenIndex > capacity else { return }
    898       memory.deallocate()
    899       memory = UnsafeMutableRawBufferPointer.allocate(
    900         byteCount: space,
    901         alignment: size)
    902       capacity = space
    903     }
    904 
    905     /// Loads an object of type `FieldLoc` from buffer memory
    906     /// - Parameter index: index of element
    907     /// - Returns: a FieldLoc at index
    908     @inline(__always)
    909     func load(at index: Int) -> FieldLoc {
    910       memory.load(fromByteOffset: index, as: FieldLoc.self)
    911     }
    912 
    913   }
    914 
    915   internal struct FieldLoc {
    916     var offset: UOffset
    917     var position: VOffset
    918   }
    919 
    920 }