mirror of
https://github.com/google/flatbuffers.git
synced 2026-07-05 06:57:03 +00:00
[Swift] Adds new API to reduce memory copying within swift (#8484)
* Adds new API to reduce memory copying within swift Adds new storage container _InternalByteBuffer which will be holding the data that will be created within the swift lib, however reading data will be redirected to ByteBuffer, which should be able to handle all types of data that swift provide without the need to copy the data itself. This is due to holding a reference to the data. Replaces assumingMemoryBinding with bindMemory which is safer Adds function that provides access to a UnsafeBufferPointer for scalars and NativeStructs within swift Updates docs Suppress compilation warnings by replacing var with let Using overflow operators within swift to improve performance Adds tests for GRPC message creation from a retained _InternalByteBuffer
This commit is contained in:
@@ -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<VOffset>.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<UInt8>.size)
|
||||
_bb.push(bytes: bytes)
|
||||
return endVector(len: size)
|
||||
bytes.withUnsafeBytes {
|
||||
startVector($0.count, elementSize: MemoryLayout<UInt8>.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<T>(def: T.Type, position: Int) -> T {
|
||||
_bb.read(def: def, position: position)
|
||||
}
|
||||
}
|
||||
|
||||
extension FlatBufferBuilder: CustomDebugStringConvertible {
|
||||
|
||||
Reference in New Issue
Block a user