mirror of
https://github.com/google/flatbuffers.git
synced 2026-07-01 19:33:56 +00:00
Allow reading unaligned buffers starting from swift 5.7, while keeping the creating aligned since its created by the library (#8061)
Addresses a warning on xcode 15 regarding copying a pointer without safeguards Address PR comments regarding initializing buffers with flag Adds a test case for copying unaligned buffers Formatting code
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
// swift-tools-version:5.2
|
// swift-tools-version:5.6
|
||||||
/*
|
/*
|
||||||
* Copyright 2020 Google Inc. All rights reserved.
|
* Copyright 2020 Google Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
@@ -32,6 +32,5 @@ let package = Package(
|
|||||||
.target(
|
.target(
|
||||||
name: "FlatBuffers",
|
name: "FlatBuffers",
|
||||||
dependencies: [],
|
dependencies: [],
|
||||||
path: "swift/Sources",
|
path: "swift/Sources"),
|
||||||
exclude: ["Documentation.docc/Resources/code/swift"]),
|
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -117,6 +117,8 @@ public struct ByteBuffer {
|
|||||||
public var memory: UnsafeMutableRawPointer { _storage.memory }
|
public var memory: UnsafeMutableRawPointer { _storage.memory }
|
||||||
/// Current capacity for the buffer
|
/// Current capacity for the buffer
|
||||||
public var capacity: Int { _storage.capacity }
|
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
|
/// Constructor that creates a Flatbuffer object from a UInt8
|
||||||
/// - Parameter bytes: Array of UInt8
|
/// - Parameter bytes: Array of UInt8
|
||||||
@@ -124,6 +126,7 @@ public struct ByteBuffer {
|
|||||||
var b = bytes
|
var b = bytes
|
||||||
_storage = Storage(count: bytes.count, alignment: alignment)
|
_storage = Storage(count: bytes.count, alignment: alignment)
|
||||||
_writerSize = _storage.capacity
|
_writerSize = _storage.capacity
|
||||||
|
allowReadingUnalignedBuffers = false
|
||||||
b.withUnsafeMutableBytes { bufferPointer in
|
b.withUnsafeMutableBytes { bufferPointer in
|
||||||
self._storage.copy(from: bufferPointer.baseAddress!, count: bytes.count)
|
self._storage.copy(from: bufferPointer.baseAddress!, count: bytes.count)
|
||||||
}
|
}
|
||||||
@@ -136,6 +139,7 @@ public struct ByteBuffer {
|
|||||||
var b = data
|
var b = data
|
||||||
_storage = Storage(count: data.count, alignment: alignment)
|
_storage = Storage(count: data.count, alignment: alignment)
|
||||||
_writerSize = _storage.capacity
|
_writerSize = _storage.capacity
|
||||||
|
allowReadingUnalignedBuffers = false
|
||||||
b.withUnsafeMutableBytes { bufferPointer in
|
b.withUnsafeMutableBytes { bufferPointer in
|
||||||
self._storage.copy(from: bufferPointer.baseAddress!, count: data.count)
|
self._storage.copy(from: bufferPointer.baseAddress!, count: data.count)
|
||||||
}
|
}
|
||||||
@@ -148,6 +152,7 @@ public struct ByteBuffer {
|
|||||||
let size = size.convertToPowerofTwo
|
let size = size.convertToPowerofTwo
|
||||||
_storage = Storage(count: size, alignment: alignment)
|
_storage = Storage(count: size, alignment: alignment)
|
||||||
_storage.initialize(for: size)
|
_storage.initialize(for: size)
|
||||||
|
allowReadingUnalignedBuffers = false
|
||||||
}
|
}
|
||||||
|
|
||||||
#if swift(>=5.0) && !os(WASI)
|
#if swift(>=5.0) && !os(WASI)
|
||||||
@@ -161,6 +166,7 @@ public struct ByteBuffer {
|
|||||||
{
|
{
|
||||||
_storage = Storage(count: count, alignment: alignment)
|
_storage = Storage(count: count, alignment: alignment)
|
||||||
_writerSize = _storage.capacity
|
_writerSize = _storage.capacity
|
||||||
|
allowReadingUnalignedBuffers = false
|
||||||
contiguousBytes.withUnsafeBytes { buf in
|
contiguousBytes.withUnsafeBytes { buf in
|
||||||
_storage.copy(from: buf.baseAddress!, count: buf.count)
|
_storage.copy(from: buf.baseAddress!, count: buf.count)
|
||||||
}
|
}
|
||||||
@@ -172,10 +178,12 @@ public struct ByteBuffer {
|
|||||||
/// - Parameter capacity: The size of the given memory region
|
/// - Parameter capacity: The size of the given memory region
|
||||||
public init(
|
public init(
|
||||||
assumingMemoryBound memory: UnsafeMutableRawPointer,
|
assumingMemoryBound memory: UnsafeMutableRawPointer,
|
||||||
capacity: Int)
|
capacity: Int,
|
||||||
|
allowReadingUnalignedBuffers allowUnalignedBuffers: Bool = false)
|
||||||
{
|
{
|
||||||
_storage = Storage(memory: memory, capacity: capacity, unowned: true)
|
_storage = Storage(memory: memory, capacity: capacity, unowned: true)
|
||||||
_writerSize = capacity
|
_writerSize = capacity
|
||||||
|
allowReadingUnalignedBuffers = allowUnalignedBuffers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a copy of the buffer that's being built by calling sizedBuffer
|
/// Creates a copy of the buffer that's being built by calling sizedBuffer
|
||||||
@@ -186,6 +194,7 @@ public struct ByteBuffer {
|
|||||||
_storage = Storage(count: count, alignment: alignment)
|
_storage = Storage(count: count, alignment: alignment)
|
||||||
_storage.copy(from: memory, count: count)
|
_storage.copy(from: memory, count: count)
|
||||||
_writerSize = _storage.capacity
|
_writerSize = _storage.capacity
|
||||||
|
allowReadingUnalignedBuffers = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a copy of the existing flatbuffer, by copying it to a different memory.
|
/// Creates a copy of the existing flatbuffer, by copying it to a different memory.
|
||||||
@@ -201,6 +210,7 @@ public struct ByteBuffer {
|
|||||||
_storage = Storage(count: count, alignment: alignment)
|
_storage = Storage(count: count, alignment: alignment)
|
||||||
_storage.copy(from: memory, count: count)
|
_storage.copy(from: memory, count: count)
|
||||||
_writerSize = removeBytes
|
_writerSize = removeBytes
|
||||||
|
allowReadingUnalignedBuffers = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fills the buffer with padding by adding to the writersize
|
/// Fills the buffer with padding by adding to the writersize
|
||||||
@@ -234,8 +244,13 @@ public struct ByteBuffer {
|
|||||||
mutating func push<T: NativeStruct>(struct value: T, size: Int) {
|
mutating func push<T: NativeStruct>(struct value: T, size: Int) {
|
||||||
ensureSpace(size: size)
|
ensureSpace(size: size)
|
||||||
var v = value
|
var v = value
|
||||||
memcpy(_storage.memory.advanced(by: writerIndex &- size), &v, size)
|
withUnsafeBytes(of: &v) {
|
||||||
_writerSize = _writerSize &+ size
|
memcpy(
|
||||||
|
_storage.memory.advanced(by: writerIndex &- size),
|
||||||
|
$0.baseAddress!,
|
||||||
|
size)
|
||||||
|
self._writerSize = self._writerSize &+ size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds an object of type Scalar into the buffer
|
/// Adds an object of type Scalar into the buffer
|
||||||
@@ -247,8 +262,13 @@ public struct ByteBuffer {
|
|||||||
mutating func push<T: Scalar>(value: T, len: Int) {
|
mutating func push<T: Scalar>(value: T, len: Int) {
|
||||||
ensureSpace(size: len)
|
ensureSpace(size: len)
|
||||||
var v = value
|
var v = value
|
||||||
memcpy(_storage.memory.advanced(by: writerIndex &- len), &v, len)
|
withUnsafeBytes(of: &v) {
|
||||||
_writerSize = _writerSize &+ len
|
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
|
/// Adds a string to the buffer using swift.utf8 object
|
||||||
@@ -352,7 +372,12 @@ public struct ByteBuffer {
|
|||||||
/// - position: the index of the object in the buffer
|
/// - position: the index of the object in the buffer
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
public func read<T>(def: T.Type, position: Int) -> T {
|
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
|
/// Reads a slice from the memory assuming a type of T
|
||||||
|
|||||||
@@ -154,6 +154,64 @@ class FlatBuffersMonsterWriterTests: XCTestCase {
|
|||||||
byteBuffer: &byteBuffer) as MyGame_Example_Monster))
|
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) {
|
func readMonster(monster: Monster) {
|
||||||
var monster = monster
|
var monster = monster
|
||||||
readFlatbufferMonster(monster: &monster)
|
readFlatbufferMonster(monster: &monster)
|
||||||
|
|||||||
Reference in New Issue
Block a user