diff --git a/benchmarks/swift/Benchmarks/FlatbuffersBenchmarks/FlatbuffersBenchmarks.swift b/benchmarks/swift/Benchmarks/FlatbuffersBenchmarks/FlatbuffersBenchmarks.swift index 21eff5fac..28b4711b7 100644 --- a/benchmarks/swift/Benchmarks/FlatbuffersBenchmarks/FlatbuffersBenchmarks.swift +++ b/benchmarks/swift/Benchmarks/FlatbuffersBenchmarks/FlatbuffersBenchmarks.swift @@ -15,8 +15,8 @@ */ import Benchmark -import CoreFoundation import FlatBuffers +import Foundation @usableFromInline struct AA: NativeStruct { @@ -29,6 +29,15 @@ struct AA: NativeStruct { } let benchmarks = { + let oneGB: Int32 = 1_024_000_000 + let data = { + var array = [8888.88, 8888.88] + var data = Data() + array.withUnsafeBytes { ptr in + data.append(contentsOf: ptr) + } + return data + }() let ints: [Int] = Array(repeating: 42, count: 100) let bytes: [UInt8] = Array(repeating: 42, count: 100) let str10 = (0...9).map { _ -> String in "x" }.joined() @@ -73,12 +82,25 @@ let benchmarks = { Benchmark("Allocating 1GB", configuration: singleConfiguration) { benchmark in for _ in benchmark.scaledIterations { - blackHole(FlatBufferBuilder(initialSize: 1_024_000_000)) + blackHole(FlatBufferBuilder(initialSize: oneGB)) + } + } + + Benchmark( + "Allocating ByteBuffer 1GB", + configuration: singleConfiguration) + { benchmark in + let memory = UnsafeMutableRawPointer.allocate( + byteCount: 1_024_000_000, + alignment: 1) + benchmark.startMeasurement() + for _ in benchmark.scaledIterations { + blackHole(ByteBuffer(assumingMemoryBound: memory, capacity: Int(oneGB))) } } Benchmark("Clearing 1GB", configuration: singleConfiguration) { benchmark in - var fb = FlatBufferBuilder(initialSize: 1_024_000_000) + var fb = FlatBufferBuilder(initialSize: oneGB) benchmark.startMeasurement() for _ in benchmark.scaledIterations { blackHole(fb.clear()) @@ -158,6 +180,26 @@ let benchmarks = { } } + Benchmark( + "FlatBufferBuilder Start table", + configuration: kiloConfiguration) + { benchmark in + var fb = FlatBufferBuilder(initialSize: 1024 * 1024 * 32) + benchmark.startMeasurement() + for _ in benchmark.scaledIterations { + let s = fb.startTable(with: 4) + blackHole(fb.endTable(at: s)) + } + } + + Benchmark("Struct") { benchmark in + var fb = FlatBufferBuilder(initialSize: 1024 * 1024 * 32) + benchmark.startMeasurement() + for _ in benchmark.scaledIterations { + blackHole(fb.create(struct: array.first!)) + } + } + Benchmark("Structs") { benchmark in let rawSize = ((16 * 5) * benchmark.scaledIterations.count) / 1024 var fb = FlatBufferBuilder(initialSize: Int32(rawSize * 1600)) @@ -176,7 +218,7 @@ let benchmarks = { let start = fb.startTable(with: 1) fb.add(offset: vector, at: 4) let root = Offset(offset: fb.endTable(at: start)) - fb.finish(offset: root) + blackHole(fb.finish(offset: root)) } Benchmark("Vector of Offsets") { benchmark in @@ -198,4 +240,11 @@ let benchmarks = { blackHole(fb.endTable(at: s)) } } + + Benchmark("Reading Doubles") { benchmark in + let byteBuffer = ByteBuffer(data: data) + for _ in benchmark.scaledIterations { + blackHole(byteBuffer.read(def: Double.self, position: 0)) + } + } } diff --git a/docs/source/languages/swift.md b/docs/source/languages/swift.md index b967c54d1..78046c0d4 100644 --- a/docs/source/languages/swift.md +++ b/docs/source/languages/swift.md @@ -57,7 +57,7 @@ a data object from the server, which you can pass into the `GetRootAsMonster` fu let url = URL(fileURLWithPath: path, isDirectory: true).appendingPathComponent("monsterdata_test").appendingPathExtension("mon") guard let data = try? Data(contentsOf: url) else { return } - let monster = Monster.getRootAsMonster(bb: ByteBuffer(data: data)) + let monster: Monster = try! getCheckedRoot(byteBuffer: &byteBuffer) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Now you can access values like this: diff --git a/docs/source/tutorial.md b/docs/source/tutorial.md index cfa0b1c99..e43e1367c 100644 --- a/docs/source/tutorial.md +++ b/docs/source/tutorial.md @@ -2011,6 +2011,8 @@ like so: let buf = builder.sizedByteArray // or you can use to get an object of type Data let bufData = ByteBuffer(data: builder.data) + // or + let buf = builder.sizedBuffer ``` === "TypeScript" diff --git a/grpc/examples/swift/Greeter/Sources/Model/greeter.grpc.swift b/grpc/examples/swift/Greeter/Sources/Model/greeter.grpc.swift index 0f29f1958..0a7867b9f 100644 --- a/grpc/examples/swift/Greeter/Sources/Model/greeter.grpc.swift +++ b/grpc/examples/swift/Greeter/Sources/Model/greeter.grpc.swift @@ -17,8 +17,7 @@ public extension GRPCFlatBufPayload { self.init(byteBuffer: FlatBuffers.ByteBuffer(contiguousBytes: serializedByteBuffer.readableBytesView, count: serializedByteBuffer.readableBytes)) } func serialize(into buffer: inout NIO.ByteBuffer) throws { - let buf = UnsafeRawBufferPointer(start: self.rawPointer, count: Int(self.size)) - buffer.writeBytes(buf) + withUnsafeReadableBytes { buffer.writeBytes($0) } } } extension Message: GRPCFlatBufPayload {} diff --git a/grpc/src/compiler/swift_generator.cc b/grpc/src/compiler/swift_generator.cc index b0a96d869..935a8a39a 100644 --- a/grpc/src/compiler/swift_generator.cc +++ b/grpc/src/compiler/swift_generator.cc @@ -428,10 +428,7 @@ grpc::string GenerateHeader() { code += " }\n"; code += " func serialize(into buffer: inout NIO.ByteBuffer) throws {\n"; - code += - " let buf = UnsafeRawBufferPointer(start: self.rawPointer, count: " - "Int(self.size))\n"; - code += " buffer.writeBytes(buf)\n"; + code += " withUnsafeReadableBytes { buffer.writeBytes($0) }\n"; code += " }\n"; code += "}\n"; code += "extension Message: GRPCFlatBufPayload {}\n"; diff --git a/samples/monster_generated.swift b/samples/monster_generated.swift index 527560ae2..53ecd8e3c 100644 --- a/samples/monster_generated.swift +++ b/samples/monster_generated.swift @@ -16,6 +16,16 @@ public enum MyGame_Sample_Color: Int8, Enum, Verifiable { public static var min: MyGame_Sample_Color { return .red } } +extension MyGame_Sample_Color: Encodable { + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + switch self { + case .red: try container.encode("Red") + case .green: try container.encode("Green") + case .blue: try container.encode("Blue") + } + } +} public enum MyGame_Sample_Equipment: UInt8, UnionEnum { public typealias T = UInt8 @@ -33,8 +43,33 @@ public enum MyGame_Sample_Equipment: UInt8, UnionEnum { public static var min: MyGame_Sample_Equipment { return .none_ } } +extension MyGame_Sample_Equipment: Encodable { + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + switch self { + case .none_: try container.encode("NONE") + case .weapon: try container.encode("Weapon") + } + } +} -public struct MyGame_Sample_Vec3: NativeStruct, Verifiable, FlatbuffersInitializable { +public struct MyGame_Sample_EquipmentUnion { + public var type: MyGame_Sample_Equipment + public var value: NativeObject? + public init(_ v: NativeObject?, type: MyGame_Sample_Equipment) { + self.type = type + self.value = v + } + public func pack(builder: inout FlatBufferBuilder) -> Offset { + switch type { + case .weapon: + var __obj = value as? MyGame_Sample_WeaponT + return MyGame_Sample_Weapon.pack(&builder, obj: &__obj) + default: return Offset() + } + } +} +public struct MyGame_Sample_Vec3: NativeStruct, Verifiable, FlatbuffersInitializable, NativeObject { static func validateVersion() { FlatBuffersVersion_25_2_10() } @@ -61,6 +96,12 @@ public struct MyGame_Sample_Vec3: NativeStruct, Verifiable, FlatbuffersInitializ _z = 0.0 } + public init(_ _t: inout MyGame_Sample_Vec3_Mutable) { + _x = _t.x + _y = _t.y + _z = _t.z + } + public var x: Float32 { _x } public var y: Float32 { _y } public var z: Float32 { _z } @@ -70,6 +111,27 @@ public struct MyGame_Sample_Vec3: NativeStruct, Verifiable, FlatbuffersInitializ } } +extension MyGame_Sample_Vec3: Encodable { + + enum CodingKeys: String, CodingKey { + case x = "x" + case y = "y" + case z = "z" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + if x != 0.0 { + try container.encodeIfPresent(x, forKey: .x) + } + if y != 0.0 { + try container.encodeIfPresent(y, forKey: .y) + } + if z != 0.0 { + try container.encodeIfPresent(z, forKey: .z) + } + } +} + public struct MyGame_Sample_Vec3_Mutable: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_25_2_10() } @@ -84,9 +146,22 @@ public struct MyGame_Sample_Vec3_Mutable: FlatBufferObject { @discardableResult public func mutate(y: Float32) -> Bool { return _accessor.mutate(y, index: 4) } public var z: Float32 { return _accessor.readBuffer(of: Float32.self, at: 8) } @discardableResult public func mutate(z: Float32) -> Bool { return _accessor.mutate(z, index: 8) } + + + public mutating func unpack() -> MyGame_Sample_Vec3 { + return MyGame_Sample_Vec3(&self) + } + public static func pack(_ builder: inout FlatBufferBuilder, obj: inout MyGame_Sample_Vec3?) -> Offset { + guard var obj = obj else { return Offset() } + return pack(&builder, obj: &obj) + } + + public static func pack(_ builder: inout FlatBufferBuilder, obj: inout MyGame_Sample_Vec3) -> Offset { + return builder.create(struct: obj) + } } -public struct MyGame_Sample_Monster: FlatBufferObject, Verifiable { +public struct MyGame_Sample_Monster: FlatBufferObject, Verifiable, ObjectAPIPacker { static func validateVersion() { FlatBuffersVersion_25_2_10() } public var __buffer: ByteBuffer! { return _accessor.bb } @@ -123,6 +198,7 @@ public struct MyGame_Sample_Monster: FlatBufferObject, Verifiable { public func inventory(at index: Int32) -> UInt8 { let o = _accessor.offset(VTOFFSET.inventory.v); return o == 0 ? 0 : _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1) } public var inventory: [UInt8] { return _accessor.getVector(at: VTOFFSET.inventory.v) ?? [] } public func mutate(inventory: UInt8, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.inventory.v); return _accessor.directMutate(inventory, index: _accessor.vector(at: o) + index * 1) } + public func withUnsafePointerToInventory(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.inventory.v, body: body) } public var color: MyGame_Sample_Color { let o = _accessor.offset(VTOFFSET.color.v); return o == 0 ? .blue : MyGame_Sample_Color(rawValue: _accessor.readBuffer(of: Int8.self, at: o)) ?? .blue } @discardableResult public func mutate(color: MyGame_Sample_Color) -> Bool {let o = _accessor.offset(VTOFFSET.color.v); return _accessor.mutate(color.rawValue, index: o) } public var hasWeapons: Bool { let o = _accessor.offset(VTOFFSET.weapons.v); return o == 0 ? false : true } @@ -134,6 +210,7 @@ public struct MyGame_Sample_Monster: FlatBufferObject, Verifiable { public var pathCount: Int32 { let o = _accessor.offset(VTOFFSET.path.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func path(at index: Int32) -> MyGame_Sample_Vec3? { let o = _accessor.offset(VTOFFSET.path.v); return o == 0 ? nil : _accessor.directRead(of: MyGame_Sample_Vec3.self, offset: _accessor.vector(at: o) + index * 12) } public func mutablePath(at index: Int32) -> MyGame_Sample_Vec3_Mutable? { let o = _accessor.offset(VTOFFSET.path.v); return o == 0 ? nil : MyGame_Sample_Vec3_Mutable(_accessor.bb, o: _accessor.vector(at: o) + index * 12) } + public func withUnsafePointerToPath(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.path.v, body: body) } public static func startMonster(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 11) } public static func add(pos: MyGame_Sample_Vec3?, _ fbb: inout FlatBufferBuilder) { guard let pos = pos else { return }; fbb.create(struct: pos, position: VTOFFSET.pos.p) } public static func add(mana: Int16, _ fbb: inout FlatBufferBuilder) { fbb.add(element: mana, def: 150, at: VTOFFSET.mana.p) } @@ -175,6 +252,53 @@ public struct MyGame_Sample_Monster: FlatBufferObject, Verifiable { MyGame_Sample_Monster.addVectorOf(path: path, &fbb) return MyGame_Sample_Monster.endMonster(&fbb, start: __start) } + + + public mutating func unpack() -> MyGame_Sample_MonsterT { + return MyGame_Sample_MonsterT(&self) + } + public static func pack(_ builder: inout FlatBufferBuilder, obj: inout MyGame_Sample_MonsterT?) -> Offset { + guard var obj = obj else { return Offset() } + return pack(&builder, obj: &obj) + } + + public static func pack(_ builder: inout FlatBufferBuilder, obj: inout MyGame_Sample_MonsterT) -> Offset { + let __name: Offset + if let s = obj.name { + __name = builder.create(string: s) + } else { + __name = Offset() + } + + let __inventory = builder.createVector(obj.inventory) + var __weapons__: [Offset] = [] + for var i in obj.weapons { + __weapons__.append(MyGame_Sample_Weapon.pack(&builder, obj: &i)) + } + let __weapons = builder.createVector(ofOffsets: __weapons__) + let __equipped = obj.equipped?.pack(builder: &builder) ?? Offset() + MyGame_Sample_Monster.startVectorOfPath(obj.path.count, in: &builder) + for i in obj.path { + guard let _o = i else { continue } + builder.create(struct: _o) + } + let __path = builder.endVector(len: obj.path.count) + let __root = MyGame_Sample_Monster.startMonster(&builder) + MyGame_Sample_Monster.add(pos: obj.pos, &builder) + MyGame_Sample_Monster.add(mana: obj.mana, &builder) + MyGame_Sample_Monster.add(hp: obj.hp, &builder) + MyGame_Sample_Monster.add(name: __name, &builder) + MyGame_Sample_Monster.addVectorOf(inventory: __inventory, &builder) + MyGame_Sample_Monster.add(color: obj.color, &builder) + MyGame_Sample_Monster.addVectorOf(weapons: __weapons, &builder) + if let o = obj.equipped?.type { + MyGame_Sample_Monster.add(equippedType: o, &builder) + MyGame_Sample_Monster.add(equipped: __equipped, &builder) + } + + MyGame_Sample_Monster.addVectorOf(path: __path, &builder) + return MyGame_Sample_Monster.endMonster(&builder, start: __root) + } public static func verify(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { var _v = try verifier.visitTable(at: position) @@ -198,7 +322,115 @@ public struct MyGame_Sample_Monster: FlatBufferObject, Verifiable { } } -public struct MyGame_Sample_Weapon: FlatBufferObject, Verifiable { +extension MyGame_Sample_Monster: Encodable { + + enum CodingKeys: String, CodingKey { + case pos = "pos" + case mana = "mana" + case hp = "hp" + case name = "name" + case inventory = "inventory" + case color = "color" + case weapons = "weapons" + case equippedType = "equipped_type" + case equipped = "equipped" + case path = "path" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(pos, forKey: .pos) + if mana != 150 { + try container.encodeIfPresent(mana, forKey: .mana) + } + if hp != 100 { + try container.encodeIfPresent(hp, forKey: .hp) + } + try container.encodeIfPresent(name, forKey: .name) + if inventoryCount > 0 { + try container.encodeIfPresent(inventory, forKey: .inventory) + } + if color != .blue { + try container.encodeIfPresent(color, forKey: .color) + } + if weaponsCount > 0 { + var contentEncoder = container.nestedUnkeyedContainer(forKey: .weapons) + for index in 0.. 0 { + var contentEncoder = container.nestedUnkeyedContainer(forKey: .path) + for index in 0.. ByteBuffer { return serialize(type: MyGame_Sample_Monster.self) } + +} +public struct MyGame_Sample_Weapon: FlatBufferObject, Verifiable, ObjectAPIPacker { static func validateVersion() { FlatBuffersVersion_25_2_10() } public var __buffer: ByteBuffer! { return _accessor.bb } @@ -232,6 +464,29 @@ public struct MyGame_Sample_Weapon: FlatBufferObject, Verifiable { MyGame_Sample_Weapon.add(damage: damage, &fbb) return MyGame_Sample_Weapon.endWeapon(&fbb, start: __start) } + + + public mutating func unpack() -> MyGame_Sample_WeaponT { + return MyGame_Sample_WeaponT(&self) + } + public static func pack(_ builder: inout FlatBufferBuilder, obj: inout MyGame_Sample_WeaponT?) -> Offset { + guard var obj = obj else { return Offset() } + return pack(&builder, obj: &obj) + } + + public static func pack(_ builder: inout FlatBufferBuilder, obj: inout MyGame_Sample_WeaponT) -> Offset { + let __name: Offset + if let s = obj.name { + __name = builder.create(string: s) + } else { + __name = Offset() + } + + let __root = MyGame_Sample_Weapon.startWeapon(&builder) + MyGame_Sample_Weapon.add(name: __name, &builder) + MyGame_Sample_Weapon.add(damage: obj.damage, &builder) + return MyGame_Sample_Weapon.endWeapon(&builder, start: __root) + } public static func verify(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { var _v = try verifier.visitTable(at: position) @@ -241,3 +496,35 @@ public struct MyGame_Sample_Weapon: FlatBufferObject, Verifiable { } } +extension MyGame_Sample_Weapon: Encodable { + + enum CodingKeys: String, CodingKey { + case name = "name" + case damage = "damage" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(name, forKey: .name) + if damage != 0 { + try container.encodeIfPresent(damage, forKey: .damage) + } + } +} + +public class MyGame_Sample_WeaponT: NativeObject { + + public var name: String? + public var damage: Int16 + + public init(_ _t: inout MyGame_Sample_Weapon) { + name = _t.name + damage = _t.damage + } + + public init() { + damage = 0 + } + + public func serialize() -> ByteBuffer { return serialize(type: MyGame_Sample_Weapon.self) } + +} diff --git a/scripts/generate_code.py b/scripts/generate_code.py index 772cdf474..7f63db6d0 100755 --- a/scripts/generate_code.py +++ b/scripts/generate_code.py @@ -511,7 +511,7 @@ flatc( # Sample files samples_schema = "monster.fbs" -flatc(BASE_OPTS + CPP_OPTS + LOBSTER_OPTS, schema=samples_schema, cwd=samples_path) +flatc(BASE_OPTS + CPP_OPTS + LOBSTER_OPTS + SWIFT_OPTS, schema=samples_schema, cwd=samples_path) flatc(RUST_OPTS, prefix="rust_generated", schema=samples_schema, cwd=samples_path) flatc( BINARY_OPTS + ["--bfbs-filenames", str(samples_path)], diff --git a/src/idl_gen_swift.cpp b/src/idl_gen_swift.cpp index e3318c968..b73333b43 100644 --- a/src/idl_gen_swift.cpp +++ b/src/idl_gen_swift.cpp @@ -569,8 +569,8 @@ class SwiftGenerator : public BaseGenerator { code_ += spacing + "off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: " - "{{VOFFSET}}, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: " - "{{VOFFSET}}, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } "; + "{{VOFFSET}}, fbb: &fbb), Table.offset(Int32($0.o), vOffset: " + "{{VOFFSET}}, fbb: &fbb), fbb: &fbb) < 0 } "; code_ += spacing + "return fbb.createVector(ofOffsets: off)"; Outdent(); code_ += "}"; @@ -832,6 +832,7 @@ class SwiftGenerator : public BaseGenerator { "{{ACCESS_TYPE}} var {{FIELDVAR}}: [{{VALUETYPE}}] { return " "{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) ?? [] }"; if (parser_.opts.mutable_buffer) code_ += GenMutateArray(); + GenUnsafeBufferPointer(field); return; } @@ -845,6 +846,7 @@ class SwiftGenerator : public BaseGenerator { code_ += GenArrayMainBody(nullable) + GenOffset() + const_string + GenConstructor("{{ACCESS}}.vector(at: o) + index * {{SIZE}}"); + GenUnsafeBufferPointer(field); return; } @@ -887,6 +889,16 @@ class SwiftGenerator : public BaseGenerator { } } + void GenUnsafeBufferPointer(const FieldDef &field) { + code_.SetValue("functionName", + namer_.Variable("withUnsafePointerTo", field)); + code_ += + "{{ACCESS_TYPE}} func {{functionName}}(_ body: " + "(UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try " + "{{ACCESS}}.withUnsafePointerToSlice(at: {{TABLEOFFSET}}.{{OFFSET}}.v, " + "body: body) }"; + } + void GenerateCodingKeys(const StructDef &struct_def) { code_ += "enum CodingKeys: String, CodingKey {"; Indent(); diff --git a/swift.swiftformat b/swift.swiftformat index f8b2a6b02..be8210238 100644 --- a/swift.swiftformat +++ b/swift.swiftformat @@ -17,11 +17,11 @@ --typeattributes prev-line # wrapAttributes # rules ---rules wrap,todos,anyObjectProtocol,redundantParens,redundantReturn,redundantSelf,sortImports,strongifiedSelf,trailingCommas,trailingSpace,wrapArguments,wrapMultilineStatementBraces,indent,wrapAttributes,void,fileHeader +--rules wrap,todos,anyObjectProtocol,redundantParens,redundantSelf,sortImports,strongifiedSelf,trailingCommas,trailingSpace,wrapArguments,wrapMultilineStatementBraces,indent,wrapAttributes,void,fileHeader --disable trailingclosures --exclude **/*_generated.swift --exclude **/swift_code_*.swift --exclude **/*.grpc.swift ---header "/*\n * Copyright {year} Google Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */" \ No newline at end of file +--header "/*\n * Copyright 2024 Google Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */" \ No newline at end of file diff --git a/swift/Sources/FlatBuffers/ByteBuffer.swift b/swift/Sources/FlatBuffers/ByteBuffer.swift index 9442c855a..31485794e 100644 --- a/swift/Sources/FlatBuffers/ByteBuffer.swift +++ b/swift/Sources/FlatBuffers/ByteBuffer.swift @@ -26,192 +26,240 @@ public struct ByteBuffer { /// deallocating the memory that was held by (memory: UnsafeMutableRawPointer) @usableFromInline final class Storage { - // This storage doesn't own the memory, therefore, we won't deallocate on deinit. - private let unowned: Bool - /// pointer to the start of the buffer object in memory - var memory: UnsafeMutableRawPointer + @usableFromInline + enum Blob { + #if !os(WASI) + case data(Data) + case bytes(ContiguousBytes) + #endif + + case byteBuffer(_InternalByteBuffer) + case array([UInt8]) + case pointer(UnsafeMutableRawPointer) + } + + /// This storage doesn't own the memory, therefore, we won't deallocate on deinit. + private let isOwned: Bool + /// Retained blob of data that requires the storage to retain a pointer to. + @usableFromInline + var retainedBlob: Blob /// Capacity of UInt8 the buffer can hold var capacity: Int @usableFromInline - init(count: Int, alignment: Int) { - memory = UnsafeMutableRawPointer.allocate( + init(count: Int) { + let memory = UnsafeMutableRawPointer.allocate( byteCount: count, - alignment: alignment) + alignment: MemoryLayout.alignment) capacity = count - unowned = false + retainedBlob = .pointer(memory) + isOwned = true } @usableFromInline - init(memory: UnsafeMutableRawPointer, capacity: Int, unowned: Bool) { - self.memory = memory - self.capacity = capacity - self.unowned = unowned + init(blob: Blob, capacity count: Int) { + capacity = count + retainedBlob = blob + isOwned = false } deinit { - if !unowned { - memory.deallocate() + guard isOwned else { return } + switch retainedBlob { + case .pointer(let unsafeMutableRawPointer): + unsafeMutableRawPointer.deallocate() + default: break } } @usableFromInline func copy(from ptr: UnsafeRawPointer, count: Int) { assert( - !unowned, + isOwned, "copy should NOT be called on a buffer that is built by assumingMemoryBound") - memory.copyMemory(from: ptr, byteCount: count) + withUnsafeRawPointer { + $0.copyMemory(from: ptr, byteCount: count) + } } @usableFromInline func initialize(for size: Int) { assert( - !unowned, + isOwned, "initalize should NOT be called on a buffer that is built by assumingMemoryBound") - memset(memory, 0, size) + withUnsafeRawPointer { + memset($0, 0, size) + } } - /// Reallocates the buffer incase the object to be written doesnt fit in the current buffer - /// - Parameter size: Size of the current object - @usableFromInline - func reallocate(_ size: Int, writerSize: Int, alignment: Int) { - let currentWritingIndex = capacity &- writerSize - while capacity <= writerSize &+ size { - capacity = capacity << 1 + @discardableResult + @inline(__always) + func withUnsafeBytes( + _ body: (UnsafeRawBufferPointer) throws + -> T) rethrows -> T + { + switch retainedBlob { + case .byteBuffer(let byteBuffer): + return try byteBuffer.withUnsafeBytes(body) + #if !os(WASI) + case .data(let data): + return try data.withUnsafeBytes(body) + case .bytes(let contiguousBytes): + return try contiguousBytes.withUnsafeBytes(body) + #endif + case .array(let array): + return try array.withUnsafeBytes(body) + case .pointer(let ptr): + return try body(UnsafeRawBufferPointer(start: ptr, count: capacity)) } + } - /// solution take from Apple-NIO - capacity = capacity.convertToPowerofTwo + @discardableResult + @inline(__always) + func withUnsafeRawPointer( + _ body: (UnsafeMutableRawPointer) throws + -> T) rethrows -> T + { + switch retainedBlob { + case .byteBuffer(let byteBuffer): + return try byteBuffer.withUnsafeRawPointer(body) + #if !os(WASI) + case .data(let data): + return try data + .withUnsafeBytes { + try body(UnsafeMutableRawPointer(mutating: $0.baseAddress!)) + } + case .bytes(let contiguousBytes): + return try contiguousBytes + .withUnsafeBytes { + try body(UnsafeMutableRawPointer(mutating: $0.baseAddress!)) + } + #endif + case .array(let array): + return try array + .withUnsafeBytes { + try body(UnsafeMutableRawPointer(mutating: $0.baseAddress!)) + } + case .pointer(let ptr): + return try body(ptr) + } + } - let newData = UnsafeMutableRawPointer.allocate( - byteCount: capacity, - alignment: alignment) - memset(newData, 0, capacity &- writerSize) - memcpy( - newData.advanced(by: capacity &- writerSize), - memory.advanced(by: currentWritingIndex), - writerSize) - memory.deallocate() - memory = newData + @discardableResult + @inline(__always) + func readWithUnsafeRawPointer( + position: Int, + _ body: (UnsafeRawPointer) throws -> T) rethrows -> T + { + switch retainedBlob { + case .byteBuffer(let byteBuffer): + return try byteBuffer.readWithUnsafeRawPointer(position: position, body) + #if !os(WASI) + case .data(let data): + return try data.withUnsafeBytes { + try body($0.baseAddress!.advanced(by: position)) + } + case .bytes(let contiguousBytes): + return try contiguousBytes.withUnsafeBytes { + try body($0.baseAddress!.advanced(by: position)) + } + #endif + case .array(let array): + return try array.withUnsafeBytes { + try body($0.baseAddress!.advanced(by: position)) + } + case .pointer(let ptr): + return try body(ptr.advanced(by: position)) + } } } @usableFromInline var _storage: Storage /// The size of the elements written to the buffer + their paddings - private var _writerSize: Int = 0 - /// Alignment of the current memory being written to the buffer - 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 - var writerIndex: Int { _storage.capacity &- _writerSize } - + private var _readerIndex: Int = 0 /// Reader is the position of the current Writer Index (capacity - size) - public var reader: Int { writerIndex } + public var reader: Int { _storage.capacity &- _readerIndex } /// Current size of the buffer - public var size: UOffset { UOffset(_writerSize) } - /// Public Pointer to the buffer object in memory. This should NOT be modified for any reason - public var memory: UnsafeMutableRawPointer { _storage.memory } + public var size: UOffset { UOffset(_readerIndex) } /// Current capacity for the buffer public var capacity: Int { _storage.capacity } - /// Crash if the trying to read an unaligned buffer instead of allowing users to read them. - public let allowReadingUnalignedBuffers: Bool + + /// Constructor that creates a Flatbuffer object from an InternalByteBuffer + /// - Parameter + /// - bytes: Array of UInt8 + @inline(__always) + init(byteBuffer: _InternalByteBuffer) { + _storage = Storage( + blob: .byteBuffer(byteBuffer), + capacity: byteBuffer.capacity) + _readerIndex = Int(byteBuffer.size) + } + + /// Constructor that creates a Flatbuffer from unsafe memory region by copying + /// the underlying data to a new pointer + /// + /// - Parameters: + /// - copyingMemoryBound: The unsafe memory region + /// - capacity: The size of the given memory region + @inline(__always) + public init( + copyingMemoryBound memory: UnsafeRawPointer, + capacity: Int) + { + _storage = Storage(count: capacity) + _storage.copy(from: memory, count: capacity) + _readerIndex = _storage.capacity + } /// Constructor that creates a Flatbuffer object from a UInt8 /// - Parameter /// - bytes: Array of UInt8 - /// - allowReadingUnalignedBuffers: allow reading from unaligned buffer - public init( - bytes: [UInt8], - allowReadingUnalignedBuffers allowUnalignedBuffers: Bool = false) - { - var b = bytes - _storage = Storage(count: bytes.count, alignment: alignment) - _writerSize = _storage.capacity - allowReadingUnalignedBuffers = allowUnalignedBuffers - b.withUnsafeMutableBytes { bufferPointer in - _storage.copy(from: bufferPointer.baseAddress!, count: bytes.count) - } + @inline(__always) + public init(bytes: [UInt8]) { + _storage = Storage(blob: .array(bytes), capacity: bytes.count) + _readerIndex = _storage.capacity } #if !os(WASI) /// Constructor that creates a Flatbuffer from the Swift Data type object /// - Parameter /// - data: Swift data Object - /// - allowReadingUnalignedBuffers: allow reading from unaligned buffer - public init( - data: Data, - allowReadingUnalignedBuffers allowUnalignedBuffers: Bool = false) - { - var b = data - _storage = Storage(count: data.count, alignment: alignment) - _writerSize = _storage.capacity - allowReadingUnalignedBuffers = allowUnalignedBuffers - b.withUnsafeMutableBytes { bufferPointer in - _storage.copy(from: bufferPointer.baseAddress!, count: data.count) - } - } - #endif - - /// Constructor that creates a Flatbuffer instance with a size - /// - Parameter: - /// - size: Length of the buffer - /// - allowReadingUnalignedBuffers: allow reading from unaligned buffer - init(initialSize size: Int) { - let size = size.convertToPowerofTwo - _storage = Storage(count: size, alignment: alignment) - _storage.initialize(for: size) - allowReadingUnalignedBuffers = false + @inline(__always) + public init(data: Data) { + _storage = Storage(blob: .data(data), capacity: data.count) + _readerIndex = _storage.capacity } - #if swift(>=5.0) && !os(WASI) /// Constructor that creates a Flatbuffer object from a ContiguousBytes /// - Parameters: /// - contiguousBytes: Binary stripe to use as the buffer /// - count: amount of readable bytes - /// - allowReadingUnalignedBuffers: allow reading from unaligned buffer + @inline(__always) public init( contiguousBytes: Bytes, - count: Int, - allowReadingUnalignedBuffers allowUnalignedBuffers: Bool = false) + count: Int) { - _storage = Storage(count: count, alignment: alignment) - _writerSize = _storage.capacity - allowReadingUnalignedBuffers = allowUnalignedBuffers - contiguousBytes.withUnsafeBytes { buf in - _storage.copy(from: buf.baseAddress!, count: buf.count) - } + _storage = Storage(blob: .bytes(contiguousBytes), capacity: count) + _readerIndex = _storage.capacity } #endif /// Constructor that creates a Flatbuffer from unsafe memory region without copying - /// - Parameter: + /// **NOTE** Needs a call to `memory.deallocate()` later on to free the memory + /// + /// - Parameters: /// - assumingMemoryBound: The unsafe memory region /// - capacity: The size of the given memory region - /// - allowReadingUnalignedBuffers: allow reading from unaligned buffer + @inline(__always) public init( assumingMemoryBound memory: UnsafeMutableRawPointer, - capacity: Int, - allowReadingUnalignedBuffers allowUnalignedBuffers: Bool = false) + capacity: Int) { - _storage = Storage(memory: memory, capacity: capacity, unowned: true) - _writerSize = capacity - allowReadingUnalignedBuffers = allowUnalignedBuffers - } - - /// Creates a copy of the buffer that's being built by calling sizedBuffer - /// - Parameters: - /// - memory: Current memory of the buffer - /// - count: count of bytes - /// - allowReadingUnalignedBuffers: allow reading from unaligned buffer - init( - memory: UnsafeMutableRawPointer, - count: Int, - allowReadingUnalignedBuffers allowUnalignedBuffers: Bool = false) - { - _storage = Storage(count: count, alignment: alignment) - _storage.copy(from: memory, count: count) - _writerSize = _storage.capacity - allowReadingUnalignedBuffers = allowUnalignedBuffers + _storage = Storage( + blob: .pointer(memory), + capacity: capacity) + _readerIndex = _storage.capacity } /// Creates a copy of the existing flatbuffer, by copying it to a different memory. @@ -219,145 +267,14 @@ public struct ByteBuffer { /// - memory: Current memory of the buffer /// - count: count of bytes /// - removeBytes: Removes a number of bytes from the current size - /// - allowReadingUnalignedBuffers: allow reading from unaligned buffer + @inline(__always) init( - memory: UnsafeMutableRawPointer, + blob: Storage.Blob, count: Int, - removing removeBytes: Int, - allowReadingUnalignedBuffers allowUnalignedBuffers: Bool = false) + removing removeBytes: Int) { - _storage = Storage(count: count, alignment: alignment) - _storage.copy(from: memory, count: count) - _writerSize = removeBytes - allowReadingUnalignedBuffers = allowUnalignedBuffers - } - - /// Fills the buffer with padding by adding to the writersize - /// - Parameter padding: Amount of padding between two to be serialized objects - @inline(__always) - @usableFromInline - mutating func fill(padding: Int) { - assert(padding >= 0, "Fill should be larger than or equal to zero") - ensureSpace(size: padding) - _writerSize = _writerSize &+ (MemoryLayout.size &* padding) - } - - /// Adds an array of type Scalar to the buffer memory - /// - Parameter elements: An array of Scalars - @inline(__always) - @usableFromInline - mutating func push(elements: [T]) { - elements.withUnsafeBytes { ptr in - ensureSpace(size: ptr.count) - memcpy( - _storage.memory.advanced(by: writerIndex &- ptr.count), - ptr.baseAddress!, - ptr.count) - _writerSize = _writerSize &+ ptr.count - } - } - - /// Adds an array of type Scalar to the buffer memory - /// - Parameter elements: An array of Scalars - @inline(__always) - @usableFromInline - mutating func push(elements: [T]) { - elements.withUnsafeBytes { ptr in - ensureSpace(size: ptr.count) - memcpy( - _storage.memory.advanced(by: writerIndex &- ptr.count), - ptr.baseAddress!, - ptr.count) - _writerSize = _writerSize &+ ptr.count - } - } - - /// Adds a `ContiguousBytes` to buffer memory - /// - Parameter value: bytes to copy - #if swift(>=5.0) && !os(WASI) - @inline(__always) - @usableFromInline - mutating func push(bytes: ContiguousBytes) { - bytes.withUnsafeBytes { ptr in - ensureSpace(size: ptr.count) - memcpy( - _storage.memory.advanced(by: writerIndex &- ptr.count), - ptr.baseAddress!, - ptr.count) - _writerSize = _writerSize &+ ptr.count - } - } - #endif - - /// Adds an object of type NativeStruct into the buffer - /// - Parameters: - /// - value: Object that will be written to the buffer - /// - size: size to subtract from the WriterIndex - @usableFromInline - @inline(__always) - mutating func push(struct value: T, size: Int) { - ensureSpace(size: size) - withUnsafePointer(to: value) { - memcpy( - _storage.memory.advanced(by: writerIndex &- size), - $0, - size) - _writerSize = _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 - @inline(__always) - @usableFromInline - mutating func push(value: T, len: Int) { - ensureSpace(size: len) - withUnsafePointer(to: value) { - memcpy( - _storage.memory.advanced(by: writerIndex &- len), - $0, - len) - _writerSize = _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 - @inline(__always) - @usableFromInline - mutating func push(string str: String, len: Int) { - ensureSpace(size: len) - if str.utf8 - .withContiguousStorageIfAvailable({ self.push(bytes: $0, len: len) }) != - nil - { - } else { - let utf8View = str.utf8 - for c in utf8View.reversed() { - push(value: c, len: 1) - } - } - } - - /// Writes a string to Bytebuffer using UTF8View - /// - Parameters: - /// - bytes: Pointer to the view - /// - len: Size of string - @usableFromInline - @inline(__always) - mutating func push( - bytes: UnsafeBufferPointer, - len: Int) -> Bool - { - memcpy( - _storage.memory.advanced(by: writerIndex &- len), - bytes.baseAddress!, - len) - _writerSize = _writerSize &+ len - return true + _storage = Storage(blob: blob, capacity: count) + _readerIndex = removeBytes } /// Write stores an object into the buffer directly or indirectly. @@ -376,63 +293,26 @@ public struct ByteBuffer { } assert(index < _storage.capacity, "Write index is out of writing bound") assert(index >= 0, "Writer index should be above zero") - withUnsafePointer(to: value) { - memcpy( - _storage.memory.advanced(by: index), - $0, - MemoryLayout.size) + _ = withUnsafePointer(to: value) { ptr in + _storage.withUnsafeRawPointer { + memcpy( + $0.advanced(by: index), + ptr, + MemoryLayout.size) + } } } - /// Makes sure that buffer has enouch space for each of the objects that will be written into it - /// - Parameter size: size of object - @discardableResult - @usableFromInline - @inline(__always) - mutating func ensureSpace(size: Int) -> Int { - if size &+ _writerSize > _storage.capacity { - _storage.reallocate(size, writerSize: _writerSize, alignment: alignment) - } - assert(size < FlatBufferMaxSize, "Buffer can't grow beyond 2 Gigabytes") - return size - } - - /// pops the written VTable if it's already written into the buffer - /// - Parameter size: size of the `VTable` - @usableFromInline - @inline(__always) - mutating func pop(_ size: Int) { - assert( - (_writerSize &- size) > 0, - "New size should NOT be a negative number") - memset(_storage.memory.advanced(by: writerIndex), 0, _writerSize &- size) - _writerSize = size - } - - /// Clears the current size of the buffer - @inline(__always) - mutating public func clearSize() { - _writerSize = 0 - } - - /// Clears the current instance of the buffer, replacing it with new memory - @inline(__always) - mutating public func clear() { - _writerSize = 0 - alignment = 1 - _storage.initialize(for: _storage.capacity) - } - /// Reads an object from the buffer /// - Parameters: /// - def: Type of the object /// - position: the index of the object in the buffer @inline(__always) public func read(def: T.Type, position: Int) -> T { - if allowReadingUnalignedBuffers { - return _storage.memory.advanced(by: position).loadUnaligned(as: T.self) + _storage.readWithUnsafeRawPointer(position: position) { + $0.bindMemory(to: T.self, capacity: 1) + .pointee } - return _storage.memory.advanced(by: position).load(as: T.self) } /// Reads a slice from the memory assuming a type of T @@ -447,10 +327,32 @@ public struct ByteBuffer { assert( index + count <= _storage.capacity, "Reading out of bounds is illegal") - let start = _storage.memory.advanced(by: index) - .assumingMemoryBound(to: T.self) - let array = UnsafeBufferPointer(start: start, count: count) - return Array(array) + + return _storage.readWithUnsafeRawPointer(position: index) { + let buf = UnsafeBufferPointer( + start: $0.bindMemory(to: T.self, capacity: count), + count: count) + return Array(buf) + } + } + + /// Provides a pointer towards the underlying primitive types + /// - Parameters: + /// - index: index of the object to be read from the buffer + /// - count: count of bytes in memory + @discardableResult + @inline(__always) + public func withUnsafePointerToSlice( + index: Int, + count: Int, + body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T + { + assert( + index + count <= _storage.capacity, + "Reading out of bounds is illegal") + return try _storage.readWithUnsafeRawPointer(position: index) { + try body(UnsafeRawBufferPointer(start: $0, count: count)) + } } #if !os(WASI) @@ -468,10 +370,14 @@ public struct ByteBuffer { assert( index + count <= _storage.capacity, "Reading out of bounds is illegal") - let start = _storage.memory.advanced(by: index) - .assumingMemoryBound(to: UInt8.self) - let bufprt = UnsafeBufferPointer(start: start, count: count) - return String(bytes: Array(bufprt), encoding: type) + return _storage.readWithUnsafeRawPointer(position: index) { + let buf = UnsafeBufferPointer( + start: $0.bindMemory(to: UInt8.self, capacity: count), + count: count) + return String( + bytes: buf, + encoding: type) + } } #else /// Reads a string from the buffer and encodes it to a swift string @@ -486,10 +392,9 @@ public struct ByteBuffer { assert( index + count <= _storage.capacity, "Reading out of bounds is illegal") - let start = _storage.memory.advanced(by: index) - .assumingMemoryBound(to: UInt8.self) - let bufprt = UnsafeBufferPointer(start: start, count: count) - return String(cString: bufprt.baseAddress!) + return _storage.readWithUnsafeRawPointer(position: index) { + String(cString: $0.bindMemory(to: UInt8.self, capacity: count)) + } } #endif @@ -502,19 +407,9 @@ public struct ByteBuffer { removeBytes < _storage.capacity, "Can NOT remove more bytes than the ones allocated") return ByteBuffer( - memory: _storage.memory, + blob: _storage.retainedBlob, count: _storage.capacity, - removing: _writerSize &- removeBytes) - } - - /// Returns the written bytes into the ``ByteBuffer`` - public var underlyingBytes: [UInt8] { - let cp = capacity &- writerIndex - let start = memory.advanced(by: writerIndex) - .bindMemory(to: UInt8.self, capacity: cp) - - let ptr = UnsafeBufferPointer(start: start, count: cp) - return Array(ptr) + removing: _readerIndex &- removeBytes) } /// SkipPrefix Skips the first 4 bytes in case one of the following @@ -524,19 +419,46 @@ public struct ByteBuffer { @usableFromInline @inline(__always) mutating func skipPrefix() -> Int32 { - _writerSize = _writerSize &- MemoryLayout.size + _readerIndex = _readerIndex &- MemoryLayout.size return read(def: Int32.self, position: 0) } + @discardableResult + @inline(__always) + public func withUnsafeBytes( + body: (UnsafeRawBufferPointer) throws + -> T) rethrows -> T + { + try _storage.withUnsafeBytes(body) + } + + @discardableResult + @inline(__always) + func withUnsafeMutableRawPointer( + body: (UnsafeMutableRawPointer) throws + -> T) rethrows -> T + { + try _storage.withUnsafeRawPointer(body) + } + + @discardableResult + @inline(__always) + func readWithUnsafeRawPointer( + position: Int, + _ body: (UnsafeRawPointer) throws -> T) rethrows -> T + { + try _storage.readWithUnsafeRawPointer(position: position, body) + } } extension ByteBuffer: CustomDebugStringConvertible { public var debugDescription: String { """ - buffer located at: \(_storage.memory), with capacity of \(_storage.capacity) - { writerSize: \(_writerSize), readerSize: \(reader), writerIndex: \( - writerIndex) } + buffer located at: \(_storage.retainedBlob), + with capacity of \(_storage.capacity), + { writtenSize: \(_readerIndex), readerSize: \(reader), + size: \(size) } """ } } diff --git a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift index 26ae63491..c96f24cde 100644 --- a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift +++ b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift @@ -32,7 +32,7 @@ public struct FlatBufferBuilder { /// Storage for the Vtables used in the buffer are stored in here, so they would be written later in EndTable @usableFromInline internal var _vtableStorage = VTableStorage() /// Flatbuffer data will be written into - @usableFromInline internal var _bb: ByteBuffer + @usableFromInline internal var _bb: _InternalByteBuffer /// Reference Vtables that were already written to the buffer private var _vtables: [UOffset] = [] @@ -54,6 +54,9 @@ public struct FlatBufferBuilder { /// Gives a read access to the buffer's size public var size: UOffset { _bb.size } + /// Current allocated capacity within the storage + @inline(__always) + public var capacity: Int { _bb.capacity } #if !os(WASI) /// Data representation of the buffer @@ -61,9 +64,15 @@ public struct FlatBufferBuilder { /// Should only be used after ``finish(offset:addPrefix:)`` is called public var data: Data { assert(finished, "Data shouldn't be called before finish()") - return Data( - bytes: _bb.memory.advanced(by: _bb.writerIndex), - count: _bb.capacity &- _bb.writerIndex) + return _bb.withUnsafeSlicedBytes { ptr in + var data = Data() + data.append( + ptr.baseAddress!.bindMemory( + to: UInt8.self, + capacity: _bb.capacity), + count: _bb.capacity) + return data + } } #endif @@ -71,10 +80,9 @@ public struct FlatBufferBuilder { /// /// Note: This should be used with caution. public var fullSizedByteArray: [UInt8] { - let ptr = UnsafeBufferPointer( - start: _bb.memory.assumingMemoryBound(to: UInt8.self), - count: _bb.capacity) - return Array(ptr) + _bb.withUnsafeBytes { ptr in + Array(ptr) + } } /// Returns the written bytes into the ``ByteBuffer`` @@ -82,14 +90,18 @@ public struct FlatBufferBuilder { /// Should only be used after ``finish(offset:addPrefix:)`` is called public var sizedByteArray: [UInt8] { assert(finished, "Data shouldn't be called before finish()") - return _bb.underlyingBytes + return _bb.withUnsafeSlicedBytes { ptr in + Array(ptr) + } } /// Returns the original ``ByteBuffer`` /// /// Returns the current buffer that was just created /// with the offsets, and data written to it. - public var buffer: ByteBuffer { _bb } + public var buffer: ByteBuffer { + ByteBuffer(byteBuffer: _bb) + } /// Returns a newly created sized ``ByteBuffer`` /// @@ -97,9 +109,11 @@ public struct FlatBufferBuilder { /// to the main buffer public var sizedBuffer: ByteBuffer { assert(finished, "Data shouldn't be called before finish()") - return ByteBuffer( - memory: _bb.memory.advanced(by: _bb.reader), - count: Int(_bb.size)) + return _bb.withUnsafeSlicedBytes { ptr in + ByteBuffer( + copyingMemoryBound: ptr.baseAddress!, + capacity: ptr.count) + } } // MARK: - Init @@ -122,7 +136,7 @@ public struct FlatBufferBuilder { "Reading/Writing a buffer in big endian machine is not supported on swift") } serializeDefaults = force - _bb = ByteBuffer(initialSize: Int(initialSize)) + _bb = _InternalByteBuffer(initialSize: Int(initialSize)) } /// Clears the builder and the buffer from the written data. @@ -149,9 +163,10 @@ public struct FlatBufferBuilder { 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(fields[index])) != 0 + let isOkay = + _bb.read( + def: VOffset.self, + position: startTable &+ Int(fields[index])) != 0 assert(isOkay, "Flatbuffers requires the following field") } } @@ -249,7 +264,8 @@ public struct FlatBufferBuilder { /// /// - Parameter startOffset:Start point of the object written /// - returns: The root of the table - mutating public func endTable(at startOffset: UOffset) -> UOffset { + @inline(__always) + mutating public func endTable(at startOffset: UOffset) -> UOffset { assert(isNested, "Calling endtable without calling starttable") let sizeofVoffset = MemoryLayout.size let vTableOffset = push(element: SOffset(0)) @@ -313,7 +329,7 @@ public struct FlatBufferBuilder { /// Asserts to see if the object is not nested @inline(__always) @usableFromInline - mutating internal func notNested() { + mutating internal func notNested() { assert(!isNested, "Object serialization must not be nested") } @@ -337,7 +353,7 @@ public struct FlatBufferBuilder { bufSize: UInt32, elementSize: UInt32) -> UInt32 { - ((~bufSize) &+ 1) & (elementSize - 1) + ((~bufSize) &+ 1) & (elementSize &- 1) } /// Prealigns the buffer before writting a new object into the buffer @@ -348,9 +364,11 @@ public struct FlatBufferBuilder { @usableFromInline mutating internal func preAlign(len: Int, alignment: Int) { minAlignment(size: alignment) - _bb.fill(padding: Int(padding( - bufSize: _bb.size &+ UOffset(len), - elementSize: UOffset(alignment)))) + _bb.fill( + padding: Int( + padding( + bufSize: _bb.size &+ UOffset(len), + elementSize: UOffset(alignment)))) } /// Prealigns the buffer before writting a new object into the buffer @@ -478,10 +496,11 @@ public struct FlatBufferBuilder { /// - Parameter bytes: bytes to be written into the buffer /// - Returns: ``Offset`` of the vector mutating public func createVector(bytes: ContiguousBytes) -> Offset { - let size = bytes.withUnsafeBytes { ptr in ptr.count } - startVector(size, elementSize: MemoryLayout.size) - _bb.push(bytes: bytes) - return endVector(len: size) + bytes.withUnsafeBytes { + startVector($0.count, elementSize: MemoryLayout.size) + _bb.push(bytes: $0) + return endVector(len: $0.count) + } } #endif @@ -822,6 +841,10 @@ public struct FlatBufferBuilder { return _bb.size } + @inline(__always) + public func read(def: T.Type, position: Int) -> T { + _bb.read(def: def, position: position) + } } extension FlatBufferBuilder: CustomDebugStringConvertible { diff --git a/swift/Sources/FlatBuffers/Message.swift b/swift/Sources/FlatBuffers/Message.swift index 8ccfca418..28436a2be 100644 --- a/swift/Sources/FlatBuffers/Message.swift +++ b/swift/Sources/FlatBuffers/Message.swift @@ -19,14 +19,16 @@ import Foundation /// FlatBufferGRPCMessage protocol that should allow us to invoke /// initializers directly from the GRPC generated code public protocol FlatBufferGRPCMessage { - - /// Raw pointer which would be pointing to the beginning of the readable bytes - var rawPointer: UnsafeMutableRawPointer { get } - /// Size of readable bytes in the buffer var size: Int { get } init(byteBuffer: ByteBuffer) + + @discardableResult + @inline(__always) + func withUnsafeReadableBytes( + _ body: (UnsafeRawBufferPointer) throws + -> T) rethrows -> T } /// Message is a wrapper around Buffers to to able to send Flatbuffers `Buffers` through the @@ -38,13 +40,10 @@ public struct Message: FlatBufferGRPCMessage { public var object: T { T.init( buffer, - o: Int32(buffer.read(def: UOffset.self, position: buffer.reader)) + + o: Int32(buffer.read(def: UOffset.self, position: buffer.reader)) &+ Int32(buffer.reader)) } - public var rawPointer: UnsafeMutableRawPointer { - buffer.memory.advanced(by: buffer.reader) } - public var size: Int { Int(buffer.size) } /// Initializes the message with the type Flatbuffer.Bytebuffer that is transmitted over @@ -62,4 +61,15 @@ public struct Message: FlatBufferGRPCMessage { buffer = builder.sizedBuffer builder.clear() } + + @discardableResult + @inline(__always) + public func withUnsafeReadableBytes( + _ body: (UnsafeRawBufferPointer) throws + -> Data) rethrows -> Data + { + return try buffer.readWithUnsafeRawPointer(position: buffer.reader) { + try body(UnsafeRawBufferPointer(start: $0, count: size)) + } + } } diff --git a/swift/Sources/FlatBuffers/Root.swift b/swift/Sources/FlatBuffers/Root.swift index 8e606e6cc..a725f1eb7 100644 --- a/swift/Sources/FlatBuffers/Root.swift +++ b/swift/Sources/FlatBuffers/Root.swift @@ -101,7 +101,7 @@ public func getCheckedRoot( try ForwardOffset.verify(&verifier, at: 0, of: T.self) return T.init( byteBuffer, - o: Int32(byteBuffer.read(def: UOffset.self, position: byteBuffer.reader)) + + o: Int32(byteBuffer.read(def: UOffset.self, position: byteBuffer.reader)) &+ Int32(byteBuffer.reader)) } @@ -111,6 +111,6 @@ public func getCheckedRoot( public func getRoot(byteBuffer: inout ByteBuffer) -> T { T.init( byteBuffer, - o: Int32(byteBuffer.read(def: UOffset.self, position: byteBuffer.reader)) + + o: Int32(byteBuffer.read(def: UOffset.self, position: byteBuffer.reader)) &+ Int32(byteBuffer.reader)) } diff --git a/swift/Sources/FlatBuffers/String+extension.swift b/swift/Sources/FlatBuffers/String+extension.swift index de4f5f91f..1a2df142c 100644 --- a/swift/Sources/FlatBuffers/String+extension.swift +++ b/swift/Sources/FlatBuffers/String+extension.swift @@ -64,7 +64,7 @@ extension String: FlatbuffersInitializable { let v = Int(o) let count = bb.read(def: Int32.self, position: v) self = bb.readString( - at: MemoryLayout.size + v, + at: MemoryLayout.size &+ v, count: Int(count)) ?? "" } } diff --git a/swift/Sources/FlatBuffers/Table.swift b/swift/Sources/FlatBuffers/Table.swift index 02a2e6f2c..b3be4d173 100644 --- a/swift/Sources/FlatBuffers/Table.swift +++ b/swift/Sources/FlatBuffers/Table.swift @@ -46,11 +46,11 @@ public struct Table { /// - Parameter o: current offset /// - Returns: offset of field within buffer public func offset(_ o: Int32) -> Int32 { - let vtable = position - bb.read(def: Int32.self, position: Int(position)) + let vtable = position &- bb.read(def: Int32.self, position: Int(position)) return o < bb .read(def: VOffset.self, position: Int(vtable)) ? Int32(bb.read( def: Int16.self, - position: Int(vtable + o))) : 0 + position: Int(vtable &+ o))) : 0 } /// Gets the indirect offset of the current stored object @@ -58,13 +58,13 @@ public struct Table { /// - Parameter o: current offset /// - Returns: offset of field within buffer public func indirect(_ o: Int32) -> Int32 { - o + bb.read(def: Int32.self, position: Int(o)) + o &+ bb.read(def: Int32.self, position: Int(o)) } /// String reads from the buffer with respect to position of the current table. /// - Parameter offset: Offset of the string public func string(at offset: Int32) -> String? { - directString(at: offset + position) + directString(at: offset &+ position) } /// Direct string reads from the buffer disregarding the position of the table. @@ -73,9 +73,9 @@ public struct Table { /// - Parameter offset: Offset of the string public func directString(at offset: Int32) -> String? { var offset = offset - offset += bb.read(def: Int32.self, position: Int(offset)) + offset &+= bb.read(def: Int32.self, position: Int(offset)) let count = bb.read(def: Int32.self, position: Int(offset)) - let position = Int(offset) + MemoryLayout.size + let position = Int(offset) &+ MemoryLayout.size return bb.readString(at: position, count: Int(count)) } @@ -84,7 +84,7 @@ public struct Table { /// - type: Type of Element that needs to be read from the buffer /// - o: Offset of the Element public func readBuffer(of type: T.Type, at o: Int32) -> T { - directRead(of: T.self, offset: o + position) + directRead(of: T.self, offset: o &+ position) } /// Reads from the buffer disregarding the position of the table. @@ -101,8 +101,7 @@ public struct Table { /// - type: Type of Element that needs to be read from the buffer /// - o: Offset of the Element public func directRead(of type: T.Type, offset o: Int32) -> T { - let r = bb.read(def: T.self, position: Int(o)) - return r + bb.read(def: T.self, position: Int(o)) } /// Returns that current `Union` object at a specific offset @@ -110,7 +109,7 @@ public struct Table { /// - Parameter o: offset /// - Returns: A flatbuffers object public func union(_ o: Int32) -> T { - let o = o + position + let o = o &+ position return directUnion(o) } @@ -118,7 +117,7 @@ public struct Table { /// - Parameter o: offset /// - Returns: A flatbuffers object public func directUnion(_ o: Int32) -> T { - T.init(bb, o: o + bb.read(def: Int32.self, position: Int(o))) + T.init(bb, o: o &+ bb.read(def: Int32.self, position: Int(o))) } /// Returns a vector of type T at a specific offset @@ -131,13 +130,30 @@ public struct Table { return bb.readSlice(index: Int(vector(at: o)), count: Int(vector(count: o))) } + /// Returns the underlying pointer to a vector within the buffer + /// This should only be used by `Scalars` + /// - Parameter off: Readable offset + /// - Returns: Returns a pointer to the underlying data + @inline(__always) + public func withUnsafePointerToSlice( + at off: Int32, + body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? + { + let o = offset(off) + guard o != 0 else { return nil } + return try bb.withUnsafePointerToSlice( + index: Int(vector(at: o)), + count: Int(vector(count: o)), + body: body) + } + /// Vector count gets the count of Elements within the array /// - Parameter o: start offset of the vector /// - returns: Count of elements public func vector(count o: Int32) -> Int32 { var o = o - o += position - o += bb.read(def: Int32.self, position: Int(o)) + o &+= position + o &+= bb.read(def: Int32.self, position: Int(o)) return bb.read(def: Int32.self, position: Int(o)) } @@ -146,8 +162,8 @@ public struct Table { /// - returns: the start index of the vector public func vector(at o: Int32) -> Int32 { var o = o - o += position - return o + bb.read(def: Int32.self, position: Int(o)) + 4 + o &+= position + return o &+ bb.read(def: Int32.self, position: Int(o)) + 4 } /// Reading an indirect offset of a table. @@ -165,15 +181,16 @@ public struct Table { /// - vOffset: Field offset within a vtable /// - fbb: ByteBuffer /// - Returns: an position of a field + @inline(__always) static public func offset( _ o: Int32, vOffset: Int32, - fbb: ByteBuffer) -> Int32 + fbb: inout FlatBufferBuilder) -> Int32 { - let vTable = Int32(fbb.capacity) - o - return vTable + Int32(fbb.read( + let vTable = Int32(fbb.capacity) &- o + return vTable &+ Int32(fbb.read( def: Int16.self, - position: Int(vTable + vOffset - fbb.read( + position: Int(vTable &+ vOffset &- fbb.read( def: Int32.self, position: Int(vTable))))) } @@ -184,27 +201,28 @@ public struct Table { /// - off2: second offset to compare /// - fbb: Bytebuffer /// - Returns: returns the difference between + @inline(__always) static public func compare( _ off1: Int32, _ off2: Int32, - fbb: ByteBuffer) -> Int32 + fbb: inout FlatBufferBuilder) -> Int32 { let memorySize = Int32(MemoryLayout.size) - let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1)) - let _off2 = off2 + fbb.read(def: Int32.self, position: Int(off2)) + let _off1 = off1 &+ fbb.read(def: Int32.self, position: Int(off1)) + let _off2 = off2 &+ fbb.read(def: Int32.self, position: Int(off2)) let len1 = fbb.read(def: Int32.self, position: Int(_off1)) let len2 = fbb.read(def: Int32.self, position: Int(_off2)) - let startPos1 = _off1 + memorySize - let startPos2 = _off2 + memorySize + let startPos1 = _off1 &+ memorySize + let startPos2 = _off2 &+ memorySize let minValue = min(len1, len2) for i in 0...minValue { - let b1 = fbb.read(def: Int8.self, position: Int(i + startPos1)) - let b2 = fbb.read(def: Int8.self, position: Int(i + startPos2)) + let b1 = fbb.read(def: Int8.self, position: Int(i &+ startPos1)) + let b2 = fbb.read(def: Int8.self, position: Int(i &+ startPos2)) if b1 != b2 { - return Int32(b2 - b1) + return Int32(b2 &- b1) } } - return len1 - len2 + return len1 &- len2 } /// Compares two objects at offset A and array of `Bytes` within a ByteBuffer @@ -213,24 +231,103 @@ public struct Table { /// - key: bytes array to compare to /// - fbb: Bytebuffer /// - Returns: returns the difference between + @inline(__always) + static public func compare( + _ off1: Int32, + _ key: [Byte], + fbb: inout FlatBufferBuilder) -> Int32 + { + let memorySize = Int32(MemoryLayout.size) + let _off1 = off1 &+ fbb.read(def: Int32.self, position: Int(off1)) + let len1 = fbb.read(def: Int32.self, position: Int(_off1)) + let len2 = Int32(key.count) + let startPos1 = _off1 &+ memorySize + let minValue = min(len1, len2) + for i in 0.. Int32 + { + let vTable = Int32(fbb.capacity) &- o + return vTable &+ Int32(fbb.read( + def: Int16.self, + position: Int(vTable &+ vOffset &- fbb.read( + def: Int32.self, + position: Int(vTable))))) + } + + /// Compares two objects at offset A and offset B within a ByteBuffer + /// - Parameters: + /// - off1: first offset to compare + /// - off2: second offset to compare + /// - fbb: Bytebuffer + /// - Returns: returns the difference between + @inline(__always) + static public func compare( + _ off1: Int32, + _ off2: Int32, + fbb: ByteBuffer) -> Int32 + { + let memorySize = Int32(MemoryLayout.size) + let _off1 = off1 &+ fbb.read(def: Int32.self, position: Int(off1)) + let _off2 = off2 &+ fbb.read(def: Int32.self, position: Int(off2)) + let len1 = fbb.read(def: Int32.self, position: Int(_off1)) + let len2 = fbb.read(def: Int32.self, position: Int(_off2)) + let startPos1 = _off1 &+ memorySize + let startPos2 = _off2 &+ memorySize + let minValue = min(len1, len2) + for i in 0...minValue { + let b1 = fbb.read(def: Int8.self, position: Int(i &+ startPos1)) + let b2 = fbb.read(def: Int8.self, position: Int(i &+ startPos2)) + if b1 != b2 { + return Int32(b2 &- b1) + } + } + return len1 &- len2 + } + + /// Compares two objects at offset A and array of `Bytes` within a ByteBuffer + /// - Parameters: + /// - off1: Offset to compare to + /// - key: bytes array to compare to + /// - fbb: Bytebuffer + /// - Returns: returns the difference between + @inline(__always) static public func compare( _ off1: Int32, _ key: [Byte], fbb: ByteBuffer) -> Int32 { let memorySize = Int32(MemoryLayout.size) - let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1)) + let _off1 = off1 &+ fbb.read(def: Int32.self, position: Int(off1)) let len1 = fbb.read(def: Int32.self, position: Int(_off1)) let len2 = Int32(key.count) - let startPos1 = _off1 + memorySize + let startPos1 = _off1 &+ memorySize let minValue = min(len1, len2) for i in 0.. where S: UnionEnum { while count < keysRange.count { /// index of readable enum value in array - let keysIndex = MemoryLayout.size * count + let keysIndex = MemoryLayout.size &* count guard let _enum = try S.init(value: verifier._buffer.read( def: S.T.self, - position: keysRange.start + keysIndex)) else + position: keysRange.start &+ keysIndex)) else { throw FlatbuffersErrors.unknownUnionCase } /// index of readable offset value in array - let fieldIndex = MemoryLayout.size * count - try completion(&verifier, _enum, offsetsRange.start + fieldIndex) - count += 1 + let fieldIndex = MemoryLayout.size &* count + try completion(&verifier, _enum, offsetsRange.start &+ fieldIndex) + count &+= 1 } } } diff --git a/swift/Sources/FlatBuffers/Verifier.swift b/swift/Sources/FlatBuffers/Verifier.swift index 0d52ccd8a..6f94f94c7 100644 --- a/swift/Sources/FlatBuffers/Verifier.swift +++ b/swift/Sources/FlatBuffers/Verifier.swift @@ -83,15 +83,18 @@ public struct Verifier { if !_checkAlignment { return } /// advance pointer to position X - let ptr = _buffer._storage.memory.advanced(by: position) - /// Check if the pointer is aligned - if Int(bitPattern: ptr) & (MemoryLayout.alignment &- 1) == 0 { - return - } + try _buffer.withUnsafeBytes { pointer in + let ptr = pointer.baseAddress!.advanced(by: position) - throw FlatbuffersErrors.missAlignedPointer( - position: position, - type: String(describing: T.self)) + /// Check if the pointer is aligned + if Int(bitPattern: ptr) & (MemoryLayout.alignment &- 1) == 0 { + return + } + + throw FlatbuffersErrors.missAlignedPointer( + position: position, + type: String(describing: T.self)) + } } /// Checks if the value of Size "X" is within the range of the buffer @@ -134,17 +137,17 @@ public struct Verifier { let length = Int(vtableLength) try isAligned( - position: Int(clamping: (vtablePosition + length).magnitude), + position: Int(clamping: (vtablePosition &+ length).magnitude), type: VOffset.self) try rangeInBuffer(position: vtablePosition, size: length) - storage.tableCount += 1 + storage.tableCount &+= 1 if storage.tableCount > _options._maxTableCount { throw FlatbuffersErrors.maximumTables } - storage.depth += 1 + storage.depth &+= 1 if storage.depth > _options._maxDepth { throw FlatbuffersErrors.maximumDepth @@ -211,7 +214,7 @@ public struct Verifier { @inline(__always) func verify(id: String) throws { let size = MemoryLayout.size - guard storage.capacity >= (size * 2) else { + guard storage.capacity >= (size &* 2) else { throw FlatbuffersErrors.bufferDoesntContainID } let str = _buffer.readString(at: size, count: size) diff --git a/swift/Sources/FlatBuffers/_InternalByteBuffer.swift b/swift/Sources/FlatBuffers/_InternalByteBuffer.swift new file mode 100644 index 000000000..74e828570 --- /dev/null +++ b/swift/Sources/FlatBuffers/_InternalByteBuffer.swift @@ -0,0 +1,365 @@ +/* + * Copyright 2024 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Foundation + +/// `ByteBuffer` is the interface that stores the data for a `Flatbuffers` object +/// it allows users to Construct their buffers internally without much cost to performance +@usableFromInline +struct _InternalByteBuffer { + + /// 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 { + // This storage doesn't own the memory, therefore, we won't deallocate on deinit. + private let unowned: Bool + /// pointer to the start of the buffer object in memory + var memory: UnsafeMutableRawPointer + /// Capacity of UInt8 the buffer can hold + var capacity: Int + + @usableFromInline + init(count: Int, alignment: Int) { + memory = UnsafeMutableRawPointer.allocate( + byteCount: count, + alignment: alignment) + capacity = count + unowned = false + } + + deinit { + if !unowned { + memory.deallocate() + } + } + + @usableFromInline + func initialize(for size: Int) { + assert( + !unowned, + "initalize should NOT be called on a buffer that is built by assumingMemoryBound") + memset(memory, 0, size) + } + + /// Reallocates the buffer incase the object to be written doesnt fit in the current buffer + /// - Parameter size: Size of the current object + @usableFromInline + func reallocate(_ size: Int, writerSize: Int, alignment: Int) { + let currentWritingIndex = capacity &- writerSize + while capacity <= writerSize &+ size { + capacity = capacity << 1 + } + + /// solution take from Apple-NIO + capacity = capacity.convertToPowerofTwo + + let newData = UnsafeMutableRawPointer.allocate( + byteCount: capacity, + alignment: alignment) + memset(newData, 0, capacity &- writerSize) + memcpy( + newData.advanced(by: capacity &- writerSize), + memory.advanced(by: currentWritingIndex), + writerSize) + memory.deallocate() + memory = newData + } + } + + @usableFromInline var _storage: Storage + + /// The size of the elements written to the buffer + their paddings + private var _writerSize: Int = 0 + /// Alignment of the current memory being written to the buffer + 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 + var writerIndex: Int { _storage.capacity &- _writerSize } + + /// Reader is the position of the current Writer Index (capacity - size) + public var reader: Int { writerIndex } + /// Current size of the buffer + public var size: UOffset { UOffset(_writerSize) } + /// Public Pointer to the buffer object in memory. This should NOT be modified for any reason + @usableFromInline + var memory: UnsafeMutableRawPointer { _storage.memory } + /// Current capacity for the buffer + public var capacity: Int { _storage.capacity } + + /// Constructor that creates a Flatbuffer instance with a size + /// - Parameter: + /// - size: Length of the buffer + /// - allowReadingUnalignedBuffers: allow reading from unaligned buffer + init(initialSize size: Int) { + let size = size.convertToPowerofTwo + _storage = Storage(count: size, alignment: alignment) + _storage.initialize(for: size) + } + + /// Fills the buffer with padding by adding to the writersize + /// - Parameter padding: Amount of padding between two to be serialized objects + @inline(__always) + @usableFromInline + mutating func fill(padding: Int) { + assert(padding >= 0, "Fill should be larger than or equal to zero") + ensureSpace(size: padding) + _writerSize = _writerSize &+ (MemoryLayout.size &* padding) + } + + /// Adds an array of type Scalar to the buffer memory + /// - Parameter elements: An array of Scalars + @inline(__always) + @usableFromInline + mutating func push(elements: [T]) { + elements.withUnsafeBytes { ptr in + ensureSpace(size: ptr.count) + memcpy( + _storage.memory.advanced(by: writerIndex &- ptr.count), + ptr.baseAddress!, + ptr.count) + _writerSize = _writerSize &+ ptr.count + } + } + + /// Adds an array of type Scalar to the buffer memory + /// - Parameter elements: An array of Scalars + @inline(__always) + @usableFromInline + mutating func push(elements: [T]) { + elements.withUnsafeBytes { ptr in + ensureSpace(size: ptr.count) + memcpy( + _storage.memory.advanced(by: writerIndex &- ptr.count), + ptr.baseAddress!, + ptr.count) + _writerSize = _writerSize &+ ptr.count + } + } + + /// Adds a `ContiguousBytes` to buffer memory + /// - Parameter value: bytes to copy + #if swift(>=5.0) && !os(WASI) + @inline(__always) + @usableFromInline + mutating func push(bytes: ContiguousBytes) { + bytes.withUnsafeBytes { ptr in + ensureSpace(size: ptr.count) + memcpy( + _storage.memory.advanced(by: writerIndex &- ptr.count), + ptr.baseAddress!, + ptr.count) + _writerSize = _writerSize &+ ptr.count + } + } + #endif + + /// Adds an object of type NativeStruct into the buffer + /// - Parameters: + /// - value: Object that will be written to the buffer + /// - size: size to subtract from the WriterIndex + @usableFromInline + @inline(__always) + mutating func push(struct value: T, size: Int) { + ensureSpace(size: size) + withUnsafePointer(to: value) { + memcpy( + _storage.memory.advanced(by: writerIndex &- size), + $0, + size) + _writerSize = _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 + @inline(__always) + @usableFromInline + mutating func push(value: T, len: Int) { + ensureSpace(size: len) + withUnsafePointer(to: value) { + memcpy( + _storage.memory.advanced(by: writerIndex &- len), + $0, + len) + _writerSize = _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 + @inline(__always) + @usableFromInline + mutating func push(string str: String, len: Int) { + ensureSpace(size: len) + if str.utf8 + .withContiguousStorageIfAvailable({ self.push(bytes: $0, len: len) }) != + nil + { + } else { + let utf8View = str.utf8 + for c in utf8View.reversed() { + push(value: c, len: 1) + } + } + } + + /// Writes a string to Bytebuffer using UTF8View + /// - Parameters: + /// - bytes: Pointer to the view + /// - len: Size of string + @usableFromInline + @inline(__always) + mutating func push( + bytes: UnsafeBufferPointer, + len: Int) -> Bool + { + memcpy( + _storage.memory.advanced(by: writerIndex &- len), + bytes.baseAddress!, + len) + _writerSize = _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 + /// indirect: takes into respect the current capacity of the buffer (capacity - index), writing to the buffer from the end + /// - Parameters: + /// - value: Value that needs to be written to the buffer + /// - index: index to write to + /// - direct: Should take into consideration the capacity of the buffer + @inline(__always) + func write(value: T, index: Int, direct: Bool = false) { + var index = index + if !direct { + index = _storage.capacity &- index + } + assert(index < _storage.capacity, "Write index is out of writing bound") + assert(index >= 0, "Writer index should be above zero") + _ = 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 + /// - Parameter size: size of object + @discardableResult + @usableFromInline + @inline(__always) + mutating func ensureSpace(size: Int) -> Int { + if size &+ _writerSize > _storage.capacity { + _storage.reallocate(size, writerSize: _writerSize, alignment: alignment) + } + assert(size < FlatBufferMaxSize, "Buffer can't grow beyond 2 Gigabytes") + return size + } + + /// pops the written VTable if it's already written into the buffer + /// - Parameter size: size of the `VTable` + @usableFromInline + @inline(__always) + mutating func pop(_ size: Int) { + assert( + (_writerSize &- size) > 0, + "New size should NOT be a negative number") + memset(_storage.memory.advanced(by: writerIndex), 0, _writerSize &- size) + _writerSize = size + } + + /// Clears the current size of the buffer + @inline(__always) + mutating public func clearSize() { + _writerSize = 0 + } + + /// Clears the current instance of the buffer, replacing it with new memory + @inline(__always) + mutating public func clear() { + _writerSize = 0 + alignment = 1 + _storage.initialize(for: _storage.capacity) + } + + /// Reads an object from the buffer + /// - Parameters: + /// - def: Type of the object + /// - position: the index of the object in the buffer + @inline(__always) + public func read(def: T.Type, position: Int) -> T { + _storage.memory + .advanced(by: position) + .bindMemory(to: T.self, capacity: 1) + .pointee + } + + @discardableResult + @inline(__always) + func withUnsafeBytes( + _ body: (UnsafeRawBufferPointer) throws + -> T) rethrows -> T + { + try body(UnsafeRawBufferPointer( + start: _storage.memory, + count: capacity)) + } + + @discardableResult + @inline(__always) + func withUnsafeSlicedBytes( + _ body: (UnsafeRawBufferPointer) throws + -> T) rethrows -> T + { + try body(UnsafeRawBufferPointer( + start: _storage.memory.advanced(by: writerIndex), + count: capacity &- writerIndex)) + } + + @discardableResult + @inline(__always) + func withUnsafeRawPointer( + _ body: (UnsafeMutableRawPointer) throws + -> T) rethrows -> T + { + try body(_storage.memory) + } + + @discardableResult + @inline(__always) + func readWithUnsafeRawPointer( + position: Int, + _ body: (UnsafeRawPointer) throws -> T) rethrows -> T + { + try body(_storage.memory.advanced(by: position)) + } +} + +extension _InternalByteBuffer: CustomDebugStringConvertible { + + public var debugDescription: String { + """ + buffer located at: \(_storage.memory), with capacity of \(_storage.capacity) + { writerSize: \(_writerSize), readerSize: \(reader), writerIndex: \( + writerIndex) } + """ + } +} diff --git a/tests/swift/Wasm.tests/Tests/FlatBuffers.Test.Swift.WasmTests/monster_test_generated.swift b/tests/swift/Wasm.tests/Tests/FlatBuffers.Test.Swift.WasmTests/monster_test_generated.swift index 476854444..94ecac147 100644 --- a/tests/swift/Wasm.tests/Tests/FlatBuffers.Test.Swift.WasmTests/monster_test_generated.swift +++ b/tests/swift/Wasm.tests/Tests/FlatBuffers.Test.Swift.WasmTests/monster_test_generated.swift @@ -906,7 +906,7 @@ public struct MyGame_Example_Stat: FlatBufferObject, Verifiable, ObjectAPIPacker } public static func sortVectorOfStat(offsets:[Offset], _ fbb: inout FlatBufferBuilder) -> Offset { var off = offsets - off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 8, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: 8, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } + off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 8, fbb: &fbb), Table.offset(Int32($0.o), vOffset: 8, fbb: &fbb), fbb: &fbb) < 0 } return fbb.createVector(ofOffsets: off) } fileprivate static func lookupByKey(vector: Int32, key: UInt16, fbb: ByteBuffer) -> MyGame_Example_Stat? { @@ -1033,7 +1033,7 @@ public struct MyGame_Example_Referrable: FlatBufferObject, Verifiable, ObjectAPI } public static func sortVectorOfReferrable(offsets:[Offset], _ fbb: inout FlatBufferBuilder) -> Offset { var off = offsets - off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 4, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: 4, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } + off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 4, fbb: &fbb), Table.offset(Int32($0.o), vOffset: 4, fbb: &fbb), fbb: &fbb) < 0 } return fbb.createVector(ofOffsets: off) } fileprivate static func lookupByKey(vector: Int32, key: UInt64, fbb: ByteBuffer) -> MyGame_Example_Referrable? { @@ -1197,6 +1197,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public func inventory(at index: Int32) -> UInt8 { let o = _accessor.offset(VTOFFSET.inventory.v); return o == 0 ? 0 : _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1) } public var inventory: [UInt8] { return _accessor.getVector(at: VTOFFSET.inventory.v) ?? [] } public func mutate(inventory: UInt8, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.inventory.v); return _accessor.directMutate(inventory, index: _accessor.vector(at: o) + index * 1) } + public func withUnsafePointerToInventory(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.inventory.v, body: body) } public var color: MyGame_Example_Color { let o = _accessor.offset(VTOFFSET.color.v); return o == 0 ? .blue : MyGame_Example_Color(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? .blue } @discardableResult public func mutate(color: MyGame_Example_Color) -> Bool {let o = _accessor.offset(VTOFFSET.color.v); return _accessor.mutate(color.rawValue, index: o) } public var testType: MyGame_Example_Any_ { let o = _accessor.offset(VTOFFSET.testType.v); return o == 0 ? .none_ : MyGame_Example_Any_(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? .none_ } @@ -1205,6 +1206,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public var test4Count: Int32 { let o = _accessor.offset(VTOFFSET.test4.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func test4(at index: Int32) -> MyGame_Example_Test? { let o = _accessor.offset(VTOFFSET.test4.v); return o == 0 ? nil : _accessor.directRead(of: MyGame_Example_Test.self, offset: _accessor.vector(at: o) + index * 4) } public func mutableTest4(at index: Int32) -> MyGame_Example_Test_Mutable? { let o = _accessor.offset(VTOFFSET.test4.v); return o == 0 ? nil : MyGame_Example_Test_Mutable(_accessor.bb, o: _accessor.vector(at: o) + index * 4) } + public func withUnsafePointerToTest4(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.test4.v, body: body) } public var hasTestarrayofstring: Bool { let o = _accessor.offset(VTOFFSET.testarrayofstring.v); return o == 0 ? false : true } public var testarrayofstringCount: Int32 { let o = _accessor.offset(VTOFFSET.testarrayofstring.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func testarrayofstring(at index: Int32) -> String? { let o = _accessor.offset(VTOFFSET.testarrayofstring.v); return o == 0 ? nil : _accessor.directString(at: _accessor.vector(at: o) + index * 4) } @@ -1220,6 +1222,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public func testnestedflatbuffer(at index: Int32) -> UInt8 { let o = _accessor.offset(VTOFFSET.testnestedflatbuffer.v); return o == 0 ? 0 : _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1) } public var testnestedflatbuffer: [UInt8] { return _accessor.getVector(at: VTOFFSET.testnestedflatbuffer.v) ?? [] } public func mutate(testnestedflatbuffer: UInt8, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.testnestedflatbuffer.v); return _accessor.directMutate(testnestedflatbuffer, index: _accessor.vector(at: o) + index * 1) } + public func withUnsafePointerToTestnestedflatbuffer(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.testnestedflatbuffer.v, body: body) } public var testempty: MyGame_Example_Stat? { let o = _accessor.offset(VTOFFSET.testempty.v); return o == 0 ? nil : MyGame_Example_Stat(_accessor.bb, o: _accessor.indirect(o + _accessor.position)) } public var testbool: Bool { let o = _accessor.offset(VTOFFSET.testbool.v); return o == 0 ? false : _accessor.readBuffer(of: Bool.self, at: o) } @discardableResult public func mutate(testbool: Bool) -> Bool {let o = _accessor.offset(VTOFFSET.testbool.v); return _accessor.mutate(testbool, index: o) } @@ -1244,6 +1247,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public func testarrayofbools(at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.testarrayofbools.v); return o == 0 ? true : _accessor.directRead(of: Bool.self, offset: _accessor.vector(at: o) + index * 1) } public var testarrayofbools: [Bool] { return _accessor.getVector(at: VTOFFSET.testarrayofbools.v) ?? [] } public func mutate(testarrayofbools: Bool, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.testarrayofbools.v); return _accessor.directMutate(testarrayofbools, index: _accessor.vector(at: o) + index * 1) } + public func withUnsafePointerToTestarrayofbools(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.testarrayofbools.v, body: body) } public var testf: Float32 { let o = _accessor.offset(VTOFFSET.testf.v); return o == 0 ? 3.14159 : _accessor.readBuffer(of: Float32.self, at: o) } @discardableResult public func mutate(testf: Float32) -> Bool {let o = _accessor.offset(VTOFFSET.testf.v); return _accessor.mutate(testf, index: o) } public var testf2: Float32 { let o = _accessor.offset(VTOFFSET.testf2.v); return o == 0 ? 3.0 : _accessor.readBuffer(of: Float32.self, at: o) } @@ -1257,25 +1261,30 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public var testarrayofsortedstructCount: Int32 { let o = _accessor.offset(VTOFFSET.testarrayofsortedstruct.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func testarrayofsortedstruct(at index: Int32) -> MyGame_Example_Ability? { let o = _accessor.offset(VTOFFSET.testarrayofsortedstruct.v); return o == 0 ? nil : _accessor.directRead(of: MyGame_Example_Ability.self, offset: _accessor.vector(at: o) + index * 8) } public func mutableTestarrayofsortedstruct(at index: Int32) -> MyGame_Example_Ability_Mutable? { let o = _accessor.offset(VTOFFSET.testarrayofsortedstruct.v); return o == 0 ? nil : MyGame_Example_Ability_Mutable(_accessor.bb, o: _accessor.vector(at: o) + index * 8) } + public func withUnsafePointerToTestarrayofsortedstruct(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.testarrayofsortedstruct.v, body: body) } public var hasFlex: Bool { let o = _accessor.offset(VTOFFSET.flex.v); return o == 0 ? false : true } public var flexCount: Int32 { let o = _accessor.offset(VTOFFSET.flex.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func flex(at index: Int32) -> UInt8 { let o = _accessor.offset(VTOFFSET.flex.v); return o == 0 ? 0 : _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1) } public var flex: [UInt8] { return _accessor.getVector(at: VTOFFSET.flex.v) ?? [] } public func mutate(flex: UInt8, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.flex.v); return _accessor.directMutate(flex, index: _accessor.vector(at: o) + index * 1) } + public func withUnsafePointerToFlex(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.flex.v, body: body) } public var hasTest5: Bool { let o = _accessor.offset(VTOFFSET.test5.v); return o == 0 ? false : true } public var test5Count: Int32 { let o = _accessor.offset(VTOFFSET.test5.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func test5(at index: Int32) -> MyGame_Example_Test? { let o = _accessor.offset(VTOFFSET.test5.v); return o == 0 ? nil : _accessor.directRead(of: MyGame_Example_Test.self, offset: _accessor.vector(at: o) + index * 4) } public func mutableTest5(at index: Int32) -> MyGame_Example_Test_Mutable? { let o = _accessor.offset(VTOFFSET.test5.v); return o == 0 ? nil : MyGame_Example_Test_Mutable(_accessor.bb, o: _accessor.vector(at: o) + index * 4) } + public func withUnsafePointerToTest5(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.test5.v, body: body) } public var hasVectorOfLongs: Bool { let o = _accessor.offset(VTOFFSET.vectorOfLongs.v); return o == 0 ? false : true } public var vectorOfLongsCount: Int32 { let o = _accessor.offset(VTOFFSET.vectorOfLongs.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func vectorOfLongs(at index: Int32) -> Int64 { let o = _accessor.offset(VTOFFSET.vectorOfLongs.v); return o == 0 ? 0 : _accessor.directRead(of: Int64.self, offset: _accessor.vector(at: o) + index * 8) } public var vectorOfLongs: [Int64] { return _accessor.getVector(at: VTOFFSET.vectorOfLongs.v) ?? [] } public func mutate(vectorOfLongs: Int64, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.vectorOfLongs.v); return _accessor.directMutate(vectorOfLongs, index: _accessor.vector(at: o) + index * 8) } + public func withUnsafePointerToVectorOfLongs(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.vectorOfLongs.v, body: body) } public var hasVectorOfDoubles: Bool { let o = _accessor.offset(VTOFFSET.vectorOfDoubles.v); return o == 0 ? false : true } public var vectorOfDoublesCount: Int32 { let o = _accessor.offset(VTOFFSET.vectorOfDoubles.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func vectorOfDoubles(at index: Int32) -> Double { let o = _accessor.offset(VTOFFSET.vectorOfDoubles.v); return o == 0 ? 0 : _accessor.directRead(of: Double.self, offset: _accessor.vector(at: o) + index * 8) } public var vectorOfDoubles: [Double] { return _accessor.getVector(at: VTOFFSET.vectorOfDoubles.v) ?? [] } public func mutate(vectorOfDoubles: Double, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.vectorOfDoubles.v); return _accessor.directMutate(vectorOfDoubles, index: _accessor.vector(at: o) + index * 8) } + public func withUnsafePointerToVectorOfDoubles(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.vectorOfDoubles.v, body: body) } public var parentNamespaceTest: MyGame_InParentNamespace? { let o = _accessor.offset(VTOFFSET.parentNamespaceTest.v); return o == 0 ? nil : MyGame_InParentNamespace(_accessor.bb, o: _accessor.indirect(o + _accessor.position)) } public var hasVectorOfReferrables: Bool { let o = _accessor.offset(VTOFFSET.vectorOfReferrables.v); return o == 0 ? false : true } public var vectorOfReferrablesCount: Int32 { let o = _accessor.offset(VTOFFSET.vectorOfReferrables.v); return o == 0 ? 0 : _accessor.vector(count: o) } @@ -1288,6 +1297,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public func vectorOfWeakReferences(at index: Int32) -> UInt64 { let o = _accessor.offset(VTOFFSET.vectorOfWeakReferences.v); return o == 0 ? 0 : _accessor.directRead(of: UInt64.self, offset: _accessor.vector(at: o) + index * 8) } public var vectorOfWeakReferences: [UInt64] { return _accessor.getVector(at: VTOFFSET.vectorOfWeakReferences.v) ?? [] } public func mutate(vectorOfWeakReferences: UInt64, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.vectorOfWeakReferences.v); return _accessor.directMutate(vectorOfWeakReferences, index: _accessor.vector(at: o) + index * 8) } + public func withUnsafePointerToVectorOfWeakReferences(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.vectorOfWeakReferences.v, body: body) } public var hasVectorOfStrongReferrables: Bool { let o = _accessor.offset(VTOFFSET.vectorOfStrongReferrables.v); return o == 0 ? false : true } public var vectorOfStrongReferrablesCount: Int32 { let o = _accessor.offset(VTOFFSET.vectorOfStrongReferrables.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func vectorOfStrongReferrables(at index: Int32) -> MyGame_Example_Referrable? { let o = _accessor.offset(VTOFFSET.vectorOfStrongReferrables.v); return o == 0 ? nil : MyGame_Example_Referrable(_accessor.bb, o: _accessor.indirect(_accessor.vector(at: o) + index * 4)) } @@ -1299,6 +1309,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public func vectorOfCoOwningReferences(at index: Int32) -> UInt64 { let o = _accessor.offset(VTOFFSET.vectorOfCoOwningReferences.v); return o == 0 ? 0 : _accessor.directRead(of: UInt64.self, offset: _accessor.vector(at: o) + index * 8) } public var vectorOfCoOwningReferences: [UInt64] { return _accessor.getVector(at: VTOFFSET.vectorOfCoOwningReferences.v) ?? [] } public func mutate(vectorOfCoOwningReferences: UInt64, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.vectorOfCoOwningReferences.v); return _accessor.directMutate(vectorOfCoOwningReferences, index: _accessor.vector(at: o) + index * 8) } + public func withUnsafePointerToVectorOfCoOwningReferences(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.vectorOfCoOwningReferences.v, body: body) } public var nonOwningReference: UInt64 { let o = _accessor.offset(VTOFFSET.nonOwningReference.v); return o == 0 ? 0 : _accessor.readBuffer(of: UInt64.self, at: o) } @discardableResult public func mutate(nonOwningReference: UInt64) -> Bool {let o = _accessor.offset(VTOFFSET.nonOwningReference.v); return _accessor.mutate(nonOwningReference, index: o) } public var hasVectorOfNonOwningReferences: Bool { let o = _accessor.offset(VTOFFSET.vectorOfNonOwningReferences.v); return o == 0 ? false : true } @@ -1306,6 +1317,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public func vectorOfNonOwningReferences(at index: Int32) -> UInt64 { let o = _accessor.offset(VTOFFSET.vectorOfNonOwningReferences.v); return o == 0 ? 0 : _accessor.directRead(of: UInt64.self, offset: _accessor.vector(at: o) + index * 8) } public var vectorOfNonOwningReferences: [UInt64] { return _accessor.getVector(at: VTOFFSET.vectorOfNonOwningReferences.v) ?? [] } public func mutate(vectorOfNonOwningReferences: UInt64, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.vectorOfNonOwningReferences.v); return _accessor.directMutate(vectorOfNonOwningReferences, index: _accessor.vector(at: o) + index * 8) } + public func withUnsafePointerToVectorOfNonOwningReferences(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.vectorOfNonOwningReferences.v, body: body) } public var anyUniqueType: MyGame_Example_AnyUniqueAliases { let o = _accessor.offset(VTOFFSET.anyUniqueType.v); return o == 0 ? .none_ : MyGame_Example_AnyUniqueAliases(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? .none_ } public func anyUnique(type: T.Type) -> T? { let o = _accessor.offset(VTOFFSET.anyUnique.v); return o == 0 ? nil : _accessor.union(o) } public var anyAmbiguousType: MyGame_Example_AnyAmbiguousAliases { let o = _accessor.offset(VTOFFSET.anyAmbiguousType.v); return o == 0 ? .none_ : MyGame_Example_AnyAmbiguousAliases(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? .none_ } @@ -1320,6 +1332,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public func testrequirednestedflatbuffer(at index: Int32) -> UInt8 { let o = _accessor.offset(VTOFFSET.testrequirednestedflatbuffer.v); return o == 0 ? 0 : _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1) } public var testrequirednestedflatbuffer: [UInt8] { return _accessor.getVector(at: VTOFFSET.testrequirednestedflatbuffer.v) ?? [] } public func mutate(testrequirednestedflatbuffer: UInt8, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.testrequirednestedflatbuffer.v); return _accessor.directMutate(testrequirednestedflatbuffer, index: _accessor.vector(at: o) + index * 1) } + public func withUnsafePointerToTestrequirednestedflatbuffer(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.testrequirednestedflatbuffer.v, body: body) } public var hasScalarKeySortedTables: Bool { let o = _accessor.offset(VTOFFSET.scalarKeySortedTables.v); return o == 0 ? false : true } public var scalarKeySortedTablesCount: Int32 { let o = _accessor.offset(VTOFFSET.scalarKeySortedTables.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func scalarKeySortedTables(at index: Int32) -> MyGame_Example_Stat? { let o = _accessor.offset(VTOFFSET.scalarKeySortedTables.v); return o == 0 ? nil : MyGame_Example_Stat(_accessor.bb, o: _accessor.indirect(_accessor.vector(at: o) + index * 4)) } @@ -1549,7 +1562,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac } public static func sortVectorOfMonster(offsets:[Offset], _ fbb: inout FlatBufferBuilder) -> Offset { var off = offsets - off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 10, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: 10, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } + off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 10, fbb: &fbb), Table.offset(Int32($0.o), vOffset: 10, fbb: &fbb), fbb: &fbb) < 0 } return fbb.createVector(ofOffsets: off) } fileprivate static func lookupByKey(vector: Int32, key: String, fbb: ByteBuffer) -> MyGame_Example_Monster? { @@ -2456,11 +2469,13 @@ public struct MyGame_Example_TypeAliases: FlatBufferObject, Verifiable, ObjectAP public func v8(at index: Int32) -> Int8 { let o = _accessor.offset(VTOFFSET.v8.v); return o == 0 ? 0 : _accessor.directRead(of: Int8.self, offset: _accessor.vector(at: o) + index * 1) } public var v8: [Int8] { return _accessor.getVector(at: VTOFFSET.v8.v) ?? [] } public func mutate(v8: Int8, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.v8.v); return _accessor.directMutate(v8, index: _accessor.vector(at: o) + index * 1) } + public func withUnsafePointerToV8(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.v8.v, body: body) } public var hasVf64: Bool { let o = _accessor.offset(VTOFFSET.vf64.v); return o == 0 ? false : true } public var vf64Count: Int32 { let o = _accessor.offset(VTOFFSET.vf64.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func vf64(at index: Int32) -> Double { let o = _accessor.offset(VTOFFSET.vf64.v); return o == 0 ? 0 : _accessor.directRead(of: Double.self, offset: _accessor.vector(at: o) + index * 8) } public var vf64: [Double] { return _accessor.getVector(at: VTOFFSET.vf64.v) ?? [] } public func mutate(vf64: Double, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.vf64.v); return _accessor.directMutate(vf64, index: _accessor.vector(at: o) + index * 8) } + public func withUnsafePointerToVf64(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.vf64.v, body: body) } public static func startTypeAliases(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 12) } public static func add(i8: Int8, _ fbb: inout FlatBufferBuilder) { fbb.add(element: i8, def: 0, at: VTOFFSET.i8.p) } public static func add(u8: UInt8, _ fbb: inout FlatBufferBuilder) { fbb.add(element: u8, def: 0, at: VTOFFSET.u8.p) } diff --git a/tests/swift/tests/Sources/SwiftFlatBuffers/fuzzer_generated.swift b/tests/swift/tests/Sources/SwiftFlatBuffers/fuzzer_generated.swift index 9f716183a..65c548c85 100644 --- a/tests/swift/tests/Sources/SwiftFlatBuffers/fuzzer_generated.swift +++ b/tests/swift/tests/Sources/SwiftFlatBuffers/fuzzer_generated.swift @@ -228,6 +228,7 @@ public struct Monster: FlatBufferObject, Verifiable { public var inventoryCount: Int32 { let o = _accessor.offset(VTOFFSET.inventory.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func inventory(at index: Int32) -> UInt8 { let o = _accessor.offset(VTOFFSET.inventory.v); return o == 0 ? 0 : _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1) } public var inventory: [UInt8] { return _accessor.getVector(at: VTOFFSET.inventory.v) ?? [] } + public func withUnsafePointerToInventory(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.inventory.v, body: body) } public var color: Color { let o = _accessor.offset(VTOFFSET.color.v); return o == 0 ? .blue : Color(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? .blue } public static func startMonster(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 7) } public static func add(pos: Vec3?, _ fbb: inout FlatBufferBuilder) { guard let pos = pos else { return }; fbb.create(struct: pos, position: VTOFFSET.pos.p) } @@ -260,7 +261,7 @@ public struct Monster: FlatBufferObject, Verifiable { } public static func sortVectorOfMonster(offsets:[Offset], _ fbb: inout FlatBufferBuilder) -> Offset { var off = offsets - off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 10, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: 10, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } + off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 10, fbb: &fbb), Table.offset(Int32($0.o), vOffset: 10, fbb: &fbb), fbb: &fbb) < 0 } return fbb.createVector(ofOffsets: off) } fileprivate static func lookupByKey(vector: Int32, key: String, fbb: ByteBuffer) -> Monster? { diff --git a/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/ByteBufferTests.swift b/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/ByteBufferTests.swift new file mode 100644 index 000000000..3ddbeb85b --- /dev/null +++ b/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/ByteBufferTests.swift @@ -0,0 +1,131 @@ +/* + * Copyright 2024 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import XCTest +@testable import FlatBuffers + +final class ByteBufferTests: XCTestCase { + func testCopyingMemory() { + let count = 100 + let ptr = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: 1) + let byteBuffer = ByteBuffer(copyingMemoryBound: ptr, capacity: count) + byteBuffer.withUnsafeBytes { memory in + XCTAssertNotEqual(memory.baseAddress, ptr) + } + } + + func testSamePointer() { + let count = 100 + let ptr = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: 1) + let byteBuffer = ByteBuffer(assumingMemoryBound: ptr, capacity: count) + byteBuffer.withUnsafeBytes { memory in + XCTAssertEqual(memory.baseAddress!, ptr) + } + } + + func testSameDataPtr() { + let count = 100 + let ptr = Data(repeating: 0, count: count) + let byteBuffer = ByteBuffer(data: ptr) + byteBuffer.withUnsafeBytes { memory in + ptr.withUnsafeBytes { ptr in + XCTAssertEqual(memory.baseAddress!, ptr) + } + } + } + + func testSameArrayPtr() { + let count = 100 + let ptr: [UInt8] = Array(repeating: 0, count: count) + let byteBuffer = ByteBuffer(bytes: ptr) + ptr.withUnsafeBytes { ptr in + byteBuffer.withUnsafeBytes { memory in + XCTAssertEqual(memory.baseAddress, ptr.baseAddress) + } + } + } + + func testReadingDoubleBuffer() { + let count = 8 + let array: [Double] = Array(repeating: 8.8, count: count) + var oldBuffer = _InternalByteBuffer(initialSize: 16) + oldBuffer.push(elements: array) + let bytes: [Byte] = oldBuffer.withUnsafeBytes { bytes in + Array(bytes) + } + let byteBuffer = ByteBuffer(bytes: bytes) + byteBuffer.withUnsafePointerToSlice(index: 0, count: count) { ptr in + XCTAssertEqual(ptr.count, count) + bytes.withUnsafeBufferPointer { + XCTAssertEqual( + UnsafeRawPointer($0.baseAddress), + UnsafeRawPointer(ptr.baseAddress)) + } + } + } + + func testReadingNativeStructs() { + let array = [ + MyGame_Example_Vec3( + x: 3.2, + y: 3.2, + z: 3.2, + test1: 8, + test2: .red, + test3: MyGame_Example_Test(a: 8, b: 8)), + MyGame_Example_Vec3( + x: 3.2, + y: 3.2, + z: 3.2, + test1: 8, + test2: .green, + test3: MyGame_Example_Test(a: 16, b: 16)), + MyGame_Example_Vec3( + x: 3.2, + y: 3.2, + z: 3.2, + test1: 8, + test2: .blue, + test3: MyGame_Example_Test(a: 32, b: 32)), + ] + let count = array.count + var oldBuffer = _InternalByteBuffer(initialSize: 16) + oldBuffer.push(elements: array) + let bytes: [Byte] = oldBuffer.withUnsafeBytes { bytes in + Array(bytes) + } + let byteBuffer = ByteBuffer(bytes: bytes) + byteBuffer + .withUnsafePointerToSlice(index: 0, count: count) { bufferPointer in + XCTAssertEqual(bufferPointer.count, count) + bytes.withUnsafeBufferPointer { ptr in + XCTAssertEqual( + UnsafeRawPointer(ptr.baseAddress), + UnsafeRawPointer(bufferPointer.baseAddress)) + } + } + } +} + +private struct TestNativeStructs: NativeStruct { + let x: Double + let y: Double + let z: Int +} + +extension MyGame_Example_Color: CaseIterable { + public static var allCases: [MyGame_Example_Color] = [.red, .blue, .green] +} diff --git a/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersMonsterWriterTests.swift b/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersMonsterWriterTests.swift index ccd8200bc..65fce4840 100644 --- a/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersMonsterWriterTests.swift +++ b/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersMonsterWriterTests.swift @@ -39,6 +39,7 @@ class FlatBuffersMonsterWriterTests: XCTestCase { .appendingPathExtension("mon") let data = try! Data(contentsOf: url) let _data = ByteBuffer(data: data) + readVerifiedMonster(fb: _data) } @@ -48,6 +49,7 @@ class FlatBuffersMonsterWriterTests: XCTestCase { XCTAssertEqual(bytes.sizedByteArray, [48, 0, 0, 0, 77, 79, 78, 83, 0, 0, 0, 0, 36, 0, 72, 0, 40, 0, 0, 0, 38, 0, 32, 0, 0, 0, 28, 0, 0, 0, 27, 0, 20, 0, 16, 0, 12, 0, 4, 0, 0, 0, 0, 0, 0, 0, 11, 0, 36, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 68, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 120, 0, 0, 0, 0, 0, 80, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 64, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 30, 0, 40, 0, 10, 0, 20, 0, 152, 255, 255, 255, 4, 0, 0, 0, 4, 0, 0, 0, 70, 114, 101, 100, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 50, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 0, 0, 0, 9, 0, 0, 0, 77, 121, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 4, 0, 0, 0, 240, 255, 255, 255, 32, 0, 0, 0, 248, 255, 255, 255, 36, 0, 0, 0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, 0, 0, 28, 0, 0, 0, 5, 0, 0, 0, 87, 105, 108, 109, 97, 0, 0, 0, 6, 0, 0, 0, 66, 97, 114, 110, 101, 121, 0, 0, 5, 0, 0, 0, 70, 114, 111, 100, 111, 0, 0, 0]) // swiftformat:enable all var buffer = bytes.buffer + print(buffer) let monster: MyGame_Example_Monster = getRoot(byteBuffer: &buffer) readMonster(monster: monster) mutateMonster(fb: bytes.buffer) @@ -130,6 +132,7 @@ class FlatBuffersMonsterWriterTests: XCTestCase { var fbb = FlatBufferBuilder(initialSize: 1) let name = fbb.create(string: "Frodo") let bools = fbb.createVector(boolArray) + let root = Monster.createMonster( &fbb, nameOffset: name, @@ -176,8 +179,7 @@ class FlatBuffersMonsterWriterTests: XCTestCase { let unlignedPtr = UnsafeMutableRawPointer(baseAddress) var bytes = ByteBuffer( assumingMemoryBound: unlignedPtr, - capacity: ptr.count - 1, - allowReadingUnalignedBuffers: true) + capacity: ptr.count - 1) var monster: Monster = getRoot(byteBuffer: &bytes) self.readFlatbufferMonster(monster: &monster) return true @@ -186,7 +188,7 @@ class FlatBuffersMonsterWriterTests: XCTestCase { XCTAssertEqual(testUnaligned(), true) } - func testCopyUnalignedToAlignedBuffers() { + func testReadingRemovedSizeUnalignedBuffer() { // Aligned read let fbb = createMonster(withPrefix: true) let testUnaligned: () -> Bool = { @@ -201,8 +203,7 @@ class FlatBuffersMonsterWriterTests: XCTestCase { let unlignedPtr = UnsafeMutableRawPointer(baseAddress) let bytes = ByteBuffer( assumingMemoryBound: unlignedPtr, - capacity: ptr.count - 1, - allowReadingUnalignedBuffers: false) + capacity: ptr.count - 1) var newBuf = FlatBuffersUtils.removeSizePrefix(bb: bytes) var monster: Monster = getRoot(byteBuffer: &newBuf) self.readFlatbufferMonster(monster: &monster) @@ -212,6 +213,37 @@ class FlatBuffersMonsterWriterTests: XCTestCase { XCTAssertEqual(testUnaligned(), true) } + func testCreateMessage() { + let fbb = createMonster(withPrefix: false) + let byteBuffer = fbb.buffer + let firstMessage = Message(byteBuffer: byteBuffer) + firstMessage.withUnsafeReadableBytes { ptr in + var bytes = ByteBuffer(contiguousBytes: ptr, count: ptr.count) + var monster: Monster = getRoot(byteBuffer: &bytes) + self.readFlatbufferMonster(monster: &monster) + } + + let secondByteBuffer = fbb.sizedBuffer + let secondMessage = Message(byteBuffer: secondByteBuffer) + secondMessage.withUnsafeReadableBytes { ptr in + var bytes = ByteBuffer(contiguousBytes: ptr, count: ptr.count) + var monster: Monster = getRoot(byteBuffer: &bytes) + self.readFlatbufferMonster(monster: &monster) + } + } + + func testForceRetainedObject() { + let byteBuffer = { + // swiftformat:disable all + var data: Data? = Data([48, 0, 0, 0, 77, 79, 78, 83, 0, 0, 0, 0, 36, 0, 72, 0, 40, 0, 0, 0, 38, 0, 32, 0, 0, 0, 28, 0, 0, 0, 27, 0, 20, 0, 16, 0, 12, 0, 4, 0, 0, 0, 0, 0, 0, 0, 11, 0, 36, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 1, 60, 0, 0, 0, 68, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, 0, 120, 0, 0, 0, 0, 0, 80, 0, 0, 0, 128, 63, 0, 0, 0, 64, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 64, 2, 0, 5, 0, 6, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 30, 0, 40, 0, 10, 0, 20, 0, 152, 255, 255, 255, 4, 0, 0, 0, 4, 0, 0, 0, 70, 114, 101, 100, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 50, 0, 0, 0, 5, 0, 0, 0, 116, 101, 115, 116, 49, 0, 0, 0, 9, 0, 0, 0, 77, 121, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 4, 0, 0, 0, 240, 255, 255, 255, 32, 0, 0, 0, 248, 255, 255, 255, 36, 0, 0, 0, 12, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, 0, 0, 28, 0, 0, 0, 5, 0, 0, 0, 87, 105, 108, 109, 97, 0, 0, 0, 6, 0, 0, 0, 66, 97, 114, 110, 101, 121, 0, 0, 5, 0, 0, 0, 70, 114, 111, 100, 111, 0, 0, 0]) + // swiftformat:enable all + let buffer = ByteBuffer(data: data!) + data = nil + return buffer + }() + readVerifiedMonster(fb: byteBuffer) + } + func readMonster(monster: Monster) { var monster = monster readFlatbufferMonster(monster: &monster) @@ -286,6 +318,7 @@ class FlatBuffersMonsterWriterTests: XCTestCase { func mutateMonster(fb: ByteBuffer) { var fb = fb + print(fb) let monster: Monster = getRoot(byteBuffer: &fb) XCTAssertFalse(monster.mutate(mana: 10)) XCTAssertEqual(monster.testarrayoftables(at: 0)?.name, "Barney") @@ -352,6 +385,15 @@ class FlatBuffersMonsterWriterTests: XCTestCase { sum += monster.inventory(at: i) } XCTAssertEqual(sum, 10) + + monster.withUnsafePointerToInventory { ptr in + var sum: UInt8 = 0 + for pointee in ptr.startIndex.. = + UnsafeBufferPointer( + start: ptr.bindMemory( + to: MyGame_Example_Test.self, + capacity: Int(monster.test4Count)), + count: Int(monster.test4Count)) + var pointerSum = 0 + for pointee in bindedMemory.startIndex.. = UnsafeBufferPointer( + start: ptr.baseAddress?.bindMemory( + to: UInt64.self, + capacity: Int(msg.arrayCount)), + count: Int(msg.arrayCount)) + return Array(ptr) + } + + XCTAssertEqual(array, [1, 2, 3]) } } diff --git a/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersVerifierTests.swift b/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersVerifierTests.swift index 53c402787..d996e4ddc 100644 --- a/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersVerifierTests.swift +++ b/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/FlatbuffersVerifierTests.swift @@ -20,11 +20,9 @@ import XCTest final class FlatbuffersVerifierTests: XCTestCase { lazy var validStorage: ByteBuffer.Storage = ByteBuffer.Storage( - count: Int(FlatBufferMaxSize) - 1, - alignment: 1) + count: Int(FlatBufferMaxSize) - 1) lazy var errorStorage: ByteBuffer.Storage = ByteBuffer.Storage( - count: Int(FlatBufferMaxSize) + 1, - alignment: 1) + count: Int(FlatBufferMaxSize) + 1) var buffer: ByteBuffer! @@ -35,7 +33,8 @@ final class FlatbuffersVerifierTests: XCTestCase { override func setUp() { // swiftformat:disable all - buffer = ByteBuffer(initialSize: 32) + let memory = UnsafeMutableRawPointer.allocate(byteCount: 32, alignment: 1) + buffer = ByteBuffer(assumingMemoryBound: memory, capacity: 32) add(buffer: &buffer, v: 4, p: 16) add(buffer: &buffer, v: 4, p: 20) @@ -52,13 +51,15 @@ final class FlatbuffersVerifierTests: XCTestCase { } func testVeriferInitPassing() { - var buffer = ByteBuffer(initialSize: 0) + let memory = UnsafeMutableRawPointer.allocate(byteCount: 8, alignment: 1) + var buffer = ByteBuffer(assumingMemoryBound: memory, capacity: 8) buffer._storage = validStorage XCTAssertNoThrow(try Verifier(buffer: &buffer)) } func testVeriferInitFailing() { - var buffer = ByteBuffer(initialSize: 0) + let memory = UnsafeMutableRawPointer.allocate(byteCount: 8, alignment: 1) + var buffer = ByteBuffer(assumingMemoryBound: memory, capacity: 8) buffer._storage = errorStorage XCTAssertThrowsError(try Verifier(buffer: &buffer)) } diff --git a/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/monster_test.grpc.swift b/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/monster_test.grpc.swift index b5fd53596..ad8b35eed 100644 --- a/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/monster_test.grpc.swift +++ b/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/monster_test.grpc.swift @@ -17,8 +17,7 @@ public extension GRPCFlatBufPayload { self.init(byteBuffer: FlatBuffers.ByteBuffer(contiguousBytes: serializedByteBuffer.readableBytesView, count: serializedByteBuffer.readableBytes)) } func serialize(into buffer: inout NIO.ByteBuffer) throws { - let buf = UnsafeRawBufferPointer(start: self.rawPointer, count: Int(self.size)) - buffer.writeBytes(buf) + withUnsafeReadableBytes { buffer.writeBytes($0) } } } extension Message: GRPCFlatBufPayload {} diff --git a/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift b/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift index 476854444..94ecac147 100644 --- a/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift +++ b/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift @@ -906,7 +906,7 @@ public struct MyGame_Example_Stat: FlatBufferObject, Verifiable, ObjectAPIPacker } public static func sortVectorOfStat(offsets:[Offset], _ fbb: inout FlatBufferBuilder) -> Offset { var off = offsets - off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 8, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: 8, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } + off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 8, fbb: &fbb), Table.offset(Int32($0.o), vOffset: 8, fbb: &fbb), fbb: &fbb) < 0 } return fbb.createVector(ofOffsets: off) } fileprivate static func lookupByKey(vector: Int32, key: UInt16, fbb: ByteBuffer) -> MyGame_Example_Stat? { @@ -1033,7 +1033,7 @@ public struct MyGame_Example_Referrable: FlatBufferObject, Verifiable, ObjectAPI } public static func sortVectorOfReferrable(offsets:[Offset], _ fbb: inout FlatBufferBuilder) -> Offset { var off = offsets - off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 4, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: 4, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } + off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 4, fbb: &fbb), Table.offset(Int32($0.o), vOffset: 4, fbb: &fbb), fbb: &fbb) < 0 } return fbb.createVector(ofOffsets: off) } fileprivate static func lookupByKey(vector: Int32, key: UInt64, fbb: ByteBuffer) -> MyGame_Example_Referrable? { @@ -1197,6 +1197,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public func inventory(at index: Int32) -> UInt8 { let o = _accessor.offset(VTOFFSET.inventory.v); return o == 0 ? 0 : _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1) } public var inventory: [UInt8] { return _accessor.getVector(at: VTOFFSET.inventory.v) ?? [] } public func mutate(inventory: UInt8, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.inventory.v); return _accessor.directMutate(inventory, index: _accessor.vector(at: o) + index * 1) } + public func withUnsafePointerToInventory(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.inventory.v, body: body) } public var color: MyGame_Example_Color { let o = _accessor.offset(VTOFFSET.color.v); return o == 0 ? .blue : MyGame_Example_Color(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? .blue } @discardableResult public func mutate(color: MyGame_Example_Color) -> Bool {let o = _accessor.offset(VTOFFSET.color.v); return _accessor.mutate(color.rawValue, index: o) } public var testType: MyGame_Example_Any_ { let o = _accessor.offset(VTOFFSET.testType.v); return o == 0 ? .none_ : MyGame_Example_Any_(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? .none_ } @@ -1205,6 +1206,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public var test4Count: Int32 { let o = _accessor.offset(VTOFFSET.test4.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func test4(at index: Int32) -> MyGame_Example_Test? { let o = _accessor.offset(VTOFFSET.test4.v); return o == 0 ? nil : _accessor.directRead(of: MyGame_Example_Test.self, offset: _accessor.vector(at: o) + index * 4) } public func mutableTest4(at index: Int32) -> MyGame_Example_Test_Mutable? { let o = _accessor.offset(VTOFFSET.test4.v); return o == 0 ? nil : MyGame_Example_Test_Mutable(_accessor.bb, o: _accessor.vector(at: o) + index * 4) } + public func withUnsafePointerToTest4(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.test4.v, body: body) } public var hasTestarrayofstring: Bool { let o = _accessor.offset(VTOFFSET.testarrayofstring.v); return o == 0 ? false : true } public var testarrayofstringCount: Int32 { let o = _accessor.offset(VTOFFSET.testarrayofstring.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func testarrayofstring(at index: Int32) -> String? { let o = _accessor.offset(VTOFFSET.testarrayofstring.v); return o == 0 ? nil : _accessor.directString(at: _accessor.vector(at: o) + index * 4) } @@ -1220,6 +1222,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public func testnestedflatbuffer(at index: Int32) -> UInt8 { let o = _accessor.offset(VTOFFSET.testnestedflatbuffer.v); return o == 0 ? 0 : _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1) } public var testnestedflatbuffer: [UInt8] { return _accessor.getVector(at: VTOFFSET.testnestedflatbuffer.v) ?? [] } public func mutate(testnestedflatbuffer: UInt8, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.testnestedflatbuffer.v); return _accessor.directMutate(testnestedflatbuffer, index: _accessor.vector(at: o) + index * 1) } + public func withUnsafePointerToTestnestedflatbuffer(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.testnestedflatbuffer.v, body: body) } public var testempty: MyGame_Example_Stat? { let o = _accessor.offset(VTOFFSET.testempty.v); return o == 0 ? nil : MyGame_Example_Stat(_accessor.bb, o: _accessor.indirect(o + _accessor.position)) } public var testbool: Bool { let o = _accessor.offset(VTOFFSET.testbool.v); return o == 0 ? false : _accessor.readBuffer(of: Bool.self, at: o) } @discardableResult public func mutate(testbool: Bool) -> Bool {let o = _accessor.offset(VTOFFSET.testbool.v); return _accessor.mutate(testbool, index: o) } @@ -1244,6 +1247,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public func testarrayofbools(at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.testarrayofbools.v); return o == 0 ? true : _accessor.directRead(of: Bool.self, offset: _accessor.vector(at: o) + index * 1) } public var testarrayofbools: [Bool] { return _accessor.getVector(at: VTOFFSET.testarrayofbools.v) ?? [] } public func mutate(testarrayofbools: Bool, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.testarrayofbools.v); return _accessor.directMutate(testarrayofbools, index: _accessor.vector(at: o) + index * 1) } + public func withUnsafePointerToTestarrayofbools(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.testarrayofbools.v, body: body) } public var testf: Float32 { let o = _accessor.offset(VTOFFSET.testf.v); return o == 0 ? 3.14159 : _accessor.readBuffer(of: Float32.self, at: o) } @discardableResult public func mutate(testf: Float32) -> Bool {let o = _accessor.offset(VTOFFSET.testf.v); return _accessor.mutate(testf, index: o) } public var testf2: Float32 { let o = _accessor.offset(VTOFFSET.testf2.v); return o == 0 ? 3.0 : _accessor.readBuffer(of: Float32.self, at: o) } @@ -1257,25 +1261,30 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public var testarrayofsortedstructCount: Int32 { let o = _accessor.offset(VTOFFSET.testarrayofsortedstruct.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func testarrayofsortedstruct(at index: Int32) -> MyGame_Example_Ability? { let o = _accessor.offset(VTOFFSET.testarrayofsortedstruct.v); return o == 0 ? nil : _accessor.directRead(of: MyGame_Example_Ability.self, offset: _accessor.vector(at: o) + index * 8) } public func mutableTestarrayofsortedstruct(at index: Int32) -> MyGame_Example_Ability_Mutable? { let o = _accessor.offset(VTOFFSET.testarrayofsortedstruct.v); return o == 0 ? nil : MyGame_Example_Ability_Mutable(_accessor.bb, o: _accessor.vector(at: o) + index * 8) } + public func withUnsafePointerToTestarrayofsortedstruct(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.testarrayofsortedstruct.v, body: body) } public var hasFlex: Bool { let o = _accessor.offset(VTOFFSET.flex.v); return o == 0 ? false : true } public var flexCount: Int32 { let o = _accessor.offset(VTOFFSET.flex.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func flex(at index: Int32) -> UInt8 { let o = _accessor.offset(VTOFFSET.flex.v); return o == 0 ? 0 : _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1) } public var flex: [UInt8] { return _accessor.getVector(at: VTOFFSET.flex.v) ?? [] } public func mutate(flex: UInt8, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.flex.v); return _accessor.directMutate(flex, index: _accessor.vector(at: o) + index * 1) } + public func withUnsafePointerToFlex(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.flex.v, body: body) } public var hasTest5: Bool { let o = _accessor.offset(VTOFFSET.test5.v); return o == 0 ? false : true } public var test5Count: Int32 { let o = _accessor.offset(VTOFFSET.test5.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func test5(at index: Int32) -> MyGame_Example_Test? { let o = _accessor.offset(VTOFFSET.test5.v); return o == 0 ? nil : _accessor.directRead(of: MyGame_Example_Test.self, offset: _accessor.vector(at: o) + index * 4) } public func mutableTest5(at index: Int32) -> MyGame_Example_Test_Mutable? { let o = _accessor.offset(VTOFFSET.test5.v); return o == 0 ? nil : MyGame_Example_Test_Mutable(_accessor.bb, o: _accessor.vector(at: o) + index * 4) } + public func withUnsafePointerToTest5(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.test5.v, body: body) } public var hasVectorOfLongs: Bool { let o = _accessor.offset(VTOFFSET.vectorOfLongs.v); return o == 0 ? false : true } public var vectorOfLongsCount: Int32 { let o = _accessor.offset(VTOFFSET.vectorOfLongs.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func vectorOfLongs(at index: Int32) -> Int64 { let o = _accessor.offset(VTOFFSET.vectorOfLongs.v); return o == 0 ? 0 : _accessor.directRead(of: Int64.self, offset: _accessor.vector(at: o) + index * 8) } public var vectorOfLongs: [Int64] { return _accessor.getVector(at: VTOFFSET.vectorOfLongs.v) ?? [] } public func mutate(vectorOfLongs: Int64, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.vectorOfLongs.v); return _accessor.directMutate(vectorOfLongs, index: _accessor.vector(at: o) + index * 8) } + public func withUnsafePointerToVectorOfLongs(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.vectorOfLongs.v, body: body) } public var hasVectorOfDoubles: Bool { let o = _accessor.offset(VTOFFSET.vectorOfDoubles.v); return o == 0 ? false : true } public var vectorOfDoublesCount: Int32 { let o = _accessor.offset(VTOFFSET.vectorOfDoubles.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func vectorOfDoubles(at index: Int32) -> Double { let o = _accessor.offset(VTOFFSET.vectorOfDoubles.v); return o == 0 ? 0 : _accessor.directRead(of: Double.self, offset: _accessor.vector(at: o) + index * 8) } public var vectorOfDoubles: [Double] { return _accessor.getVector(at: VTOFFSET.vectorOfDoubles.v) ?? [] } public func mutate(vectorOfDoubles: Double, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.vectorOfDoubles.v); return _accessor.directMutate(vectorOfDoubles, index: _accessor.vector(at: o) + index * 8) } + public func withUnsafePointerToVectorOfDoubles(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.vectorOfDoubles.v, body: body) } public var parentNamespaceTest: MyGame_InParentNamespace? { let o = _accessor.offset(VTOFFSET.parentNamespaceTest.v); return o == 0 ? nil : MyGame_InParentNamespace(_accessor.bb, o: _accessor.indirect(o + _accessor.position)) } public var hasVectorOfReferrables: Bool { let o = _accessor.offset(VTOFFSET.vectorOfReferrables.v); return o == 0 ? false : true } public var vectorOfReferrablesCount: Int32 { let o = _accessor.offset(VTOFFSET.vectorOfReferrables.v); return o == 0 ? 0 : _accessor.vector(count: o) } @@ -1288,6 +1297,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public func vectorOfWeakReferences(at index: Int32) -> UInt64 { let o = _accessor.offset(VTOFFSET.vectorOfWeakReferences.v); return o == 0 ? 0 : _accessor.directRead(of: UInt64.self, offset: _accessor.vector(at: o) + index * 8) } public var vectorOfWeakReferences: [UInt64] { return _accessor.getVector(at: VTOFFSET.vectorOfWeakReferences.v) ?? [] } public func mutate(vectorOfWeakReferences: UInt64, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.vectorOfWeakReferences.v); return _accessor.directMutate(vectorOfWeakReferences, index: _accessor.vector(at: o) + index * 8) } + public func withUnsafePointerToVectorOfWeakReferences(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.vectorOfWeakReferences.v, body: body) } public var hasVectorOfStrongReferrables: Bool { let o = _accessor.offset(VTOFFSET.vectorOfStrongReferrables.v); return o == 0 ? false : true } public var vectorOfStrongReferrablesCount: Int32 { let o = _accessor.offset(VTOFFSET.vectorOfStrongReferrables.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func vectorOfStrongReferrables(at index: Int32) -> MyGame_Example_Referrable? { let o = _accessor.offset(VTOFFSET.vectorOfStrongReferrables.v); return o == 0 ? nil : MyGame_Example_Referrable(_accessor.bb, o: _accessor.indirect(_accessor.vector(at: o) + index * 4)) } @@ -1299,6 +1309,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public func vectorOfCoOwningReferences(at index: Int32) -> UInt64 { let o = _accessor.offset(VTOFFSET.vectorOfCoOwningReferences.v); return o == 0 ? 0 : _accessor.directRead(of: UInt64.self, offset: _accessor.vector(at: o) + index * 8) } public var vectorOfCoOwningReferences: [UInt64] { return _accessor.getVector(at: VTOFFSET.vectorOfCoOwningReferences.v) ?? [] } public func mutate(vectorOfCoOwningReferences: UInt64, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.vectorOfCoOwningReferences.v); return _accessor.directMutate(vectorOfCoOwningReferences, index: _accessor.vector(at: o) + index * 8) } + public func withUnsafePointerToVectorOfCoOwningReferences(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.vectorOfCoOwningReferences.v, body: body) } public var nonOwningReference: UInt64 { let o = _accessor.offset(VTOFFSET.nonOwningReference.v); return o == 0 ? 0 : _accessor.readBuffer(of: UInt64.self, at: o) } @discardableResult public func mutate(nonOwningReference: UInt64) -> Bool {let o = _accessor.offset(VTOFFSET.nonOwningReference.v); return _accessor.mutate(nonOwningReference, index: o) } public var hasVectorOfNonOwningReferences: Bool { let o = _accessor.offset(VTOFFSET.vectorOfNonOwningReferences.v); return o == 0 ? false : true } @@ -1306,6 +1317,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public func vectorOfNonOwningReferences(at index: Int32) -> UInt64 { let o = _accessor.offset(VTOFFSET.vectorOfNonOwningReferences.v); return o == 0 ? 0 : _accessor.directRead(of: UInt64.self, offset: _accessor.vector(at: o) + index * 8) } public var vectorOfNonOwningReferences: [UInt64] { return _accessor.getVector(at: VTOFFSET.vectorOfNonOwningReferences.v) ?? [] } public func mutate(vectorOfNonOwningReferences: UInt64, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.vectorOfNonOwningReferences.v); return _accessor.directMutate(vectorOfNonOwningReferences, index: _accessor.vector(at: o) + index * 8) } + public func withUnsafePointerToVectorOfNonOwningReferences(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.vectorOfNonOwningReferences.v, body: body) } public var anyUniqueType: MyGame_Example_AnyUniqueAliases { let o = _accessor.offset(VTOFFSET.anyUniqueType.v); return o == 0 ? .none_ : MyGame_Example_AnyUniqueAliases(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? .none_ } public func anyUnique(type: T.Type) -> T? { let o = _accessor.offset(VTOFFSET.anyUnique.v); return o == 0 ? nil : _accessor.union(o) } public var anyAmbiguousType: MyGame_Example_AnyAmbiguousAliases { let o = _accessor.offset(VTOFFSET.anyAmbiguousType.v); return o == 0 ? .none_ : MyGame_Example_AnyAmbiguousAliases(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? .none_ } @@ -1320,6 +1332,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac public func testrequirednestedflatbuffer(at index: Int32) -> UInt8 { let o = _accessor.offset(VTOFFSET.testrequirednestedflatbuffer.v); return o == 0 ? 0 : _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1) } public var testrequirednestedflatbuffer: [UInt8] { return _accessor.getVector(at: VTOFFSET.testrequirednestedflatbuffer.v) ?? [] } public func mutate(testrequirednestedflatbuffer: UInt8, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.testrequirednestedflatbuffer.v); return _accessor.directMutate(testrequirednestedflatbuffer, index: _accessor.vector(at: o) + index * 1) } + public func withUnsafePointerToTestrequirednestedflatbuffer(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.testrequirednestedflatbuffer.v, body: body) } public var hasScalarKeySortedTables: Bool { let o = _accessor.offset(VTOFFSET.scalarKeySortedTables.v); return o == 0 ? false : true } public var scalarKeySortedTablesCount: Int32 { let o = _accessor.offset(VTOFFSET.scalarKeySortedTables.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func scalarKeySortedTables(at index: Int32) -> MyGame_Example_Stat? { let o = _accessor.offset(VTOFFSET.scalarKeySortedTables.v); return o == 0 ? nil : MyGame_Example_Stat(_accessor.bb, o: _accessor.indirect(_accessor.vector(at: o) + index * 4)) } @@ -1549,7 +1562,7 @@ public struct MyGame_Example_Monster: FlatBufferObject, Verifiable, ObjectAPIPac } public static func sortVectorOfMonster(offsets:[Offset], _ fbb: inout FlatBufferBuilder) -> Offset { var off = offsets - off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 10, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: 10, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } + off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 10, fbb: &fbb), Table.offset(Int32($0.o), vOffset: 10, fbb: &fbb), fbb: &fbb) < 0 } return fbb.createVector(ofOffsets: off) } fileprivate static func lookupByKey(vector: Int32, key: String, fbb: ByteBuffer) -> MyGame_Example_Monster? { @@ -2456,11 +2469,13 @@ public struct MyGame_Example_TypeAliases: FlatBufferObject, Verifiable, ObjectAP public func v8(at index: Int32) -> Int8 { let o = _accessor.offset(VTOFFSET.v8.v); return o == 0 ? 0 : _accessor.directRead(of: Int8.self, offset: _accessor.vector(at: o) + index * 1) } public var v8: [Int8] { return _accessor.getVector(at: VTOFFSET.v8.v) ?? [] } public func mutate(v8: Int8, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.v8.v); return _accessor.directMutate(v8, index: _accessor.vector(at: o) + index * 1) } + public func withUnsafePointerToV8(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.v8.v, body: body) } public var hasVf64: Bool { let o = _accessor.offset(VTOFFSET.vf64.v); return o == 0 ? false : true } public var vf64Count: Int32 { let o = _accessor.offset(VTOFFSET.vf64.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func vf64(at index: Int32) -> Double { let o = _accessor.offset(VTOFFSET.vf64.v); return o == 0 ? 0 : _accessor.directRead(of: Double.self, offset: _accessor.vector(at: o) + index * 8) } public var vf64: [Double] { return _accessor.getVector(at: VTOFFSET.vf64.v) ?? [] } public func mutate(vf64: Double, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.vf64.v); return _accessor.directMutate(vf64, index: _accessor.vector(at: o) + index * 8) } + public func withUnsafePointerToVf64(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.vf64.v, body: body) } public static func startTypeAliases(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 12) } public static func add(i8: Int8, _ fbb: inout FlatBufferBuilder) { fbb.add(element: i8, def: 0, at: VTOFFSET.i8.p) } public static func add(u8: UInt8, _ fbb: inout FlatBufferBuilder) { fbb.add(element: u8, def: 0, at: VTOFFSET.u8.p) } diff --git a/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/more_defaults_generated.swift b/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/more_defaults_generated.swift index bdafcf7bd..8dc1ea8ff 100644 --- a/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/more_defaults_generated.swift +++ b/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/more_defaults_generated.swift @@ -51,10 +51,12 @@ public struct MoreDefaults: FlatBufferObject, Verifiable, ObjectAPIPacker { public var intsCount: Int32 { let o = _accessor.offset(VTOFFSET.ints.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func ints(at index: Int32) -> Int32 { let o = _accessor.offset(VTOFFSET.ints.v); return o == 0 ? 0 : _accessor.directRead(of: Int32.self, offset: _accessor.vector(at: o) + index * 4) } public var ints: [Int32] { return _accessor.getVector(at: VTOFFSET.ints.v) ?? [] } + public func withUnsafePointerToInts(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.ints.v, body: body) } public var hasFloats: Bool { let o = _accessor.offset(VTOFFSET.floats.v); return o == 0 ? false : true } public var floatsCount: Int32 { let o = _accessor.offset(VTOFFSET.floats.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func floats(at index: Int32) -> Float32 { let o = _accessor.offset(VTOFFSET.floats.v); return o == 0 ? 0 : _accessor.directRead(of: Float32.self, offset: _accessor.vector(at: o) + index * 4) } public var floats: [Float32] { return _accessor.getVector(at: VTOFFSET.floats.v) ?? [] } + public func withUnsafePointerToFloats(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.floats.v, body: body) } public var emptyString: String? { let o = _accessor.offset(VTOFFSET.emptyString.v); return o == 0 ? "" : _accessor.string(at: o) } public var emptyStringSegmentArray: [UInt8]? { return _accessor.getVector(at: VTOFFSET.emptyString.v) } public var someString: String? { let o = _accessor.offset(VTOFFSET.someString.v); return o == 0 ? "some" : _accessor.string(at: o) } @@ -66,6 +68,7 @@ public struct MoreDefaults: FlatBufferObject, Verifiable, ObjectAPIPacker { public var boolsCount: Int32 { let o = _accessor.offset(VTOFFSET.bools.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func bools(at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.bools.v); return o == 0 ? true : _accessor.directRead(of: Bool.self, offset: _accessor.vector(at: o) + index * 1) } public var bools: [Bool] { return _accessor.getVector(at: VTOFFSET.bools.v) ?? [] } + public func withUnsafePointerToBools(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.bools.v, body: body) } public static func startMoreDefaults(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 6) } public static func addVectorOf(ints: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: ints, at: VTOFFSET.ints.p) } public static func addVectorOf(floats: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: floats, at: VTOFFSET.floats.p) } diff --git a/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/vector_has_test_generated.swift b/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/vector_has_test_generated.swift index fef6b4fe9..30601adb6 100644 --- a/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/vector_has_test_generated.swift +++ b/tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/vector_has_test_generated.swift @@ -25,14 +25,17 @@ public struct Swift_Tests_Vectors: FlatBufferObject, Verifiable { public var none_Count: Int32 { let o = _accessor.offset(VTOFFSET.none_.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func none_(at index: Int32) -> UInt64 { let o = _accessor.offset(VTOFFSET.none_.v); return o == 0 ? 0 : _accessor.directRead(of: UInt64.self, offset: _accessor.vector(at: o) + index * 8) } public var none_: [UInt64] { return _accessor.getVector(at: VTOFFSET.none_.v) ?? [] } + public func withUnsafePointerToNone(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.none_.v, body: body) } public var hasEmpty: Bool { let o = _accessor.offset(VTOFFSET.empty.v); return o == 0 ? false : true } public var emptyCount: Int32 { let o = _accessor.offset(VTOFFSET.empty.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func empty(at index: Int32) -> UInt64 { let o = _accessor.offset(VTOFFSET.empty.v); return o == 0 ? 0 : _accessor.directRead(of: UInt64.self, offset: _accessor.vector(at: o) + index * 8) } public var empty: [UInt64] { return _accessor.getVector(at: VTOFFSET.empty.v) ?? [] } + public func withUnsafePointerToEmpty(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.empty.v, body: body) } public var hasArray: Bool { let o = _accessor.offset(VTOFFSET.array.v); return o == 0 ? false : true } public var arrayCount: Int32 { let o = _accessor.offset(VTOFFSET.array.v); return o == 0 ? 0 : _accessor.vector(count: o) } public func array(at index: Int32) -> UInt64 { let o = _accessor.offset(VTOFFSET.array.v); return o == 0 ? 0 : _accessor.directRead(of: UInt64.self, offset: _accessor.vector(at: o) + index * 8) } public var array: [UInt64] { return _accessor.getVector(at: VTOFFSET.array.v) ?? [] } + public func withUnsafePointerToArray(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.array.v, body: body) } public static func startVectors(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 3) } public static func addVectorOf(none_: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: none_, at: VTOFFSET.none_.p) } public static func addVectorOf(empty: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: empty, at: VTOFFSET.empty.p) }