forked from BigfootDev/flatbuffers
Improves performance for the swift library by using structs + a storage class (#5835)
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user