[Swift] Add parsing from unowned UnsafeMutableRawPointer for ByteBuffer (#5981)
* RFC: Add ExternalStorage for ByteBuffer in Swift implementation This PR proposed one more API for ByteBuffer such that no copy is required to parse FlatBuffers content. This API has limited use, but for cases that you need to read part of the flatbuffers' data to decide whether you want to parse / copy the full buffer out, it is useful. * Use a variable rather than protocol. * Revert grouping changes from the other PR. * Add unit test to read from unowned UnsafePointer. * Manifest changed.
This commit is contained in:
parent
b124b76258
commit
f35184aef9
|
@ -5,7 +5,8 @@ public struct ByteBuffer {
|
|||
/// 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
|
||||
|
@ -14,17 +15,28 @@ public struct ByteBuffer {
|
|||
init(count: Int, alignment: Int) {
|
||||
memory = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: alignment)
|
||||
capacity = count
|
||||
unowned = false
|
||||
}
|
||||
|
||||
init(memory: UnsafeMutableRawPointer, capacity: Int, unowned: Bool) {
|
||||
self.memory = memory
|
||||
self.capacity = capacity
|
||||
self.unowned = unowned
|
||||
}
|
||||
|
||||
deinit {
|
||||
memory.deallocate()
|
||||
if !unowned {
|
||||
memory.deallocate()
|
||||
}
|
||||
}
|
||||
|
||||
func copy(from ptr: UnsafeRawPointer, count: Int) {
|
||||
precondition(!unowned)
|
||||
memory.copyMemory(from: ptr, byteCount: count)
|
||||
}
|
||||
|
||||
func initalize(for size: Int) {
|
||||
precondition(!unowned)
|
||||
memset(memory, 0, size)
|
||||
}
|
||||
|
||||
|
@ -94,6 +106,14 @@ public struct ByteBuffer {
|
|||
_storage = Storage(count: size, alignment: alignment)
|
||||
_storage.initalize(for: size)
|
||||
}
|
||||
|
||||
/// Constructor that creates a Flatbuffer from unsafe memory region without copying
|
||||
/// - Parameter assumingMemoryBound: The unsafe memory region
|
||||
/// - Parameter capacity: The size of the given memory region
|
||||
public init(assumingMemoryBound memory: UnsafeMutableRawPointer, capacity: Int) {
|
||||
_storage = Storage(memory: memory, capacity: capacity, unowned: true)
|
||||
_writerSize = capacity
|
||||
}
|
||||
|
||||
#if swift(>=5.0)
|
||||
/// Constructor that creates a Flatbuffer object from a ContiguousBytes
|
||||
|
|
|
@ -15,7 +15,7 @@ class FlatBuffersMonsterWriterTests: XCTestCase {
|
|||
readMonster(fb: _data)
|
||||
}
|
||||
|
||||
func testReadFromOtherLangagues() {
|
||||
func testReadFromOtherLanguages() {
|
||||
let path = FileManager.default.currentDirectoryPath
|
||||
let url = URL(fileURLWithPath: path, isDirectory: true).appendingPathComponent("monsterdata_test").appendingPathExtension("mon")
|
||||
guard let data = try? Data(contentsOf: url) else { return }
|
||||
|
@ -44,6 +44,18 @@ class FlatBuffersMonsterWriterTests: XCTestCase {
|
|||
let newBuf = FlatBuffersUtils.removeSizePrefix(bb: bytes.buffer)
|
||||
readMonster(fb: newBuf)
|
||||
}
|
||||
|
||||
func testReadMonsterFromUnsafePointerWithoutCopying() {
|
||||
var array: [UInt8] = [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]
|
||||
let unpacked = array.withUnsafeMutableBytes { (memory) -> MyGame.Example.MonsterT in
|
||||
let bytes = ByteBuffer(assumingMemoryBound: memory.baseAddress!, capacity: memory.count)
|
||||
var monster = Monster.getRootAsMonster(bb: bytes)
|
||||
readFlatbufferMonster(monster: &monster)
|
||||
let unpacked = monster.unpack()
|
||||
return unpacked
|
||||
}
|
||||
readObjectApi(monster: unpacked)
|
||||
}
|
||||
|
||||
func readMonster(fb: ByteBuffer) {
|
||||
var monster = Monster.getRootAsMonster(bb: fb)
|
||||
|
|
|
@ -21,7 +21,8 @@ extension FlatBuffersMonsterWriterTests {
|
|||
("testCreateMonsterPrefixed", testCreateMonsterPrefixed),
|
||||
("testCreateMonsterResizedBuffer", testCreateMonsterResizedBuffer),
|
||||
("testData", testData),
|
||||
("testReadFromOtherLangagues", testReadFromOtherLangagues),
|
||||
("testReadFromOtherLanguages", testReadFromOtherLanguages),
|
||||
("testReadMonsterFromUnsafePointerWithoutCopying", testReadMonsterFromUnsafePointerWithoutCopying),
|
||||
]
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue