[Swift] Implements FlatbuffersVector which confirms to RandomAccessCollection (#8752)

* Implements FlatbuffersVector in swift

Implements FlatbuffersVector which confirms to RandomAccessCollection,
this would give us semi-native sugary syntax to all the arrays in swift port.

This work will also be the foundation of using arrays in swift

* Fix failing tests for Swift
This commit is contained in:
mustiikhalil
2025-11-05 00:53:59 +01:00
committed by GitHub
parent 78a3d59a65
commit 5fe90a9160
63 changed files with 1554 additions and 1650 deletions

View File

@@ -29,8 +29,8 @@ public struct ByteBuffer {
@usableFromInline
enum Blob {
#if !os(WASI)
case data(Data)
case bytes(ContiguousBytes)
case data(Data)
case bytes(ContiguousBytes)
#endif
case byteBuffer(_InternalByteBuffer)
@@ -96,16 +96,16 @@ public struct ByteBuffer {
@inline(__always)
func withUnsafeBytes<T>(
_ body: (UnsafeRawBufferPointer) throws
-> T
) rethrows -> T {
-> T) rethrows -> T
{
switch retainedBlob {
case .byteBuffer(let byteBuffer):
return try byteBuffer.withUnsafeBytes(body)
#if !os(WASI)
case .data(let data):
return try data.withUnsafeBytes(body)
case .bytes(let contiguousBytes):
return try contiguousBytes.withUnsafeBytes(body)
case .data(let data):
return try data.withUnsafeBytes(body)
case .bytes(let contiguousBytes):
return try contiguousBytes.withUnsafeBytes(body)
#endif
case .array(let array):
return try array.withUnsafeBytes(body)
@@ -118,21 +118,21 @@ public struct ByteBuffer {
@inline(__always)
func withUnsafeRawPointer<T>(
_ body: (UnsafeMutableRawPointer) throws
-> T
) rethrows -> T {
-> T) rethrows -> T
{
switch retainedBlob {
case .byteBuffer(let byteBuffer):
return try byteBuffer.withUnsafeRawPointer(body)
#if !os(WASI)
case .data(let data):
return
try data
case .data(let data):
return
try data
.withUnsafeBytes {
try body(UnsafeMutableRawPointer(mutating: $0.baseAddress!))
}
case .bytes(let contiguousBytes):
return
try contiguousBytes
case .bytes(let contiguousBytes):
return
try contiguousBytes
.withUnsafeBytes {
try body(UnsafeMutableRawPointer(mutating: $0.baseAddress!))
}
@@ -140,9 +140,9 @@ public struct ByteBuffer {
case .array(let array):
return
try array
.withUnsafeBytes {
try body(UnsafeMutableRawPointer(mutating: $0.baseAddress!))
}
.withUnsafeBytes {
try body(UnsafeMutableRawPointer(mutating: $0.baseAddress!))
}
case .pointer(let ptr):
return try body(ptr)
}
@@ -152,20 +152,20 @@ public struct ByteBuffer {
@inline(__always)
func readWithUnsafeRawPointer<T>(
position: Int,
_ body: (UnsafeRawPointer) throws -> T
) rethrows -> T {
_ body: (UnsafeRawPointer) throws -> T) rethrows -> T
{
switch retainedBlob {
case .byteBuffer(let byteBuffer):
return try byteBuffer.readWithUnsafeRawPointer(position: position, body)
#if !os(WASI)
case .data(let data):
return try data.withUnsafeBytes {
try body($0.baseAddress!.advanced(by: position))
}
case .bytes(let contiguousBytes):
return try contiguousBytes.withUnsafeBytes {
try body($0.baseAddress!.advanced(by: position))
}
case .data(let data):
return try data.withUnsafeBytes {
try body($0.baseAddress!.advanced(by: position))
}
case .bytes(let contiguousBytes):
return try contiguousBytes.withUnsafeBytes {
try body($0.baseAddress!.advanced(by: position))
}
#endif
case .array(let array):
return try array.withUnsafeBytes {
@@ -207,8 +207,8 @@ public struct ByteBuffer {
@inline(__always)
public init(
copyingMemoryBound memory: UnsafeRawPointer,
capacity: Int
) {
capacity: Int)
{
_storage = Storage(count: capacity)
_storage.copy(from: memory, count: capacity)
_readerIndex = capacity
@@ -226,29 +226,29 @@ public struct ByteBuffer {
}
#if !os(WASI)
/// Constructor that creates a Flatbuffer from the Swift Data type object
/// - Parameter
/// - data: Swift data Object
@inline(__always)
public init(data: Data) {
_storage = Storage(blob: .data(data), capacity: data.count)
_readerIndex = data.count
capacity = data.count
}
/// Constructor that creates a Flatbuffer from the Swift Data type object
/// - Parameter
/// - data: Swift data Object
@inline(__always)
public init(data: Data) {
_storage = Storage(blob: .data(data), capacity: data.count)
_readerIndex = data.count
capacity = data.count
}
/// Constructor that creates a Flatbuffer object from a ContiguousBytes
/// - Parameters:
/// - contiguousBytes: Binary stripe to use as the buffer
/// - count: amount of readable bytes
@inline(__always)
public init<Bytes: ContiguousBytes>(
contiguousBytes: Bytes,
count: Int
) {
_storage = Storage(blob: .bytes(contiguousBytes), capacity: count)
_readerIndex = count
capacity = count
}
/// Constructor that creates a Flatbuffer object from a ContiguousBytes
/// - Parameters:
/// - contiguousBytes: Binary stripe to use as the buffer
/// - count: amount of readable bytes
@inline(__always)
public init<Bytes: ContiguousBytes>(
contiguousBytes: Bytes,
count: Int)
{
_storage = Storage(blob: .bytes(contiguousBytes), capacity: count)
_readerIndex = count
capacity = count
}
#endif
/// Constructor that creates a Flatbuffer from unsafe memory region without copying
@@ -260,8 +260,8 @@ public struct ByteBuffer {
@inline(__always)
public init(
assumingMemoryBound memory: UnsafeMutableRawPointer,
capacity: Int
) {
capacity: Int)
{
_storage = Storage(
blob: .pointer(memory),
capacity: capacity)
@@ -278,8 +278,8 @@ public struct ByteBuffer {
init(
blob: Storage.Blob,
count: Int,
removing removeBytes: Int
) {
removing removeBytes: Int)
{
_storage = Storage(blob: blob, capacity: count)
_readerIndex = removeBytes
capacity = count
@@ -371,8 +371,8 @@ public struct ByteBuffer {
t3: T3.Type,
t4: T4.Type,
position: Int,
byteWidth: UInt8
) -> T {
byteWidth: UInt8) -> T
{
switch byteWidth {
case 1:
numericCast(read(def: T1.self, position: position))
@@ -392,8 +392,8 @@ public struct ByteBuffer {
@inline(__always)
public func readSlice<T>(
index: Int,
count: Int
) -> [T] {
count: Int) -> [T]
{
assert(
index + count <= capacity,
"Reading out of bounds is illegal")
@@ -410,8 +410,8 @@ public struct ByteBuffer {
public func readString(
at index: Int,
count: Int,
type: String.Encoding
) -> String? {
type: String.Encoding) -> String?
{
assert(
index + count <= capacity,
"Reading out of bounds is illegal")
@@ -432,8 +432,8 @@ public struct ByteBuffer {
@inline(__always)
public func readString(
at index: Int,
count: Int
) -> String? {
count: Int) -> String?
{
assert(
index + count <= capacity,
"Reading out of bounds is illegal")
@@ -451,8 +451,8 @@ public struct ByteBuffer {
public func withUnsafePointerToSlice<T>(
index: Int,
count: Int,
body: (UnsafeRawBufferPointer) throws -> T
) rethrows -> T {
body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T
{
assert(
index + count <= capacity,
"Reading out of bounds is illegal")
@@ -465,8 +465,8 @@ public struct ByteBuffer {
@inline(__always)
public func withUnsafeBytes<T>(
body: (UnsafeRawBufferPointer) throws
-> T
) rethrows -> T {
-> T) rethrows -> T
{
try _storage.withUnsafeBytes(body)
}
@@ -474,8 +474,8 @@ public struct ByteBuffer {
@inline(__always)
func withUnsafeMutableRawPointer<T>(
body: (UnsafeMutableRawPointer) throws
-> T
) rethrows -> T {
-> T) rethrows -> T
{
try _storage.withUnsafeRawPointer(body)
}
@@ -483,8 +483,8 @@ public struct ByteBuffer {
@inline(__always)
func readWithUnsafeRawPointer<T>(
position: Int,
_ body: (UnsafeRawPointer) throws -> T
) rethrows -> T {
_ body: (UnsafeRawPointer) throws -> T) rethrows -> T
{
try _storage.readWithUnsafeRawPointer(position: position, body)
}
}

View File

@@ -46,8 +46,7 @@ public enum FlexBufferType: UInt64 {
@available(
*,
deprecated,
message: "use FBT_VECTOR or FBT_VECTOR_KEY instead."
)
message: "use FBT_VECTOR or FBT_VECTOR_KEY instead.")
case vectorString = 15
/// Typed tuples (no type table, no size field).

View File

@@ -31,8 +31,8 @@ public struct FixedTypedVector: FlexBufferVector {
offset: Int,
byteWidth: UInt8,
type: FlexBufferType,
count: Int
) {
count: Int)
{
self.byteBuffer = byteBuffer
self.offset = offset
self.byteWidth = byteWidth

View File

@@ -39,14 +39,13 @@ public protocol FlexBufferContiguousBytes {
var count: Int { get }
func withUnsafeRawBufferPointer<Result>(
_ body: (UnsafeRawBufferPointer) throws -> Result
) rethrows -> Result
_ body: (UnsafeRawBufferPointer) throws -> Result) rethrows -> Result
}
extension FlexBufferContiguousBytes {
public func withUnsafeRawBufferPointer<Result>(
_ body: (UnsafeRawBufferPointer) throws -> Result
) rethrows -> Result {
_ body: (UnsafeRawBufferPointer) throws -> Result) rethrows -> Result
{
try byteBuffer.withUnsafePointerToSlice(
index: offset,
count: count,

View File

@@ -58,8 +58,8 @@ public struct Reference {
byteBuffer: ByteBuffer,
offset: Int,
parentWidth: UInt8,
packedType: UInt8
) {
packedType: UInt8)
{
guard let type = FlexBufferType(rawValue: UInt64(packedType >> 2)) else {
return nil
}
@@ -76,8 +76,8 @@ public struct Reference {
offset: Int,
parentWidth: UInt8,
byteWidth: UInt8,
type: FlexBufferType
) {
type: FlexBufferType)
{
self.byteBuffer = byteBuffer
self.offset = offset
self.parentWidth = parentWidth
@@ -241,8 +241,7 @@ public struct Reference {
@inline(__always)
public func withUnsafeRawPointer<Result>(
_ completion: (UnsafeRawPointer) throws
-> Result
)
-> Result)
rethrows -> Result?
{
return try byteBuffer.readWithUnsafeRawPointer(

View File

@@ -30,8 +30,8 @@ public struct TypedVector: FlexBufferVector {
byteBuffer: ByteBuffer,
offset: Int,
byteWidth: UInt8,
type: FlexBufferType
) {
type: FlexBufferType)
{
self.byteBuffer = byteBuffer
self.offset = offset
self.byteWidth = byteWidth
@@ -54,8 +54,8 @@ public struct TypedVector: FlexBufferVector {
static func mapKeys(
byteBuffer: ByteBuffer,
offset: Int,
byteWidth: UInt8
) -> TypedVector {
byteWidth: UInt8) -> TypedVector
{
let prefixedFields = 3
let keysOffset = offset &- (numericCast(byteWidth) &* prefixedFields)
@@ -88,8 +88,8 @@ extension TypedVector {
byteWidth)
return byteBuffer.readWithUnsafeRawPointer(
position: indirectoffset
) { bufPointer in
position: indirectoffset)
{ bufPointer in
target.withCString { strPointer in
Int(strcmp(bufPointer, strPointer))
}

View File

@@ -17,7 +17,7 @@
import Foundation
#if canImport(Common)
import Common
import Common
#endif
extension UInt64 {

View File

@@ -17,7 +17,7 @@
import Foundation
#if canImport(Common)
import Common
import Common
#endif
public struct Value: Equatable {

View File

@@ -17,7 +17,7 @@
import Foundation
#if canImport(Common)
import Common
import Common
#endif
@inline(__always)
@@ -128,13 +128,14 @@ func toFixedTypedVectorElementType(type: FlexBufferType)
type.rawValue
&- FlexBufferType.vectorInt2
.rawValue)
let len: Int = numericCast(fixedType.dividedReportingOverflow(by: 3).partialValue &+ 2)
let len: Int = numericCast(
fixedType.dividedReportingOverflow(by: 3)
.partialValue &+ 2)
return (
FlexBufferType(
rawValue: (fixedType.quotientAndRemainder(dividingBy: 3).remainder)
&+ FlexBufferType.int.rawValue),
len
)
len)
}
// MARK: - Reader functions
@@ -142,8 +143,8 @@ func toFixedTypedVectorElementType(type: FlexBufferType)
@inline(__always)
func binarySearch(
vector: TypedVector,
target: String
) -> Int? {
target: String) -> Int?
{
var left = 0
var right = vector.count

View File

@@ -17,7 +17,7 @@
import Foundation
#if canImport(Common)
import Common
import Common
#endif
private let twentyFourBytes: Int = 24
@@ -74,21 +74,21 @@ public struct FlexBuffersWriter {
}
#if !os(WASI)
/// Data representation of the buffer
///
/// Should only be used after ``finish(offset:addPrefix:)`` is called
public var data: Data {
assert(finished, "Data shouldn't be called before finish()")
return _bb.withUnsafeSlicedBytes { ptr in
var data = Data()
data.append(
ptr.baseAddress!.bindMemory(
to: UInt8.self,
capacity: ptr.count),
count: ptr.count)
return data
}
/// Data representation of the buffer
///
/// Should only be used after ``finish(offset:addPrefix:)`` is called
public var data: Data {
assert(finished, "Data shouldn't be called before finish()")
return _bb.withUnsafeSlicedBytes { ptr in
var data = Data()
data.append(
ptr.baseAddress!.bindMemory(
to: UInt8.self,
capacity: ptr.count),
count: ptr.count)
return data
}
}
#endif
/// Resets the internal state. Automatically called before building a new flexbuffer.
@@ -139,8 +139,8 @@ public struct FlexBuffersWriter {
public mutating func endVector(
start: Int,
typed: Bool = false,
fixed: Bool = false
) -> UInt64 {
fixed: Bool = false) -> UInt64
{
let vec = createVector(
start: start,
count: stack.count &- start,
@@ -162,7 +162,8 @@ public struct FlexBuffersWriter {
@discardableResult
@inline(__always)
public mutating func create<T>(vector: [T], key: borrowing String) -> Int
where T: Scalar {
where T: Scalar
{
add(key: key)
return create(vector: vector, fixed: false)
}
@@ -178,8 +179,8 @@ public struct FlexBuffersWriter {
@inline(__always)
public mutating func createFixed<T>(
vector: [T],
key: borrowing String
) -> Int where T: Scalar {
key: borrowing String) -> Int where T: Scalar
{
assert(vector.count >= 2 && vector.count <= 4)
add(key: key)
return create(vector: vector, fixed: true)
@@ -301,8 +302,8 @@ public struct FlexBuffersWriter {
@inline(__always)
public mutating func add(
uint64 value: borrowing UInt64,
key: borrowing String
) {
key: borrowing String)
{
add(key: key)
add(uint64: value)
}
@@ -315,8 +316,8 @@ public struct FlexBuffersWriter {
@inline(__always)
public mutating func indirect(
uint64 val: borrowing UInt64,
key: borrowing String
) {
key: borrowing String)
{
add(key: key)
indirect(uint64: val)
}
@@ -324,8 +325,8 @@ public struct FlexBuffersWriter {
@inline(__always)
public mutating func indirect(
uint val: borrowing UInt,
key: borrowing String
) {
key: borrowing String)
{
add(key: key)
indirect(uint64: numericCast(val))
}
@@ -384,8 +385,8 @@ public struct FlexBuffersWriter {
@inline(__always)
public mutating func add(
int64 value: borrowing Int64,
key: borrowing String
) {
key: borrowing String)
{
add(key: key)
add(int64: value)
}
@@ -398,8 +399,8 @@ public struct FlexBuffersWriter {
@inline(__always)
public mutating func indirect(
int64 val: borrowing Int64,
key: borrowing String
) {
key: borrowing String)
{
add(key: key)
indirect(int64: val)
}
@@ -407,8 +408,8 @@ public struct FlexBuffersWriter {
@inline(__always)
public mutating func indirect(
int val: borrowing Int,
key: borrowing String
) {
key: borrowing String)
{
add(key: key)
indirect(int64: numericCast(val))
}
@@ -423,8 +424,8 @@ public struct FlexBuffersWriter {
@inline(__always)
public mutating func add(
float32 value: borrowing Float32,
key: borrowing String
) {
key: borrowing String)
{
add(key: key)
add(float32: value)
}
@@ -437,8 +438,8 @@ public struct FlexBuffersWriter {
@inline(__always)
public mutating func indirect(
float32 val: borrowing Float32,
key: borrowing String
) {
key: borrowing String)
{
add(key: key)
indirect(float32: val)
}
@@ -451,8 +452,8 @@ public struct FlexBuffersWriter {
@inline(__always)
public mutating func add(
double value: borrowing Double,
key: borrowing String
) {
key: borrowing String)
{
add(key: key)
add(double: value)
}
@@ -465,8 +466,8 @@ public struct FlexBuffersWriter {
@inline(__always)
public mutating func indirect(
double val: borrowing Double,
key: borrowing String
) {
key: borrowing String)
{
add(key: key)
indirect(double: val)
}
@@ -488,8 +489,8 @@ public struct FlexBuffersWriter {
@inline(__always)
public mutating func add<T>(
blob: borrowing T,
length l: Int
) -> UInt where T: ContiguousBytes {
length l: Int) -> UInt where T: ContiguousBytes
{
storeBlob(blob, len: l, type: .blob)
}
@@ -498,8 +499,8 @@ public struct FlexBuffersWriter {
public mutating func add<T>(
blob: borrowing T,
key: borrowing String,
length l: Int
) -> UInt where T: ContiguousBytes {
length l: Int) -> UInt where T: ContiguousBytes
{
add(key: key)
return storeBlob(blob, len: l, type: .blob)
}
@@ -540,8 +541,8 @@ public struct FlexBuffersWriter {
mutating func pushIndirect<T>(
value: T,
type: FlexBufferType,
bitWidth: BitWidth
) {
bitWidth: BitWidth)
{
let byteWidth = align(width: bitWidth)
let iloc = writerIndex
_bb.ensureSpace(size: byteWidth)
@@ -618,8 +619,8 @@ public struct FlexBuffersWriter {
mutating func storeBlob<T>(
_ bytes: T,
len: Int,
type: FlexBufferType
) -> UInt where T: ContiguousBytes {
type: FlexBufferType) -> UInt where T: ContiguousBytes
{
return bytes.withUnsafeBytes {
storeBlob(pointer: $0.baseAddress!, len: len, type: type)
}
@@ -631,8 +632,8 @@ public struct FlexBuffersWriter {
pointer: borrowing UnsafeRawPointer,
len: Int,
trailing: Int = 0,
type: FlexBufferType
) -> UInt {
type: FlexBufferType) -> UInt
{
_bb.ensureSpace(size: len &+ trailing)
let bitWidth = widthU(numericCast(len))
@@ -655,7 +656,8 @@ public struct FlexBuffersWriter {
@discardableResult
@usableFromInline
mutating func create<T>(vector: [T], fixed: Bool) -> Int
where T: Scalar {
where T: Scalar
{
let length: UInt64 = numericCast(vector.count)
let vectorType = getScalarType(type: T.self)
let byteWidth = MemoryLayout<T>.size
@@ -691,8 +693,8 @@ public struct FlexBuffersWriter {
step: Int,
typed: Bool,
fixed: Bool,
keys: Value? = nil
) -> Value {
keys: Value? = nil) -> Value
{
assert(
!fixed || typed,
"Typed false and fixed true is a combination not supported currently")
@@ -857,8 +859,8 @@ extension FlexBuffersWriter {
@discardableResult
public mutating func vector(
key: String,
_ closure: FlexBuffersWriterBuilder
) -> UInt64 {
_ closure: FlexBuffersWriterBuilder) -> UInt64
{
let start = startVector(key: key)
closure(&self)
return endVector(start: start)
@@ -879,8 +881,8 @@ extension FlexBuffersWriter {
@discardableResult
public mutating func map(
key: String,
_ closure: FlexBuffersWriterBuilder
) -> UInt64 {
_ closure: FlexBuffersWriterBuilder) -> UInt64
{
let start = startMap(key: key)
closure(&self)
return endMap(start: start)

View File

@@ -17,7 +17,7 @@
import Foundation
#if canImport(Common)
import Common
import Common
#endif
/// `ByteBuffer` is the interface that stores the data for a `Flatbuffers` object
@@ -55,8 +55,8 @@ struct _InternalByteBuffer {
func reallocate(
capacity: Int,
writerSize: Int,
alignment: Int
) {
alignment: Int)
{
let newData = UnsafeMutableRawPointer.allocate(
byteCount: capacity,
alignment: alignment)
@@ -135,18 +135,17 @@ struct _InternalByteBuffer {
_storage.reallocate(
capacity: capacity,
writerSize: writerIndex,
alignment: alignment
)
alignment: alignment)
}
@inline(__always)
mutating func addPadding(bytes: Int) {
writerIndex =
writerIndex
&+ numericCast(
padding(
bufSize: numericCast(writerIndex),
elementSize: numericCast(bytes)))
&+ numericCast(
padding(
bufSize: numericCast(writerIndex),
elementSize: numericCast(bytes)))
ensureSpace(size: writerIndex)
}
@@ -174,8 +173,8 @@ struct _InternalByteBuffer {
@inline(__always)
func withUnsafeBytes<T>(
_ body: (UnsafeRawBufferPointer) throws
-> T
) rethrows -> T {
-> T) rethrows -> T
{
try body(
UnsafeRawBufferPointer(
start: _storage.memory,
@@ -186,8 +185,8 @@ struct _InternalByteBuffer {
@inline(__always)
func withUnsafeSlicedBytes<T>(
_ body: (UnsafeRawBufferPointer) throws
-> T
) rethrows -> T {
-> T) rethrows -> T
{
try body(
UnsafeRawBufferPointer(
start: _storage.memory,
@@ -198,8 +197,8 @@ struct _InternalByteBuffer {
@inline(__always)
func withUnsafeRawPointer<T>(
_ body: (UnsafeMutableRawPointer) throws
-> T
) rethrows -> T {
-> T) rethrows -> T
{
try body(_storage.memory)
}
@@ -207,8 +206,8 @@ struct _InternalByteBuffer {
@inline(__always)
func readWithUnsafeRawPointer<T>(
position: Int,
_ body: (UnsafeRawPointer) throws -> T
) rethrows -> T {
_ body: (UnsafeRawPointer) throws -> T) rethrows -> T
{
try body(_storage.memory.advanced(by: position))
}
}