diff --git a/benchmarks/swift/Benchmarks/FlatbuffersBenchmarks/FlatbuffersBenchmarks.swift b/benchmarks/swift/Benchmarks/FlatbuffersBenchmarks/FlatbuffersBenchmarks.swift index 263e006bef3..21eff5fac5f 100644 --- a/benchmarks/swift/Benchmarks/FlatbuffersBenchmarks/FlatbuffersBenchmarks.swift +++ b/benchmarks/swift/Benchmarks/FlatbuffersBenchmarks/FlatbuffersBenchmarks.swift @@ -178,4 +178,24 @@ let benchmarks = { let root = Offset(offset: fb.endTable(at: start)) fb.finish(offset: root) } + + Benchmark("Vector of Offsets") { benchmark in + let rawSize = ((16 * 5) * benchmark.scaledIterations.count) / 1024 + var fb = FlatBufferBuilder(initialSize: Int32(rawSize * 1600)) + benchmark.startMeasurement() + for _ in benchmark.scaledIterations { + let offsets = [ + fb.create(string: "T"), + fb.create(string: "2"), + fb.create(string: "3"), + ] + let off = fb.createVector(ofOffsets: [ + fb.createVector(ofOffsets: offsets), + fb.createVector(ofOffsets: offsets), + ]) + let s = fb.startTable(with: 2) + fb.add(offset: off, at: 2) + blackHole(fb.endTable(at: s)) + } + } } diff --git a/benchmarks/swift/Package.swift b/benchmarks/swift/Package.swift index 4204c48131b..1a1dd09eeec 100644 --- a/benchmarks/swift/Package.swift +++ b/benchmarks/swift/Package.swift @@ -26,7 +26,7 @@ let package = Package( .package(path: "../.."), .package( url: "https://github.com/ordo-one/package-benchmark", - from: "1.12.0"), + from: "1.27.0"), ], targets: [ .executableTarget( diff --git a/swift/Sources/FlatBuffers/ByteBuffer.swift b/swift/Sources/FlatBuffers/ByteBuffer.swift index 5debd01e99f..9442c855a6c 100644 --- a/swift/Sources/FlatBuffers/ByteBuffer.swift +++ b/swift/Sources/FlatBuffers/ByteBuffer.swift @@ -251,7 +251,7 @@ public struct ByteBuffer { ensureSpace(size: ptr.count) memcpy( _storage.memory.advanced(by: writerIndex &- ptr.count), - UnsafeRawPointer(ptr.baseAddress!), + ptr.baseAddress!, ptr.count) _writerSize = _writerSize &+ ptr.count } @@ -264,9 +264,10 @@ public struct ByteBuffer { mutating func push(elements: [T]) { elements.withUnsafeBytes { ptr in ensureSpace(size: ptr.count) - _storage.memory - .advanced(by: writerIndex &- ptr.count) - .copyMemory(from: ptr.baseAddress!, byteCount: ptr.count) + memcpy( + _storage.memory.advanced(by: writerIndex &- ptr.count), + ptr.baseAddress!, + ptr.count) _writerSize = _writerSize &+ ptr.count } } @@ -281,7 +282,7 @@ public struct ByteBuffer { ensureSpace(size: ptr.count) memcpy( _storage.memory.advanced(by: writerIndex &- ptr.count), - UnsafeRawPointer(ptr.baseAddress!), + ptr.baseAddress!, ptr.count) _writerSize = _writerSize &+ ptr.count } @@ -296,11 +297,10 @@ public struct ByteBuffer { @inline(__always) mutating func push(struct value: T, size: Int) { ensureSpace(size: size) - var v = value - withUnsafeBytes(of: &v) { + withUnsafePointer(to: value) { memcpy( _storage.memory.advanced(by: writerIndex &- size), - $0.baseAddress!, + $0, size) _writerSize = _writerSize &+ size } @@ -314,11 +314,10 @@ public struct ByteBuffer { @usableFromInline mutating func push(value: T, len: Int) { ensureSpace(size: len) - var v = value - withUnsafeBytes(of: &v) { + withUnsafePointer(to: value) { memcpy( _storage.memory.advanced(by: writerIndex &- len), - $0.baseAddress!, + $0, len) _writerSize = _writerSize &+ len } @@ -355,7 +354,7 @@ public struct ByteBuffer { { memcpy( _storage.memory.advanced(by: writerIndex &- len), - UnsafeRawPointer(bytes.baseAddress!), + bytes.baseAddress!, len) _writerSize = _writerSize &+ len return true @@ -377,7 +376,12 @@ public struct ByteBuffer { } assert(index < _storage.capacity, "Write index is out of writing bound") assert(index >= 0, "Writer index should be above zero") - _storage.memory.storeBytes(of: value, toByteOffset: index, as: T.self) + withUnsafePointer(to: value) { + memcpy( + _storage.memory.advanced(by: index), + $0, + MemoryLayout.size) + } } /// Makes sure that buffer has enouch space for each of the objects that will be written into it diff --git a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift index e31b10cca4e..26ae6349154 100644 --- a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift +++ b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift @@ -146,12 +146,12 @@ public struct FlatBufferBuilder { /// by the generated code* @inline(__always) mutating public func require(table: Offset, fields: [Int32]) { - for field in fields { + for index in stride(from: 0, to: fields.count, by: 1) { let start = _bb.capacity &- Int(table.o) let startTable = start &- Int(_bb.read(def: Int32.self, position: start)) let isOkay = _bb.read( def: VOffset.self, - position: startTable &+ Int(field)) != 0 + position: startTable &+ Int(fields[index])) != 0 assert(isOkay, "Flatbuffers requires the following field") } } @@ -285,13 +285,13 @@ public struct FlatBufferBuilder { let vt2 = _bb.memory.advanced(by: _bb.writerIndex) let len2 = vt2.load(fromByteOffset: 0, as: Int16.self) - for table in _vtables { - let position = _bb.capacity &- Int(table) + for index in stride(from: 0, to: _vtables.count, by: 1) { + let position = _bb.capacity &- Int(_vtables[index]) let vt1 = _bb.memory.advanced(by: position) let len1 = _bb.read(def: Int16.self, position: position) if len2 != len1 || 0 != memcmp(vt1, vt2, Int(len2)) { continue } - isAlreadyAdded = Int(table) + isAlreadyAdded = Int(_vtables[index]) break } @@ -380,7 +380,7 @@ public struct FlatBufferBuilder { @inline(__always) @usableFromInline mutating internal func track(offset: UOffset, at position: VOffset) { - _vtableStorage.add(loc: FieldLoc(offset: offset, position: position)) + _vtableStorage.add(loc: (offset: offset, position: position)) } // MARK: - Inserting Vectors @@ -524,8 +524,8 @@ public struct FlatBufferBuilder { { let size = size startVector(size, elementSize: T.byteSize) - for e in elements.reversed() { - _bb.push(value: e.value, len: T.byteSize) + for index in stride(from: elements.count, to: 0, by: -1) { + _bb.push(value: elements[index &- 1].value, len: T.byteSize) } return endVector(len: size) } @@ -569,8 +569,8 @@ public struct FlatBufferBuilder { len: Int) -> Offset { startVector(len, elementSize: MemoryLayout.size) - for o in offsets.reversed() { - push(element: o) + for index in stride(from: offsets.count, to: 0, by: -1) { + push(element: offsets[index &- 1]) } return endVector(len: len) } @@ -593,8 +593,8 @@ public struct FlatBufferBuilder { @inline(__always) mutating public func createVector(ofStrings str: [String]) -> Offset { var offsets: [Offset] = [] - for s in str { - offsets.append(create(string: s)) + for index in stride(from: 0, to: str.count, by: 1) { + offsets.append(create(string: str[index])) } return createVector(ofOffsets: offsets) } @@ -646,9 +646,8 @@ public struct FlatBufferBuilder { struct s: T, position: VOffset) -> Offset { let offset = create(struct: s) - _vtableStorage.add(loc: FieldLoc( - offset: _bb.size, - position: VOffset(position))) + _vtableStorage.add( + loc: (offset: _bb.size, position: VOffset(position))) return offset } @@ -837,6 +836,8 @@ extension FlatBufferBuilder: CustomDebugStringConvertible { """ } + typealias FieldLoc = (offset: UOffset, position: VOffset) + /// VTableStorage is a class to contain the VTable buffer that would be serialized into buffer @usableFromInline internal class VTableStorage { @@ -920,12 +921,5 @@ extension FlatBufferBuilder: CustomDebugStringConvertible { func load(at index: Int) -> FieldLoc { memory.load(fromByteOffset: index, as: FieldLoc.self) } - } - - internal struct FieldLoc { - var offset: UOffset - var position: VOffset - } - }