Skip to content

Commit ca120fd

Browse files
wthollidayJochen Parmentier
authored andcommitted
[Swift] Push contiguous bytes (google#8157)
* Add version of push which takes ContiguousBytes * Ensure overloads aren't ambiguous * Add version of createVector * Add version of push which takes ContiguousBytes * Ensure overloads aren't ambiguous * Add version of createVector * Add similar conditional to other use of ContiguousBytes * Attempt CI fix * Use memcpy instead of copyMemory memcpy is faster in tests * Add testContiguousBytes * Add benchmarks * Add version of createVector * Add benchmarks * Update push to copy memory Since we don't care about endianness, we can simply memcpy the array of scalars * Remove function and benchmarks Since we don't care about endianness, a FixedWidthInteger version of createVector isn't needed * Improve naming * Add doc comment
1 parent da38a78 commit ca120fd

File tree

4 files changed

+72
-4
lines changed

4 files changed

+72
-4
lines changed

swift/Sources/FlatBuffers/ByteBuffer.swift

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,12 +228,32 @@ public struct ByteBuffer {
228228
@inline(__always)
229229
@usableFromInline
230230
mutating func push<T: Scalar>(elements: [T]) {
231-
let size = elements.count &* MemoryLayout<T>.size
232-
ensureSpace(size: size)
233-
elements.reversed().forEach { s in
234-
push(value: s, len: MemoryLayout.size(ofValue: s))
231+
elements.withUnsafeBytes { ptr in
232+
ensureSpace(size: ptr.count)
233+
memcpy(
234+
_storage.memory.advanced(by: writerIndex &- ptr.count),
235+
UnsafeRawPointer(ptr.baseAddress!),
236+
ptr.count)
237+
self._writerSize = self._writerSize &+ ptr.count
238+
}
239+
}
240+
241+
/// Adds a `ContiguousBytes` to buffer memory
242+
/// - Parameter value: bytes to copy
243+
#if swift(>=5.0) && !os(WASI)
244+
@inline(__always)
245+
@usableFromInline
246+
mutating func push(bytes: ContiguousBytes) {
247+
bytes.withUnsafeBytes { ptr in
248+
ensureSpace(size: ptr.count)
249+
memcpy(
250+
_storage.memory.advanced(by: writerIndex &- ptr.count),
251+
UnsafeRawPointer(ptr.baseAddress!),
252+
ptr.count)
253+
self._writerSize = self._writerSize &+ ptr.count
235254
}
236255
}
256+
#endif
237257

238258
/// Adds an object of type NativeStruct into the buffer
239259
/// - Parameters:

swift/Sources/FlatBuffers/FlatBufferBuilder.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,22 @@ public struct FlatBufferBuilder {
473473
return endVector(len: size)
474474
}
475475

476+
#if swift(>=5.0) && !os(WASI)
477+
@inline(__always)
478+
/// Creates a vector of bytes in the buffer.
479+
///
480+
/// Allows creating a vector from `Data` without copying to a `[UInt8]`
481+
///
482+
/// - Parameter bytes: bytes to be written into the buffer
483+
/// - Returns: ``Offset`` of the vector
484+
mutating public func createVector(bytes: ContiguousBytes) -> Offset {
485+
let size = bytes.withUnsafeBytes { ptr in ptr.count }
486+
startVector(size, elementSize: MemoryLayout<UInt8>.size)
487+
_bb.push(bytes: bytes)
488+
return endVector(len: size)
489+
}
490+
#endif
491+
476492
/// Creates a vector of type ``Enum`` into the ``ByteBuffer``
477493
///
478494
/// ``createVector(_:)-9h189`` writes a vector of type ``Enum`` into

tests/swift/benchmarks/Sources/benchmarks/main.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,20 @@ benchmark("100Strings") {
3232
}
3333
}
3434

35+
benchmark("100Bytes") {
36+
var fb = FlatBufferBuilder(initialSize: 1<<20)
37+
for _ in 0..<1_000_000 {
38+
_ = fb.createVector(bytes)
39+
}
40+
}
41+
42+
benchmark("100Bytes-ContiguousBytes") {
43+
var fb = FlatBufferBuilder(initialSize: 1<<20)
44+
for _ in 0..<1_000_000 {
45+
_ = fb.createVector(bytes: bytes)
46+
}
47+
}
48+
3549
benchmark("FlatBufferBuilder.add") {
3650
var fb = FlatBufferBuilder(initialSize: 1024 * 1024 * 32)
3751
for _ in 0..<1_000_000 {
@@ -73,6 +87,7 @@ benchmark("structs") {
7387
}
7488

7589
let str = (0...99).map { _ -> String in "x" }.joined()
90+
let bytes: [UInt8] = Array(repeating: 42, count: 100)
7691

7792
@usableFromInline
7893
struct AA: NativeStruct {

tests/swift/tests/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersMonsterWriterTests.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,4 +484,21 @@ class FlatBuffersMonsterWriterTests: XCTestCase {
484484
#endif
485485
}
486486

487+
func testContiguousBytes() {
488+
let byteArray: [UInt8] = [3, 1, 4, 1, 5, 9]
489+
var fbb = FlatBufferBuilder(initialSize: 1)
490+
let name = fbb.create(string: "Frodo")
491+
let bytes = fbb.createVector(bytes: byteArray)
492+
let root = Monster.createMonster(
493+
&fbb,
494+
nameOffset: name,
495+
inventoryVectorOffset: bytes)
496+
fbb.finish(offset: root)
497+
var buffer = fbb.sizedBuffer
498+
let monster: Monster = getRoot(byteBuffer: &buffer)
499+
let values = monster.inventory
500+
501+
XCTAssertEqual(byteArray, values)
502+
}
503+
487504
}

0 commit comments

Comments
 (0)