diff --git a/benchmarks/swift/Benchmarks/FlatbuffersBenchmarks/FlatbuffersBenchmarks.swift b/benchmarks/swift/Benchmarks/FlatbuffersBenchmarks/FlatbuffersBenchmarks.swift index 4607f58094..aa085686fb 100644 --- a/benchmarks/swift/Benchmarks/FlatbuffersBenchmarks/FlatbuffersBenchmarks.swift +++ b/benchmarks/swift/Benchmarks/FlatbuffersBenchmarks/FlatbuffersBenchmarks.swift @@ -97,6 +97,7 @@ let benchmarks = { for _ in benchmark.scaledIterations { blackHole(ByteBuffer(assumingMemoryBound: memory, capacity: Int(oneGB))) } + benchmark.stopMeasurement() } Benchmark("Clearing 1GB", configuration: singleConfiguration) { benchmark in @@ -105,6 +106,7 @@ let benchmarks = { for _ in benchmark.scaledIterations { blackHole(fb.clear()) } + benchmark.stopMeasurement() } Benchmark("Strings 10") { benchmark in @@ -113,6 +115,7 @@ let benchmarks = { for _ in benchmark.scaledIterations { blackHole(fb.create(string: str10)) } + benchmark.stopMeasurement() } Benchmark("Strings 100") { benchmark in @@ -121,6 +124,7 @@ let benchmarks = { for _ in benchmark.scaledIterations { blackHole(fb.create(string: str100)) } + benchmark.stopMeasurement() } Benchmark("Vector 1 Bytes") { benchmark in @@ -129,6 +133,7 @@ let benchmarks = { for _ in benchmark.scaledIterations { blackHole(fb.createVector(bytes: bytes)) } + benchmark.stopMeasurement() } Benchmark("Vector 1 Ints") { benchmark in @@ -137,6 +142,7 @@ let benchmarks = { for _ in benchmark.scaledIterations { blackHole(fb.createVector(ints)) } + benchmark.stopMeasurement() } Benchmark("Vector 100 Ints") { benchmark in @@ -145,6 +151,7 @@ let benchmarks = { for i in benchmark.scaledIterations { blackHole(fb.createVector(ints)) } + benchmark.stopMeasurement() } Benchmark("Vector 100 Bytes") { benchmark in @@ -153,6 +160,7 @@ let benchmarks = { for i in benchmark.scaledIterations { blackHole(fb.createVector(bytes)) } + benchmark.stopMeasurement() } Benchmark("Vector 100 ContiguousBytes") { benchmark in @@ -161,6 +169,7 @@ let benchmarks = { for i in benchmark.scaledIterations { blackHole(fb.createVector(bytes: bytes)) } + benchmark.stopMeasurement() } Benchmark( @@ -178,6 +187,7 @@ let benchmarks = { fb.add(offset: off, at: 8) blackHole(fb.endTable(at: s)) } + benchmark.stopMeasurement() } Benchmark( @@ -190,6 +200,7 @@ let benchmarks = { let s = fb.startTable(with: 4) blackHole(fb.endTable(at: s)) } + benchmark.stopMeasurement() } Benchmark("Struct") { benchmark in @@ -198,6 +209,7 @@ let benchmarks = { for _ in benchmark.scaledIterations { blackHole(fb.create(struct: array.first!)) } + benchmark.stopMeasurement() } Benchmark("Structs") { benchmark in @@ -219,6 +231,7 @@ let benchmarks = { fb.add(offset: vector, at: 4) let root = Offset(offset: fb.endTable(at: start)) blackHole(fb.finish(offset: root)) + benchmark.stopMeasurement() } Benchmark("Vector of Offsets") { benchmark in @@ -239,12 +252,15 @@ let benchmarks = { fb.add(offset: off, at: 2) blackHole(fb.endTable(at: s)) } + benchmark.stopMeasurement() } Benchmark("Reading Doubles") { benchmark in let byteBuffer = ByteBuffer(data: data) + benchmark.startMeasurement() for _ in benchmark.scaledIterations { blackHole(byteBuffer.read(def: Double.self, position: 0)) } + benchmark.stopMeasurement() } } diff --git a/swift/Sources/Common/Scalar.swift b/swift/Sources/Common/Scalar.swift index 518580a605..ae573d235b 100644 --- a/swift/Sources/Common/Scalar.swift +++ b/swift/Sources/Common/Scalar.swift @@ -28,10 +28,17 @@ public let FileIdLength = 4 /// Protocol that All Scalars should conform to /// /// Scalar is used to conform all the numbers that can be represented in a FlatBuffer. It's used to write/read from the buffer. +#if compiler(>=6.0) +public protocol Scalar: Equatable, BitwiseCopyable { + associatedtype NumericValue + var convertedEndian: NumericValue { get } +} +#else public protocol Scalar: Equatable { associatedtype NumericValue var convertedEndian: NumericValue { get } } +#endif extension Scalar where Self: FixedWidthInteger { /// Converts the value from BigEndian to LittleEndian diff --git a/swift/Sources/FlatBuffers/ByteBuffer.swift b/swift/Sources/FlatBuffers/ByteBuffer.swift index ec27fd1d73..ed5213a6ef 100644 --- a/swift/Sources/FlatBuffers/ByteBuffer.swift +++ b/swift/Sources/FlatBuffers/ByteBuffer.swift @@ -26,8 +26,9 @@ public struct ByteBuffer { /// deallocating the memory that was held by (memory: UnsafeMutableRawPointer) @usableFromInline final class Storage { + #if compiler(>=6.0) @usableFromInline - enum Blob { + @frozen enum Blob: ~Copyable { #if !os(WASI) case data(Data) case bytes(ContiguousBytes) @@ -36,7 +37,65 @@ public struct ByteBuffer { case byteBuffer(_InternalByteBuffer) case array([UInt8]) case pointer(UnsafeMutableRawPointer) + + init(_ other: borrowing Blob) { + switch other { + case .data(let data): + self = .data(data) + case .bytes(let contiguousBytes): + self = .bytes(contiguousBytes) + case .byteBuffer(let internalByteBuffer): + self = .byteBuffer(internalByteBuffer) + case .array(let array): + self = .array(array) + case .pointer(let unsafeMutableRawPointer): + self = .pointer(unsafeMutableRawPointer) + } + } + + var description: String { + switch self { + case .data(let data): + "data: \(data)" + case .bytes(let contiguousBytes): + "bytes: \(contiguousBytes)" + case .byteBuffer(let internalByteBuffer): + "byteBuffer: \(internalByteBuffer)" + case .array(let array): + "array: \(array)" + case .pointer(let unsafeMutableRawPointer): + "pointer: \(unsafeMutableRawPointer)" + } + } + } + #else + @usableFromInline + @frozen enum Blob { + #if !os(WASI) + case data(Data) + case bytes(ContiguousBytes) + #endif + + case byteBuffer(_InternalByteBuffer) + case array([UInt8]) + case pointer(UnsafeMutableRawPointer) + + var description: String { + switch self { + case .data(let data): + return "data: \(data)" + case .bytes(let contiguousBytes): + return "bytes: \(contiguousBytes)" + case .byteBuffer(let internalByteBuffer): + return "byteBuffer: \(internalByteBuffer)" + case .array(let array): + return "array: \(array)" + case .pointer(let unsafeMutableRawPointer): + return "pointer: \(unsafeMutableRawPointer)" + } + } } + #endif /// This storage doesn't own the memory, therefore, we won't deallocate on deinit. private let isOwned: Bool @@ -44,7 +103,7 @@ public struct ByteBuffer { private let capacity: Int /// Retained blob of data that requires the storage to retain a pointer to. @usableFromInline - var retainedBlob: Blob + let retainedBlob: Blob @usableFromInline init(count: Int) { @@ -56,12 +115,21 @@ public struct ByteBuffer { isOwned = true } + #if compiler(>=6.0) + @usableFromInline + init(blob: borrowing Blob, capacity count: Int) { + capacity = count + retainedBlob = .init(blob) + isOwned = false + } + #else @usableFromInline init(blob: Blob, capacity count: Int) { capacity = count retainedBlob = blob isOwned = false } + #endif deinit { guard isOwned else { return } @@ -150,6 +218,7 @@ public struct ByteBuffer { @discardableResult @inline(__always) + @inlinable func readWithUnsafeRawPointer( position: Int, _ body: (UnsafeRawPointer) throws -> T) rethrows -> T @@ -276,6 +345,18 @@ public struct ByteBuffer { /// - memory: Current memory of the buffer /// - count: count of bytes /// - removeBytes: Removes a number of bytes from the current size + #if compiler(>=6.0) + @inline(__always) + init( + blob: borrowing Storage.Blob, + count: Int, + removing removeBytes: Int) + { + _storage = Storage(blob: blob, capacity: count) + _readerIndex = removeBytes + capacity = count + } + #else @inline(__always) init( blob: Storage.Blob, @@ -286,6 +367,7 @@ public struct ByteBuffer { _readerIndex = removeBytes capacity = count } + #endif /// Write stores an object into the buffer directly or indirectly. /// @@ -317,13 +399,25 @@ public struct ByteBuffer { /// - Parameters: /// - def: Type of the object /// - position: the index of the object in the buffer + #if compiler(>=6.0) + @inline(__always) + @inlinable + public func read(def: T.Type, position: Int) -> T { + _storage.readWithUnsafeRawPointer(position: position) { + $0.bindMemory(to: T.self, capacity: 1) + .pointee + } + } + #else @inline(__always) + @inlinable public func read(def: T.Type, position: Int) -> T { _storage.readWithUnsafeRawPointer(position: position) { $0.bindMemory(to: T.self, capacity: 1) .pointee } } + #endif /// Reads a slice from the memory assuming a type of T /// - Parameters: @@ -412,7 +506,7 @@ public struct ByteBuffer { /// - Parameter removeBytes: the amount of bytes to remove from the current Size @inline(__always) public func duplicate(removing removeBytes: Int = 0) -> ByteBuffer { - assert(removeBytes > 0, "Can NOT remove negative bytes") + assert(removeBytes >= 0, "Can NOT remove negative bytes") assert( removeBytes < capacity, "Can NOT remove more bytes than the ones allocated") @@ -464,8 +558,9 @@ public struct ByteBuffer { extension ByteBuffer: CustomDebugStringConvertible { public var debugDescription: String { - """ - buffer located at: \(_storage.retainedBlob), + let blobDescription = _storage.retainedBlob.description + return """ + buffer located at: \(blobDescription), with capacity of \(capacity), { writtenSize: \(_readerIndex), readerSize: \(reader), size: \(size) } diff --git a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift index 9e778d225c..d2c4c99fc2 100644 --- a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift +++ b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift @@ -47,7 +47,8 @@ public struct FlatBufferBuilder { /// A check to see if finish(::) was ever called to retreive data object private var finished = false /// A check to see if the buffer should serialize Default values - private var serializeDefaults: Bool + @usableFromInline + var serializeDefaults: Bool /// Current alignment for the buffer var _minAlignment: Int = 0 { @@ -756,6 +757,7 @@ public struct FlatBufferBuilder { /// - offset: ``Offset`` of another object to be written /// - position: The predefined position of the object @inline(__always) + @inlinable mutating public func add(offset: Offset, at position: VOffset) { if offset.isEmpty { return } add(element: refer(to: offset.o), def: 0, at: position) @@ -794,6 +796,7 @@ public struct FlatBufferBuilder { /// - def: Default value for that element /// - position: The predefined position of the element @inline(__always) + @inlinable mutating public func add( element: T, def: T, @@ -813,6 +816,7 @@ public struct FlatBufferBuilder { /// - element: Optional element of type scalar /// - position: The predefined position of the element @inline(__always) + @inlinable mutating public func add(element: T?, at position: VOffset) { guard let element = element else { return } track(offset: push(element: element), at: position) @@ -825,6 +829,7 @@ public struct FlatBufferBuilder { /// - Parameter element: Element to insert /// - returns: position of the Element @inline(__always) + @inlinable @discardableResult mutating public func push(element: T) -> UOffset { let size = MemoryLayout.size @@ -835,10 +840,19 @@ public struct FlatBufferBuilder { return _bb.size } + #if compiler(>=6.0) @inline(__always) + @inlinable + public func read(def: T.Type, position: Int) -> T { + _bb.read(def: def, position: position) + } + #else + @inline(__always) + @inlinable public func read(def: T.Type, position: Int) -> T { _bb.read(def: def, position: position) } + #endif } extension FlatBufferBuilder: CustomDebugStringConvertible { diff --git a/swift/Sources/FlatBuffers/FlatBufferObject.swift b/swift/Sources/FlatBuffers/FlatBufferObject.swift index 0b9f01b070..612d89d645 100644 --- a/swift/Sources/FlatBuffers/FlatBufferObject.swift +++ b/swift/Sources/FlatBuffers/FlatBufferObject.swift @@ -18,7 +18,11 @@ import Foundation /// NativeStruct is a protocol that indicates if the struct is a native `swift` struct /// since now we will be serializing native structs into the buffer. +#if compiler(>=6.0) +public protocol NativeStruct: BitwiseCopyable {} +#else public protocol NativeStruct {} +#endif /// FlatbuffersInitializable is a protocol that allows any object to be /// Initialized from a ByteBuffer diff --git a/swift/Sources/FlatBuffers/Table.swift b/swift/Sources/FlatBuffers/Table.swift index f29a51e5b3..c0f0a2e68a 100644 --- a/swift/Sources/FlatBuffers/Table.swift +++ b/swift/Sources/FlatBuffers/Table.swift @@ -82,9 +82,15 @@ public struct Table { /// - Parameters: /// - type: Type of Element that needs to be read from the buffer /// - o: Offset of the Element + #if compiler(>=6.0) + public func readBuffer(of type: T.Type, at o: Int32) -> T { + bb.read(def: T.self, position: Int(o &+ position)) + } + #else public func readBuffer(of type: T.Type, at o: Int32) -> T { bb.read(def: T.self, position: Int(o &+ position)) } + #endif /// Returns that current `Union` object at a specific offset /// by adding offset to the current position of table diff --git a/swift/Sources/FlatBuffers/Verifier.swift b/swift/Sources/FlatBuffers/Verifier.swift index b0ef3968d0..a7dbffb5ae 100644 --- a/swift/Sources/FlatBuffers/Verifier.swift +++ b/swift/Sources/FlatBuffers/Verifier.swift @@ -163,10 +163,17 @@ public struct Verifier { /// - Parameter position: Current position to be read /// - Throws: `inBuffer` errors /// - Returns: a value of type `T` usually a `VTable` or a table offset + #if compiler(>=6.0) + internal func getValue(at position: Int) throws -> T { + try inBuffer(position: position, of: T.self) + return _buffer.read(def: T.self, position: position) + } + #else internal func getValue(at position: Int) throws -> T { try inBuffer(position: position, of: T.self) return _buffer.read(def: T.self, position: position) } + #endif /// derefrences an offset within a vtable to get the position of the field /// in the bytebuffer diff --git a/swift/Sources/FlatBuffers/_InternalByteBuffer.swift b/swift/Sources/FlatBuffers/_InternalByteBuffer.swift index 8dced85b41..a92fa8847b 100644 --- a/swift/Sources/FlatBuffers/_InternalByteBuffer.swift +++ b/swift/Sources/FlatBuffers/_InternalByteBuffer.swift @@ -30,7 +30,7 @@ struct _InternalByteBuffer { @usableFromInline final class Storage { /// pointer to the start of the buffer object in memory - private(set) var memory: UnsafeMutableRawPointer + @exclusivity(unchecked) private(set) var memory: UnsafeMutableRawPointer @usableFromInline init(count: Int, alignment: Int) { @@ -333,6 +333,7 @@ struct _InternalByteBuffer { @discardableResult @inline(__always) + @usableFromInline func readWithUnsafeRawPointer( position: Int, _ body: (UnsafeRawPointer) throws -> T) rethrows -> T