Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Swift] Overall Improvements #8061

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:5.2
// swift-tools-version:5.6
/*
* Copyright 2020 Google Inc. All rights reserved.
*
Expand Down Expand Up @@ -32,6 +32,5 @@ let package = Package(
.target(
name: "FlatBuffers",
dependencies: [],
path: "swift/Sources",
exclude: ["Documentation.docc/Resources/code/swift"]),
path: "swift/Sources"),
])
37 changes: 31 additions & 6 deletions swift/Sources/FlatBuffers/ByteBuffer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,16 @@ public struct ByteBuffer {
public var memory: UnsafeMutableRawPointer { _storage.memory }
/// 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 a UInt8
/// - Parameter bytes: Array of UInt8
public init(bytes: [UInt8]) {
var b = bytes
_storage = Storage(count: bytes.count, alignment: alignment)
_writerSize = _storage.capacity
allowReadingUnalignedBuffers = false
b.withUnsafeMutableBytes { bufferPointer in
self._storage.copy(from: bufferPointer.baseAddress!, count: bytes.count)
}
Expand All @@ -136,6 +139,7 @@ public struct ByteBuffer {
var b = data
_storage = Storage(count: data.count, alignment: alignment)
_writerSize = _storage.capacity
allowReadingUnalignedBuffers = false
b.withUnsafeMutableBytes { bufferPointer in
self._storage.copy(from: bufferPointer.baseAddress!, count: data.count)
}
Expand All @@ -148,6 +152,7 @@ public struct ByteBuffer {
let size = size.convertToPowerofTwo
_storage = Storage(count: size, alignment: alignment)
_storage.initialize(for: size)
allowReadingUnalignedBuffers = false
}

#if swift(>=5.0) && !os(WASI)
Expand All @@ -161,6 +166,7 @@ public struct ByteBuffer {
{
_storage = Storage(count: count, alignment: alignment)
_writerSize = _storage.capacity
allowReadingUnalignedBuffers = false
contiguousBytes.withUnsafeBytes { buf in
_storage.copy(from: buf.baseAddress!, count: buf.count)
}
Expand All @@ -172,10 +178,12 @@ public struct ByteBuffer {
/// - Parameter capacity: The size of the given memory region
public init(
assumingMemoryBound memory: UnsafeMutableRawPointer,
capacity: Int)
capacity: Int,
allowReadingUnalignedBuffers allowUnalignedBuffers: Bool = false)
{
_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
Expand All @@ -186,6 +194,7 @@ public struct ByteBuffer {
_storage = Storage(count: count, alignment: alignment)
_storage.copy(from: memory, count: count)
_writerSize = _storage.capacity
allowReadingUnalignedBuffers = false
}

/// Creates a copy of the existing flatbuffer, by copying it to a different memory.
Expand All @@ -201,6 +210,7 @@ public struct ByteBuffer {
_storage = Storage(count: count, alignment: alignment)
_storage.copy(from: memory, count: count)
_writerSize = removeBytes
allowReadingUnalignedBuffers = false
}

/// Fills the buffer with padding by adding to the writersize
Expand Down Expand Up @@ -234,8 +244,13 @@ public struct ByteBuffer {
mutating func push<T: NativeStruct>(struct value: T, size: Int) {
ensureSpace(size: size)
var v = value
memcpy(_storage.memory.advanced(by: writerIndex &- size), &v, size)
_writerSize = _writerSize &+ size
withUnsafeBytes(of: &v) {
memcpy(
_storage.memory.advanced(by: writerIndex &- size),
$0.baseAddress!,
size)
self._writerSize = self._writerSize &+ size
}
}

/// Adds an object of type Scalar into the buffer
Expand All @@ -247,8 +262,13 @@ public struct ByteBuffer {
mutating func push<T: Scalar>(value: T, len: Int) {
ensureSpace(size: len)
var v = value
memcpy(_storage.memory.advanced(by: writerIndex &- len), &v, len)
_writerSize = _writerSize &+ len
withUnsafeBytes(of: &v) {
memcpy(
_storage.memory.advanced(by: writerIndex &- len),
$0.baseAddress!,
len)
self._writerSize = self._writerSize &+ len
}
}

/// Adds a string to the buffer using swift.utf8 object
Expand Down Expand Up @@ -352,7 +372,12 @@ public struct ByteBuffer {
/// - position: the index of the object in the buffer
@inline(__always)
public func read<T>(def: T.Type, position: Int) -> T {
_storage.memory.advanced(by: position).load(as: T.self)
#if swift(>=5.7)
if allowReadingUnalignedBuffers {
return _storage.memory.advanced(by: position).loadUnaligned(as: T.self)
}
#endif
return _storage.memory.advanced(by: position).load(as: T.self)
}

/// Reads a slice from the memory assuming a type of T
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,64 @@ class FlatBuffersMonsterWriterTests: XCTestCase {
byteBuffer: &byteBuffer) as MyGame_Example_Monster))
}

func testUnalignedRead() {
// Aligned read
let fbb = createMonster(withPrefix: false)
let testAligned: () -> Bool = {
var buffer = fbb.sizedBuffer
var monster: Monster = getRoot(byteBuffer: &buffer)
self.readFlatbufferMonster(monster: &monster)
return true
}
XCTAssertEqual(testAligned(), true)
let testUnaligned: () -> Bool = {
var bytes: [UInt8] = [0x00]
bytes.append(contentsOf: fbb.sizedByteArray)
return bytes.withUnsafeMutableBytes { ptr in
guard var baseAddress = ptr.baseAddress else {
XCTFail("Base pointer is not defined")
return false
}
baseAddress = baseAddress.advanced(by: 1)
let unlignedPtr = UnsafeMutableRawPointer(baseAddress)
var bytes = ByteBuffer(
assumingMemoryBound: unlignedPtr,
capacity: ptr.count - 1,
allowReadingUnalignedBuffers: true)
var monster: Monster = getRoot(byteBuffer: &bytes)
self.readFlatbufferMonster(monster: &monster)
return true
}
}
XCTAssertEqual(testUnaligned(), true)
}

func testCopyUnalignedToAlignedBuffers() {
// Aligned read
let fbb = createMonster(withPrefix: true)
let testUnaligned: () -> Bool = {
var bytes: [UInt8] = [0x00]
bytes.append(contentsOf: fbb.sizedByteArray)
return bytes.withUnsafeMutableBytes { ptr in
guard var baseAddress = ptr.baseAddress else {
XCTFail("Base pointer is not defined")
return false
}
baseAddress = baseAddress.advanced(by: 1)
let unlignedPtr = UnsafeMutableRawPointer(baseAddress)
let bytes = ByteBuffer(
assumingMemoryBound: unlignedPtr,
capacity: ptr.count - 1,
allowReadingUnalignedBuffers: false)
var newBuf = FlatBuffersUtils.removeSizePrefix(bb: bytes)
var monster: Monster = getRoot(byteBuffer: &newBuf)
self.readFlatbufferMonster(monster: &monster)
return true
}
}
XCTAssertEqual(testUnaligned(), true)
}

func readMonster(monster: Monster) {
var monster = monster
readFlatbufferMonster(monster: &monster)
Expand Down