Improves performance for the swift library by using structs + a storage class (#5835)

This commit is contained in:
mustiikhalil
2020-04-02 22:55:30 +03:00
committed by GitHub
parent 925fab6b15
commit a83caf5910
12 changed files with 467 additions and 445 deletions

View File

@@ -1,55 +1,80 @@
import Foundation
public final class ByteBuffer {
public struct ByteBuffer {
/// Storage is a container that would hold the memory pointer to solve the issue of
/// deallocating the memory that was held by (memory: UnsafeMutableRawPointer)
@usableFromInline final class Storage {
/// pointer to the start of the buffer object in memory
var memory: UnsafeMutableRawPointer
/// Capacity of UInt8 the buffer can hold
var capacity: Int
init(count: Int, alignment: Int) {
memory = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: alignment)
capacity = count
}
deinit {
memory.deallocate()
}
func copy(from ptr: UnsafeRawPointer, count: Int) {
memory.copyMemory(from: ptr, byteCount: count)
}
func initalize(for size: Int) {
memory.initializeMemory(as: UInt8.self, repeating: 0, count: size)
}
}
@usableFromInline var _storage: Storage
/// pointer to the start of the buffer object in memory
private var _memory: UnsafeMutableRawPointer
/// The size of the elements written to the buffer + their paddings
private var _writerSize: Int = 0
/// Capacity of UInt8 the buffer can hold
private var _capacity: Int
/// Aliginment of the current memory being written to the buffer
internal var alignment = 1
/// Current Index which is being used to write to the buffer, it is written from the end to the start of the buffer
internal var writerIndex: Int { return _capacity - _writerSize }
internal var writerIndex: Int { return _storage.capacity - _writerSize }
/// Reader is the position of the current Writer Index (capacity - size)
public var reader: Int { return writerIndex }
/// Current size of the buffer
public var size: UOffset { return UOffset(_writerSize) }
/// Public Pointer to the buffer object in memory. This should NOT be modified for any reason
public var memory: UnsafeMutableRawPointer { return _memory }
public var memory: UnsafeMutableRawPointer { return _storage.memory }
/// Current capacity for the buffer
public var capacity: Int { return _capacity }
public var capacity: Int { return _storage.capacity }
/// Constructor that creates a Flatbuffer object from a UInt8
/// - Parameter bytes: Array of UInt8
public init(bytes: [UInt8]) {
let ptr = UnsafePointer(bytes)
_memory = UnsafeMutableRawPointer.allocate(byteCount: bytes.count, alignment: alignment)
_memory.copyMemory(from: ptr, byteCount: bytes.count)
_capacity = bytes.count
_writerSize = _capacity
var b = bytes
_storage = Storage(count: bytes.count, alignment: alignment)
_writerSize = _storage.capacity
b.withUnsafeMutableBytes { bufferPointer in
self._storage.copy(from: bufferPointer.baseAddress!, count: bytes.count)
}
}
/// Constructor that creates a Flatbuffer from the Swift Data type object
/// - Parameter data: Swift data Object
public init(data: Data) {
let pointer = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
data.copyBytes(to: pointer, count: data.count)
_memory = UnsafeMutableRawPointer(pointer)
_capacity = data.count
_writerSize = _capacity
var b = data
_storage = Storage(count: data.count, alignment: alignment)
_writerSize = _storage.capacity
b.withUnsafeMutableBytes { bufferPointer in
self._storage.copy(from: bufferPointer.baseAddress!, count: data.count)
}
}
/// Constructor that creates a Flatbuffer instance with a size
/// - Parameter size: Length of the buffer
init(initialSize size: Int) {
let size = size.convertToPowerofTwo
_memory = UnsafeMutableRawPointer.allocate(byteCount: size, alignment: alignment)
_memory.initializeMemory(as: UInt8.self, repeating: 0, count: size)
_capacity = size
_storage = Storage(count: size, alignment: alignment)
_storage.initalize(for: size)
}
#if swift(>=5.0)
@@ -61,83 +86,78 @@ public final class ByteBuffer {
contiguousBytes: Bytes,
count: Int
) {
_memory = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: alignment)
_capacity = count
_writerSize = _capacity
_storage = Storage(count: count, alignment: alignment)
_writerSize = _storage.capacity
contiguousBytes.withUnsafeBytes { buf in
_memory.copyMemory(from: buf.baseAddress!, byteCount: buf.count)
_storage.copy(from: buf.baseAddress!, count: buf.count)
}
}
#endif
/// Creates a copy of the buffer that's being built by calling sizedBuffer
/// - Parameters:
/// - memory: Current memory of the buffer
/// - count: count of bytes
internal init(memory: UnsafeMutableRawPointer, count: Int) {
_memory = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: alignment)
_memory.copyMemory(from: memory, byteCount: count)
_capacity = count
_writerSize = _capacity
_storage = Storage(count: count, alignment: alignment)
_storage.copy(from: memory, count: count)
_writerSize = _storage.capacity
}
/// Creates a copy of the existing flatbuffer, by copying it to a different memory.
/// - Parameters:
/// - memory: Current memory of the buffer
/// - count: count of bytes
/// - removeBytes: Removes a number of bytes from the current size
internal init(memory: UnsafeMutableRawPointer, count: Int, removing removeBytes: Int) {
_memory = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: alignment)
_memory.copyMemory(from: memory, byteCount: count)
_capacity = count
_storage = Storage(count: count, alignment: alignment)
_storage.copy(from: memory, count: count)
_writerSize = removeBytes
}
deinit { _memory.deallocate() }
/// Fills the buffer with padding by adding to the writersize
/// - Parameter padding: Amount of padding between two to be serialized objects
func fill(padding: UInt32) {
@usableFromInline mutating func fill(padding: UInt32) {
ensureSpace(size: padding)
_writerSize += (MemoryLayout<UInt8>.size * Int(padding))
}
///Adds an array of type Scalar to the buffer memory
/// - Parameter elements: An array of Scalars
func push<T: Scalar>(elements: [T]) {
@usableFromInline mutating func push<T: Scalar>(elements: [T]) {
let size = elements.count * MemoryLayout<T>.size
ensureSpace(size: UInt32(size))
elements.lazy.reversed().forEach { (s) in
push(value: s, len: MemoryLayout.size(ofValue: s))
}
}
/// A custom type of structs that are padded according to the flatbuffer padding,
/// - Parameters:
/// - value: Pointer to the object in memory
/// - size: Size of Value being written to the buffer
func push(struct value: UnsafeMutableRawPointer, size: Int) {
@usableFromInline mutating func push(struct value: UnsafeMutableRawPointer, size: Int) {
ensureSpace(size: UInt32(size))
memcpy(_memory.advanced(by: writerIndex - size), value, size)
memcpy(_storage.memory.advanced(by: writerIndex - size), value, size)
defer { value.deallocate() }
_writerSize += size
}
/// Adds an object of type Scalar into the buffer
/// - Parameters:
/// - value: Object that will be written to the buffer
/// - len: Offset to subtract from the WriterIndex
func push<T: Scalar>(value: T, len: Int) {
@usableFromInline mutating func push<T: Scalar>(value: T, len: Int) {
ensureSpace(size: UInt32(len))
var v = value.convertedEndian
memcpy(_memory.advanced(by: writerIndex - len), &v, len)
memcpy(_storage.memory.advanced(by: writerIndex - len), &v, len)
_writerSize += len
}
/// Adds a string to the buffer using swift.utf8 object
/// - Parameter str: String that will be added to the buffer
/// - Parameter len: length of the string
func push(string str: String, len: Int) {
@usableFromInline mutating func push(string str: String, len: Int) {
ensureSpace(size: UInt32(len))
if str.utf8.withContiguousStorageIfAvailable({ self.push(bytes: $0, len: len) }) != nil {
} else {
@@ -147,18 +167,19 @@ public final class ByteBuffer {
}
}
}
/// Writes a string to Bytebuffer using UTF8View
/// - Parameters:
/// - bytes: Pointer to the view
/// - len: Size of string
private func push(bytes: UnsafeBufferPointer<String.UTF8View.Element>, len: Int) -> Bool {
_memory.advanced(by: writerIndex - len).copyMemory(from:
UnsafeRawPointer(bytes.baseAddress!), byteCount: len)
@usableFromInline mutating internal func push(bytes: UnsafeBufferPointer<String.UTF8View.Element>, len: Int) -> Bool {
memcpy(_storage.memory.advanced(by: writerIndex - len), UnsafeRawPointer(bytes.baseAddress!), len)
// _memory.advanced(by: writerIndex - len).copyMemory(from:
// UnsafeRawPointer(bytes.baseAddress!), byteCount: len)
_writerSize += len
return true
}
/// Write stores an object into the buffer directly or indirectly.
///
/// Direct: ignores the capacity of buffer which would mean we are referring to the direct point in memory
@@ -170,78 +191,78 @@ public final class ByteBuffer {
func write<T>(value: T, index: Int, direct: Bool = false) {
var index = index
if !direct {
index = _capacity - index
index = _storage.capacity - index
}
_memory.storeBytes(of: value, toByteOffset: index, as: T.self)
_storage.memory.storeBytes(of: value, toByteOffset: index, as: T.self)
}
/// Makes sure that buffer has enouch space for each of the objects that will be written into it
/// - Parameter size: size of object
@discardableResult
func ensureSpace(size: UInt32) -> UInt32 {
if Int(size) + _writerSize > _capacity { reallocate(size) }
@usableFromInline mutating func ensureSpace(size: UInt32) -> UInt32 {
if Int(size) + _writerSize > _storage.capacity { reallocate(size) }
assert(size < FlatBufferMaxSize, "Buffer can't grow beyond 2 Gigabytes")
return size
}
/// Reallocates the buffer incase the object to be written doesnt fit in the current buffer
/// - Parameter size: Size of the current object
fileprivate func reallocate(_ size: UInt32) {
@usableFromInline mutating internal func reallocate(_ size: UInt32) {
let currentWritingIndex = writerIndex
while _capacity <= _writerSize + Int(size) {
_capacity = _capacity << 1
while _storage.capacity <= _writerSize + Int(size) {
_storage.capacity = _storage.capacity << 1
}
/// solution take from Apple-NIO
_capacity = _capacity.convertToPowerofTwo
let newData = UnsafeMutableRawPointer.allocate(byteCount: _capacity, alignment: alignment)
newData.initializeMemory(as: UInt8.self, repeating: 0, count: _capacity)
_storage.capacity = _storage.capacity.convertToPowerofTwo
let newData = UnsafeMutableRawPointer.allocate(byteCount: _storage.capacity, alignment: alignment)
newData.initializeMemory(as: UInt8.self, repeating: 0, count: _storage.capacity)
newData
.advanced(by: writerIndex)
.copyMemory(from: _memory.advanced(by: currentWritingIndex), byteCount: _writerSize)
_memory.deallocate()
_memory = newData
.copyMemory(from: _storage.memory.advanced(by: currentWritingIndex), byteCount: _writerSize)
_storage.memory.deallocate()
_storage.memory = newData
}
/// Clears the current size of the buffer
public func clearSize() {
mutating public func clearSize() {
_writerSize = 0
}
/// Clears the current instance of the buffer, replacing it with new memory
public func clear() {
mutating public func clear() {
_writerSize = 0
alignment = 1
_memory.deallocate()
_memory = UnsafeMutableRawPointer.allocate(byteCount: _capacity, alignment: alignment)
_storage.memory.deallocate()
_storage.memory = UnsafeMutableRawPointer.allocate(byteCount: _storage.capacity, alignment: alignment)
}
/// Resizes the buffer size
/// - Parameter size: new size for the buffer
internal func resize(_ size: Int) {
@usableFromInline mutating internal func resize(_ size: Int) {
_writerSize = size
}
/// Reads an object from the buffer
/// - Parameters:
/// - def: Type of the object
/// - position: the index of the object in the buffer
public func read<T>(def: T.Type, position: Int) -> T {
return _memory.advanced(by: position).load(as: T.self)
return _storage.memory.advanced(by: position).load(as: T.self)
}
/// Reads a slice from the memory assuming a type of T
/// - Parameters:
/// - index: index of the object to be read from the buffer
/// - count: count of bytes in memory
public func readSlice<T>(index: Int32,
count: Int32) -> [T] {
let start = _memory.advanced(by: Int(index)).assumingMemoryBound(to: T.self)
let start = _storage.memory.advanced(by: Int(index)).assumingMemoryBound(to: T.self)
let array = UnsafeBufferPointer(start: start, count: Int(count))
return Array(array)
}
/// Reads a string from the buffer and encodes it to a swift string
/// - Parameters:
/// - index: index of the string in the buffer
@@ -250,23 +271,23 @@ public final class ByteBuffer {
public func readString(at index: Int32,
count: Int32,
type: String.Encoding = .utf8) -> String? {
let start = _memory.advanced(by: Int(index)).assumingMemoryBound(to: UInt8.self)
let start = _storage.memory.advanced(by: Int(index)).assumingMemoryBound(to: UInt8.self)
let bufprt = UnsafeBufferPointer(start: start, count: Int(count))
return String(bytes: Array(bufprt), encoding: type)
}
/// Creates a new Flatbuffer object that's duplicated from the current one
/// - Parameter removeBytes: the amount of bytes to remove from the current Size
public func duplicate(removing removeBytes: Int = 0) -> ByteBuffer {
return ByteBuffer(memory: _memory, count: _capacity, removing: _writerSize - removeBytes)
return ByteBuffer(memory: _storage.memory, count: _storage.capacity, removing: _writerSize - removeBytes)
}
}
extension ByteBuffer: CustomDebugStringConvertible {
public var debugDescription: String {
"""
buffer located at: \(_memory), with capacity of \(_capacity)
buffer located at: \(_storage.memory), with capacity of \(_storage.capacity)
{ writerSize: \(_writerSize), readerSize: \(reader), writerIndex: \(writerIndex) }
"""
}

View File

@@ -1,6 +1,6 @@
import Foundation
public final class FlatBufferBuilder {
public struct FlatBufferBuilder {
/// Vtables used in the buffer are stored in here, so they would be written later in EndTable
private var _vtable: [UInt32] = []
@@ -72,7 +72,7 @@ public final class FlatBufferBuilder {
}
/// Clears the buffer and the builder from it's data
public func clear() {
mutating public func clear() {
_minAlignment = 0
isNested = false
_bb.clear()
@@ -80,7 +80,7 @@ public final class FlatBufferBuilder {
}
/// Removes all the offsets from the VTable
public func clearOffsets() {
mutating public func clearOffsets() {
_vtable = []
}
@@ -90,7 +90,7 @@ public final class FlatBufferBuilder {
/// - Parameters:
/// - table: offset for the table
/// - fields: Array of all the important fields to be serialized
public func require(table: Offset<UOffset>, fields: [Int32]) {
mutating public func require(table: Offset<UOffset>, fields: [Int32]) {
for field in fields {
let start = _bb.capacity - Int(table.o)
let startTable = start - Int(_bb.read(def: Int32.self, position: start))
@@ -104,7 +104,7 @@ public final class FlatBufferBuilder {
/// - offset: Offset of the table
/// - fileId: Takes the fileId
/// - prefix: if false it wont add the size of the buffer
public func finish<T>(offset: Offset<T>, fileId: String, addPrefix prefix: Bool = false) {
mutating public func finish<T>(offset: Offset<T>, fileId: String, addPrefix prefix: Bool = false) {
let size = MemoryLayout<UOffset>.size
preAlign(len: size + (prefix ? size : 0) + FileIdLength, alignment: _minAlignment)
assert(fileId.count == FileIdLength, "Flatbuffers requires file id to be 4")
@@ -116,7 +116,7 @@ public final class FlatBufferBuilder {
/// - Parameters:
/// - offset: Offset of the table
/// - prefix: if false it wont add the size of the buffer
public func finish<T>(offset: Offset<T>, addPrefix prefix: Bool = false) {
mutating public func finish<T>(offset: Offset<T>, addPrefix prefix: Bool = false) {
notNested()
let size = MemoryLayout<UOffset>.size
preAlign(len: size + (prefix ? size : 0), alignment: _minAlignment)
@@ -130,7 +130,7 @@ public final class FlatBufferBuilder {
///
/// The function will fatalerror if called while there is another object being serialized
/// - Parameter numOfFields: Number of elements to be written to the buffer
public func startTable(with numOfFields: Int) -> UOffset {
mutating public func startTable(with numOfFields: Int) -> UOffset {
notNested()
isNested = true
_vtable = [UInt32](repeating: 0, count: numOfFields)
@@ -145,7 +145,7 @@ public final class FlatBufferBuilder {
/// 2GB,
/// - Parameter startOffset:Start point of the object written
/// - returns: The root of the table
public func endTable(at startOffset: UOffset) -> UOffset {
mutating public func endTable(at startOffset: UOffset) -> UOffset {
assert(isNested, "Calling endtable without calling starttable")
let sizeofVoffset = MemoryLayout<VOffset>.size
let vTableOffset = push(element: SOffset(0))
@@ -203,13 +203,13 @@ public final class FlatBufferBuilder {
// MARK: - Builds Buffer
/// asserts to see if the object is not nested
fileprivate func notNested() {
@usableFromInline mutating internal func notNested() {
assert(!isNested, "Object serialization must not be nested")
}
/// Changes the minimuim alignment of the buffer
/// - Parameter size: size of the current alignment
fileprivate func minAlignment(size: Int) {
@usableFromInline mutating internal func minAlignment(size: Int) {
if size > _minAlignment {
_minAlignment = size
}
@@ -219,7 +219,7 @@ public final class FlatBufferBuilder {
/// - Parameters:
/// - bufSize: Current size of the buffer + the offset of the object to be written
/// - elementSize: Element size
fileprivate func padding(bufSize: UInt32, elementSize: UInt32) -> UInt32 {
@usableFromInline mutating internal func padding(bufSize: UInt32, elementSize: UInt32) -> UInt32 {
((~bufSize) &+ 1) & (elementSize - 1)
}
@@ -227,7 +227,7 @@ public final class FlatBufferBuilder {
/// - Parameters:
/// - len:Length of the object
/// - alignment: Alignment type
fileprivate func preAlign(len: Int, alignment: Int) {
@usableFromInline mutating internal func preAlign(len: Int, alignment: Int) {
minAlignment(size: alignment)
_bb.fill(padding: padding(bufSize: _bb.size + UOffset(len), elementSize: UOffset(alignment)))
}
@@ -236,13 +236,13 @@ public final class FlatBufferBuilder {
/// - Parameters:
/// - len: Length of the object
/// - type: Type of the object to be written
fileprivate func preAlign<T: Scalar>(len: Int, type: T.Type) {
@usableFromInline mutating internal func preAlign<T: Scalar>(len: Int, type: T.Type) {
preAlign(len: len, alignment: MemoryLayout<T>.size)
}
/// Refers to an object that's written in the buffer
/// - Parameter off: the objects index value
fileprivate func refer(to off: UOffset) -> UOffset {
@usableFromInline mutating internal func refer(to off: UOffset) -> UOffset {
let size = MemoryLayout<UOffset>.size
preAlign(len: size, alignment: size)
return _bb.size - off + UInt32(size)
@@ -252,14 +252,14 @@ public final class FlatBufferBuilder {
/// - Parameters:
/// - offset: The offset of the element witten
/// - position: The position of the element
fileprivate func track(offset: UOffset, at position: VOffset) {
@usableFromInline mutating internal func track(offset: UOffset, at position: VOffset) {
_vtable[Int(position)] = offset
}
// MARK: - Vectors
/// Starts a vector of length and Element size
public func startVector(_ len: Int, elementSize: Int) {
mutating public func startVector(_ len: Int, elementSize: Int) {
notNested()
isNested = true
preAlign(len: len * elementSize, type: UOffset.self)
@@ -270,7 +270,7 @@ public final class FlatBufferBuilder {
///
/// The current function will fatalError if startVector is called before serializing the vector
/// - Parameter len: Length of the buffer
public func endVector(len: Int) -> UOffset {
mutating public func endVector(len: Int) -> UOffset {
assert(isNested, "Calling endVector without calling startVector")
isNested = false
return push(element: Int32(len))
@@ -279,7 +279,7 @@ public final class FlatBufferBuilder {
/// Creates a vector of type Scalar in the buffer
/// - Parameter elements: elements to be written into the buffer
/// - returns: Offset of the vector
public func createVector<T: Scalar>(_ elements: [T]) -> Offset<UOffset> {
mutating public func createVector<T: Scalar>(_ elements: [T]) -> Offset<UOffset> {
return createVector(elements, size: elements.count)
}
@@ -287,7 +287,7 @@ public final class FlatBufferBuilder {
/// - Parameter elements: Elements to be written into the buffer
/// - Parameter size: Count of elements
/// - returns: Offset of the vector
public func createVector<T: Scalar>(_ elements: [T], size: Int) -> Offset<UOffset> {
mutating public func createVector<T: Scalar>(_ elements: [T], size: Int) -> Offset<UOffset> {
let size = size
startVector(size, elementSize: MemoryLayout<T>.size)
_bb.push(elements: elements)
@@ -297,7 +297,7 @@ public final class FlatBufferBuilder {
/// Creates a vector of type Enums in the buffer
/// - Parameter elements: elements to be written into the buffer
/// - returns: Offset of the vector
public func createVector<T: Enum>(_ elements: [T]) -> Offset<UOffset> {
mutating public func createVector<T: Enum>(_ elements: [T]) -> Offset<UOffset> {
return createVector(elements, size: elements.count)
}
@@ -305,7 +305,7 @@ public final class FlatBufferBuilder {
/// - Parameter elements: Elements to be written into the buffer
/// - Parameter size: Count of elements
/// - returns: Offset of the vector
public func createVector<T: Enum>(_ elements: [T], size: Int) -> Offset<UOffset> {
mutating public func createVector<T: Enum>(_ elements: [T], size: Int) -> Offset<UOffset> {
let size = size
startVector(size, elementSize: T.byteSize)
for e in elements.lazy.reversed() {
@@ -317,7 +317,7 @@ public final class FlatBufferBuilder {
/// Creates a vector of type Offsets in the buffer
/// - Parameter offsets:Array of offsets of type T
/// - returns: Offset of the vector
public func createVector<T>(ofOffsets offsets: [Offset<T>]) -> Offset<UOffset> {
mutating public func createVector<T>(ofOffsets offsets: [Offset<T>]) -> Offset<UOffset> {
createVector(ofOffsets: offsets, len: offsets.count)
}
@@ -325,7 +325,7 @@ public final class FlatBufferBuilder {
/// - Parameter elements: Array of offsets of type T
/// - Parameter size: Count of elements
/// - returns: Offset of the vector
public func createVector<T>(ofOffsets offsets: [Offset<T>], len: Int) -> Offset<UOffset> {
mutating public func createVector<T>(ofOffsets offsets: [Offset<T>], len: Int) -> Offset<UOffset> {
startVector(len, elementSize: MemoryLayout<Offset<T>>.size)
for o in offsets.lazy.reversed() {
push(element: o)
@@ -336,7 +336,7 @@ public final class FlatBufferBuilder {
/// Creates a vector of Strings
/// - Parameter str: a vector of strings that will be written into the buffer
/// - returns: Offset of the vector
public func createVector(ofStrings str: [String]) -> Offset<UOffset> {
mutating public func createVector(ofStrings str: [String]) -> Offset<UOffset> {
var offsets: [Offset<String>] = []
for s in str {
offsets.append(create(string: s))
@@ -351,7 +351,7 @@ public final class FlatBufferBuilder {
/// - structs: An array of UnsafeMutableRawPointer
/// - type: Type of the struct being written
/// - returns: Offset of the vector
public func createVector<T: Readable>(structs: [UnsafeMutableRawPointer],
mutating public func createVector<T: Readable>(structs: [UnsafeMutableRawPointer],
type: T.Type) -> Offset<UOffset> {
startVector(structs.count * T.size, elementSize: T.alignment)
for i in structs.lazy.reversed() {
@@ -368,7 +368,7 @@ public final class FlatBufferBuilder {
/// - type: Type of the element to be serialized
/// - returns: Offset of the Object
@discardableResult
public func create<T: Readable>(struct s: UnsafeMutableRawPointer,
mutating public func create<T: Readable>(struct s: UnsafeMutableRawPointer,
type: T.Type) -> Offset<UOffset> {
let size = T.size
preAlign(len: size, alignment: T.alignment)
@@ -380,7 +380,7 @@ public final class FlatBufferBuilder {
///
/// The function fatalErrors if we pass an offset that is out of range
/// - Parameter o: offset
public func add(structOffset o: UOffset) {
mutating public func add(structOffset o: UOffset) {
guard Int(o) < _vtable.count else { fatalError("Out of the table range") }
_vtable[Int(o)] = _bb.size
}
@@ -390,7 +390,7 @@ public final class FlatBufferBuilder {
/// Insets a string into the buffer using UTF8
/// - Parameter str: String to be serialized
/// - returns: The strings offset in the buffer
public func create(string str: String) -> Offset<String> {
mutating public func create(string str: String) -> Offset<String> {
let len = str.count
notNested()
preAlign(len: len + 1, type: UOffset.self)
@@ -405,7 +405,7 @@ public final class FlatBufferBuilder {
/// The function checks the stringOffsetmap if it's seen a similar string before
/// - Parameter str: String to be serialized
/// - returns: The strings offset in the buffer
public func createShared(string str: String) -> Offset<String> {
mutating public func createShared(string str: String) -> Offset<String> {
if let offset = stringOffsetMap[str] {
return offset
}
@@ -420,7 +420,7 @@ public final class FlatBufferBuilder {
/// - Parameters:
/// - offset: Offset of another object to be written
/// - position: The predefined position of the object
public func add<T>(offset: Offset<T>, at position: VOffset) {
mutating public func add<T>(offset: Offset<T>, at position: VOffset) {
if offset.isEmpty {
track(offset: 0, at: position)
return
@@ -432,7 +432,7 @@ public final class FlatBufferBuilder {
/// - Parameter o: Offset
/// - returns: Position of the offset
@discardableResult
public func push<T>(element o: Offset<T>) -> UOffset {
mutating public func push<T>(element o: Offset<T>) -> UOffset {
push(element: refer(to: o.o))
}
@@ -444,7 +444,7 @@ public final class FlatBufferBuilder {
/// - element: Element to insert
/// - def: Default value for that element
/// - position: The predefined position of the element
public func add<T: Scalar>(element: T, def: T, at position: VOffset) {
mutating public func add<T: Scalar>(element: T, def: T, at position: VOffset) {
if (element == def && !serializeDefaults) {
track(offset: 0, at: position)
return
@@ -458,7 +458,7 @@ public final class FlatBufferBuilder {
/// - condition: Condition to insert
/// - def: Default condition
/// - position: The predefined position of the element
public func add(condition: Bool, def: Bool, at position: VOffset) {
mutating public func add(condition: Bool, def: Bool, at position: VOffset) {
if (condition == def && !serializeDefaults) {
track(offset: 0, at: position)
return
@@ -471,12 +471,13 @@ public final class FlatBufferBuilder {
/// - Parameter element: Element to insert
/// - returns: Postion of the Element
@discardableResult
public func push<T: Scalar>(element: T) -> UOffset {
mutating public func push<T: Scalar>(element: T) -> UOffset {
preAlign(len: MemoryLayout<T>.size,
alignment: MemoryLayout<T>.size)
_bb.push(value: element, len: MemoryLayout<T>.size)
return _bb.size
}
}
extension FlatBufferBuilder: CustomDebugStringConvertible {