mirror of
https://github.com/google/flatbuffers.git
synced 2026-11-11 22:46:21 +00:00
Bigfoot
This commit is contained in:
@@ -28,7 +28,7 @@ public let FileIdLength = 4
|
||||
/// Protocol that All Scalars should conform to
|
||||
///
|
||||
/// Scalar is used to conform all the numbers that can be represented in a FlatBuffer. It's used to write/read from the buffer.
|
||||
public protocol Scalar: Equatable, BitwiseCopyable {
|
||||
public protocol Scalar: Equatable {
|
||||
associatedtype NumericValue
|
||||
var convertedEndian: NumericValue { get }
|
||||
}
|
||||
|
||||
@@ -20,56 +20,22 @@ import Foundation
|
||||
/// it allows users to write and read data directly from memory thus the use of its
|
||||
/// functions should be used
|
||||
@frozen
|
||||
public struct ByteBuffer: @unchecked Sendable {
|
||||
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 {
|
||||
@usableFromInline
|
||||
@frozen enum Blob: ~Copyable {
|
||||
enum Blob {
|
||||
#if !os(WASI)
|
||||
case data(Data)
|
||||
case bytes(any ContiguousBytes)
|
||||
case bytes(ContiguousBytes)
|
||||
#endif
|
||||
|
||||
case byteBuffer(_InternalByteBuffer)
|
||||
case array([UInt8])
|
||||
case pointer(UnsafeMutableRawPointer)
|
||||
|
||||
init(_ other: borrowing Blob) {
|
||||
switch other {
|
||||
#if !os(WASI)
|
||||
case .data(let data):
|
||||
self = .data(data)
|
||||
case .bytes(let contiguousBytes):
|
||||
self = .bytes(contiguousBytes)
|
||||
#endif
|
||||
case .byteBuffer(let internalByteBuffer):
|
||||
self = .byteBuffer(internalByteBuffer)
|
||||
case .array(let array):
|
||||
self = .array(array)
|
||||
case .pointer(let unsafeMutableRawPointer):
|
||||
self = .pointer(unsafeMutableRawPointer)
|
||||
}
|
||||
}
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
#if !os(WASI)
|
||||
case .data(let data):
|
||||
"data: \(data)"
|
||||
case .bytes(let contiguousBytes):
|
||||
"bytes: \(contiguousBytes)"
|
||||
#endif
|
||||
case .byteBuffer(let internalByteBuffer):
|
||||
"byteBuffer: \(internalByteBuffer)"
|
||||
case .array(let array):
|
||||
"array: \(array)"
|
||||
case .pointer(let unsafeMutableRawPointer):
|
||||
"pointer: \(unsafeMutableRawPointer)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This storage doesn't own the memory, therefore, we won't deallocate on deinit.
|
||||
@@ -78,7 +44,7 @@ public struct ByteBuffer: @unchecked Sendable {
|
||||
private let capacity: Int
|
||||
/// Retained blob of data that requires the storage to retain a pointer to.
|
||||
@usableFromInline
|
||||
let retainedBlob: Blob
|
||||
var retainedBlob: Blob
|
||||
|
||||
@usableFromInline
|
||||
init(count: Int) {
|
||||
@@ -91,9 +57,9 @@ public struct ByteBuffer: @unchecked Sendable {
|
||||
}
|
||||
|
||||
@usableFromInline
|
||||
init(blob: borrowing Blob, capacity count: Int) {
|
||||
init(blob: Blob, capacity count: Int) {
|
||||
capacity = count
|
||||
retainedBlob = .init(blob)
|
||||
retainedBlob = blob
|
||||
isOwned = false
|
||||
}
|
||||
|
||||
@@ -184,7 +150,6 @@ public struct ByteBuffer: @unchecked Sendable {
|
||||
|
||||
@discardableResult
|
||||
@inline(__always)
|
||||
@inlinable
|
||||
func readWithUnsafeRawPointer<T>(
|
||||
position: Int,
|
||||
_ body: (UnsafeRawPointer) throws -> T) rethrows -> T
|
||||
@@ -313,7 +278,7 @@ public struct ByteBuffer: @unchecked Sendable {
|
||||
/// - removeBytes: Removes a number of bytes from the current size
|
||||
@inline(__always)
|
||||
init(
|
||||
blob: borrowing Storage.Blob,
|
||||
blob: Storage.Blob,
|
||||
count: Int,
|
||||
removing removeBytes: Int)
|
||||
{
|
||||
@@ -353,8 +318,7 @@ public struct ByteBuffer: @unchecked Sendable {
|
||||
/// - def: Type of the object
|
||||
/// - position: the index of the object in the buffer
|
||||
@inline(__always)
|
||||
@inlinable
|
||||
public func read<T: BitwiseCopyable>(def: T.Type, position: Int) -> T {
|
||||
public func read<T>(def: T.Type, position: Int) -> T {
|
||||
_storage.readWithUnsafeRawPointer(position: position) {
|
||||
$0.bindMemory(to: T.self, capacity: 1)
|
||||
.pointee
|
||||
@@ -448,7 +412,7 @@ public struct ByteBuffer: @unchecked Sendable {
|
||||
/// - Parameter removeBytes: the amount of bytes to remove from the current Size
|
||||
@inline(__always)
|
||||
public func duplicate(removing removeBytes: Int = 0) -> ByteBuffer {
|
||||
assert(removeBytes >= 0, "Can NOT remove negative bytes")
|
||||
assert(removeBytes > 0, "Can NOT remove negative bytes")
|
||||
assert(
|
||||
removeBytes < capacity,
|
||||
"Can NOT remove more bytes than the ones allocated")
|
||||
@@ -500,9 +464,8 @@ public struct ByteBuffer: @unchecked Sendable {
|
||||
extension ByteBuffer: CustomDebugStringConvertible {
|
||||
|
||||
public var debugDescription: String {
|
||||
let blobDescription = _storage.retainedBlob.description
|
||||
return """
|
||||
buffer located at: \(blobDescription),
|
||||
"""
|
||||
buffer located at: \(_storage.retainedBlob),
|
||||
with capacity of \(capacity),
|
||||
{ writtenSize: \(_readerIndex), readerSize: \(reader),
|
||||
size: \(size) }
|
||||
|
||||
@@ -23,7 +23,7 @@ import Common
|
||||
/// Enum is a protocol that all flatbuffers enums should conform to
|
||||
/// Since it allows us to get the actual `ByteSize` and `Value` from
|
||||
/// a swift enum.
|
||||
public protocol Enum: Sendable {
|
||||
public protocol Enum {
|
||||
/// associatedtype that the type of the enum should conform to
|
||||
associatedtype T: Scalar & Verifiable
|
||||
/// Size of the current associatedtype in the enum
|
||||
|
||||
@@ -45,10 +45,9 @@ public struct FlatBufferBuilder {
|
||||
/// Dictonary that stores a map of all the strings that were written to the buffer
|
||||
private var stringOffsetMap: [String: Offset] = [:]
|
||||
/// A check to see if finish(::) was ever called to retreive data object
|
||||
private(set) var finished = false
|
||||
private var finished = false
|
||||
/// A check to see if the buffer should serialize Default values
|
||||
@usableFromInline
|
||||
let serializeDefaults: Bool
|
||||
private var serializeDefaults: Bool
|
||||
|
||||
/// Current alignment for the buffer
|
||||
var _minAlignment: Int = 0 {
|
||||
@@ -489,7 +488,7 @@ public struct FlatBufferBuilder {
|
||||
///
|
||||
/// - Parameter bytes: bytes to be written into the buffer
|
||||
/// - Returns: ``Offset`` of the vector
|
||||
mutating public func createVector(bytes: any ContiguousBytes) -> Offset {
|
||||
mutating public func createVector(bytes: ContiguousBytes) -> Offset {
|
||||
bytes.withUnsafeBytes {
|
||||
startVector($0.count, elementSize: MemoryLayout<UInt8>.size)
|
||||
_bb.push(bytes: $0)
|
||||
@@ -757,7 +756,6 @@ public struct FlatBufferBuilder {
|
||||
/// - offset: ``Offset`` of another object to be written
|
||||
/// - position: The predefined position of the object
|
||||
@inline(__always)
|
||||
@inlinable
|
||||
mutating public func add(offset: Offset, at position: VOffset) {
|
||||
if offset.isEmpty { return }
|
||||
add(element: refer(to: offset.o), def: 0, at: position)
|
||||
@@ -796,7 +794,6 @@ public struct FlatBufferBuilder {
|
||||
/// - def: Default value for that element
|
||||
/// - position: The predefined position of the element
|
||||
@inline(__always)
|
||||
@inlinable
|
||||
mutating public func add<T: Scalar>(
|
||||
element: T,
|
||||
def: T,
|
||||
@@ -816,7 +813,6 @@ public struct FlatBufferBuilder {
|
||||
/// - element: Optional element of type scalar
|
||||
/// - position: The predefined position of the element
|
||||
@inline(__always)
|
||||
@inlinable
|
||||
mutating public func add<T: Scalar>(element: T?, at position: VOffset) {
|
||||
guard let element = element else { return }
|
||||
track(offset: push(element: element), at: position)
|
||||
@@ -829,7 +825,6 @@ public struct FlatBufferBuilder {
|
||||
/// - Parameter element: Element to insert
|
||||
/// - returns: position of the Element
|
||||
@inline(__always)
|
||||
@inlinable
|
||||
@discardableResult
|
||||
mutating public func push<T: Scalar>(element: T) -> UOffset {
|
||||
let size = MemoryLayout<T>.size
|
||||
@@ -841,8 +836,7 @@ public struct FlatBufferBuilder {
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
@inlinable
|
||||
public func read<T: BitwiseCopyable>(def: T.Type, position: Int) -> T {
|
||||
public func read<T>(def: T.Type, position: Int) -> T {
|
||||
_bb.read(def: def, position: position)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,7 @@ import Foundation
|
||||
|
||||
/// NativeStruct is a protocol that indicates if the struct is a native `swift` struct
|
||||
/// since now we will be serializing native structs into the buffer.
|
||||
public protocol NativeStruct: BitwiseCopyable {}
|
||||
|
||||
public protocol FlatBufferVerifiableNativeStruct: NativeStruct, Verifiable {}
|
||||
public protocol NativeStruct {}
|
||||
|
||||
/// FlatbuffersInitializable is a protocol that allows any object to be
|
||||
/// Initialized from a ByteBuffer
|
||||
@@ -37,8 +35,6 @@ public protocol FlatBufferTable: FlatbuffersInitializable,
|
||||
var __buffer: ByteBuffer! { get }
|
||||
}
|
||||
|
||||
public protocol FlatBufferVerifiableTable: FlatBufferTable, Verifiable {}
|
||||
|
||||
/// FlatbufferStruct structures all the Flatbuffers structs
|
||||
public protocol FlatBufferStruct: FlatbuffersInitializable,
|
||||
FlatbuffersVectorInitializable
|
||||
|
||||
@@ -16,52 +16,50 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
enum FlatbuffersGRPCError: Error {
|
||||
case finishedNotCalledOnBuilder
|
||||
}
|
||||
/// FlatBufferGRPCMessage protocol that should allow us to invoke
|
||||
/// initializers directly from the GRPC generated code
|
||||
public protocol FlatBufferGRPCMessage {
|
||||
/// Size of readable bytes in the buffer
|
||||
var size: Int { get }
|
||||
|
||||
public protocol GRPCVerifiableMessage<Message> {
|
||||
associatedtype Message
|
||||
|
||||
init(pointer: UnsafeRawBufferPointer)
|
||||
init(byteBuffer: ByteBuffer)
|
||||
|
||||
func decode() throws -> Message
|
||||
func withUnsafeReadableBytes<Data>(
|
||||
@discardableResult
|
||||
@inline(__always)
|
||||
func withUnsafeReadableBytes<T>(
|
||||
_ body: (UnsafeRawBufferPointer) throws
|
||||
-> Data) rethrows -> Data
|
||||
-> T) rethrows -> T
|
||||
}
|
||||
|
||||
public struct GRPCMessage<
|
||||
Table: FlatBufferVerifiableTable
|
||||
>: Sendable, GRPCVerifiableMessage {
|
||||
public typealias Message = Table
|
||||
/// Message is a wrapper around Buffers to to able to send Flatbuffers `Buffers` through the
|
||||
/// GRPC library
|
||||
public struct Message<T: FlatBufferTable>: FlatBufferGRPCMessage {
|
||||
internal var buffer: ByteBuffer
|
||||
|
||||
private let buffer: ByteBuffer
|
||||
/// Returns the an object of type T that would be read from the buffer
|
||||
public var object: T {
|
||||
T.init(
|
||||
buffer,
|
||||
o: Int32(buffer.read(def: UOffset.self, position: buffer.reader)) &+
|
||||
Int32(buffer.reader))
|
||||
}
|
||||
|
||||
public var size: Int { Int(buffer.size) }
|
||||
|
||||
public init(pointer: UnsafeRawBufferPointer) {
|
||||
buffer = ByteBuffer(
|
||||
copyingMemoryBound: pointer.baseAddress!,
|
||||
capacity: pointer.count)
|
||||
}
|
||||
|
||||
public init(builder: inout FlatBufferBuilder) throws {
|
||||
guard builder.finished else {
|
||||
throw FlatbuffersGRPCError.finishedNotCalledOnBuilder
|
||||
}
|
||||
|
||||
buffer = builder.sizedBuffer
|
||||
}
|
||||
|
||||
/// Initializes the message with the type Flatbuffer.Bytebuffer that is transmitted over
|
||||
/// GRPC
|
||||
/// - Parameter byteBuffer: Flatbuffer ByteBuffer object
|
||||
public init(byteBuffer: ByteBuffer) {
|
||||
buffer = byteBuffer
|
||||
}
|
||||
|
||||
public func decode() throws -> Table {
|
||||
var buf = buffer
|
||||
return try getCheckedRoot(byteBuffer: &buf)
|
||||
/// Initializes the message by copying the buffer to the message to be sent.
|
||||
/// from the builder
|
||||
/// - Parameter builder: FlatbufferBuilder that has the bytes created in
|
||||
/// - Note: Use `builder.finish(offset)` before passing the builder without prefixing anything to it
|
||||
public init(builder: inout FlatBufferBuilder) {
|
||||
buffer = builder.sizedBuffer
|
||||
builder.clear()
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
@@ -75,30 +73,3 @@ public struct GRPCMessage<
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
|
||||
public struct FlatBuffersMessageSerializer<
|
||||
Message: GRPCVerifiableMessage
|
||||
>: Sendable {
|
||||
public init() {}
|
||||
|
||||
public func serialize<Data>(
|
||||
message: Message,
|
||||
_ completion: (UnsafeRawBufferPointer) throws -> Data) throws -> Data
|
||||
{
|
||||
return try message.withUnsafeReadableBytes {
|
||||
try completion($0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
|
||||
public struct FlatBuffersMessageDeserializer<
|
||||
Message: GRPCVerifiableMessage
|
||||
>: Sendable {
|
||||
public init() {}
|
||||
|
||||
public func deserialize(pointer: UnsafeRawBufferPointer) throws -> Message {
|
||||
Message.init(pointer: pointer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,30 +16,6 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
@inline(__always)
|
||||
private func verifySizePrefix(
|
||||
byteBuffer: inout ByteBuffer,
|
||||
requireExactSize: Bool,
|
||||
options: VerifierOptions) throws
|
||||
{
|
||||
let verifier = try Verifier(buffer: &byteBuffer, options: options)
|
||||
let prefixPosition = byteBuffer.reader
|
||||
let prefix: UOffset = try verifier.getValue(at: prefixPosition)
|
||||
let availableSize = byteBuffer.size &- UOffset(MemoryLayout<UOffset>.size)
|
||||
|
||||
if requireExactSize {
|
||||
guard prefix == availableSize else {
|
||||
throw FlatbuffersErrors.prefixedSizeNotEqualToBufferSize
|
||||
}
|
||||
} else if prefix > availableSize {
|
||||
throw FlatbuffersErrors.outOfBounds(
|
||||
position: UInt(prefixPosition)
|
||||
&+ UInt(MemoryLayout<UOffset>.size)
|
||||
&+ UInt(prefix),
|
||||
end: byteBuffer.capacity)
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes in a prefixed sized buffer, where the prefixed size would be skipped.
|
||||
/// And would verify that the buffer passed is a valid `Flatbuffers` Object.
|
||||
/// - Parameters:
|
||||
@@ -55,10 +31,6 @@ public func getPrefixedSizeCheckedRoot<T: FlatBufferTable & Verifiable>(
|
||||
fileId: String? = nil,
|
||||
options: VerifierOptions = .init()) throws -> T
|
||||
{
|
||||
try verifySizePrefix(
|
||||
byteBuffer: &byteBuffer,
|
||||
requireExactSize: false,
|
||||
options: options)
|
||||
byteBuffer.skipPrefix()
|
||||
return try getCheckedRoot(
|
||||
byteBuffer: &byteBuffer,
|
||||
@@ -81,11 +53,10 @@ public func getCheckedPrefixedSizeRoot<T: FlatBufferTable & Verifiable>(
|
||||
fileId: String? = nil,
|
||||
options: VerifierOptions = .init()) throws -> T
|
||||
{
|
||||
try verifySizePrefix(
|
||||
byteBuffer: &byteBuffer,
|
||||
requireExactSize: true,
|
||||
options: options)
|
||||
byteBuffer.skipPrefix()
|
||||
let prefix = byteBuffer.skipPrefix()
|
||||
if prefix != byteBuffer.size {
|
||||
throw FlatbuffersErrors.prefixedSizeNotEqualToBufferSize
|
||||
}
|
||||
return try getCheckedRoot(
|
||||
byteBuffer: &byteBuffer,
|
||||
fileId: fileId,
|
||||
@@ -124,15 +95,14 @@ public func getCheckedRoot<T: FlatBufferTable & Verifiable>(
|
||||
options: VerifierOptions = .init()) throws -> T
|
||||
{
|
||||
var verifier = try Verifier(buffer: &byteBuffer, options: options)
|
||||
let rootPosition = byteBuffer.reader
|
||||
if let fileId = fileId {
|
||||
try verifier.verify(id: fileId, at: rootPosition)
|
||||
try verifier.verify(id: fileId)
|
||||
}
|
||||
try ForwardOffset<T>.verify(&verifier, at: rootPosition, of: T.self)
|
||||
try ForwardOffset<T>.verify(&verifier, at: 0, of: T.self)
|
||||
return T.init(
|
||||
byteBuffer,
|
||||
o: Int32(byteBuffer.read(def: UOffset.self, position: rootPosition))
|
||||
&+ Int32(rootPosition))
|
||||
o: Int32(byteBuffer.read(def: UOffset.self, position: byteBuffer.reader))
|
||||
&+ Int32(byteBuffer.reader))
|
||||
}
|
||||
|
||||
/// Returns a `NON-Checked` flatbuffers object
|
||||
|
||||
@@ -49,7 +49,7 @@ public struct Table {
|
||||
/// the vtable
|
||||
/// - Parameter o: current offset
|
||||
/// - Returns: offset of field within buffer
|
||||
public func offset(_ o: VOffset) -> Int32 {
|
||||
public func offset(_ o: Int32) -> Int32 {
|
||||
let vtable = position &- bb.read(def: Int32.self, position: Int(position))
|
||||
return o
|
||||
< bb
|
||||
@@ -57,7 +57,7 @@ public struct Table {
|
||||
? Int32(
|
||||
bb.read(
|
||||
def: Int16.self,
|
||||
position: Int(vtable &+ Int32(o)))) : 0
|
||||
position: Int(vtable &+ o))) : 0
|
||||
}
|
||||
|
||||
/// Gets the indirect offset of the current stored object
|
||||
@@ -82,7 +82,7 @@ public struct Table {
|
||||
/// - Parameters:
|
||||
/// - type: Type of Element that needs to be read from the buffer
|
||||
/// - o: Offset of the Element
|
||||
public func readBuffer<T: BitwiseCopyable>(of type: T.Type, at o: Int32) -> T {
|
||||
public func readBuffer<T>(of type: T.Type, at o: Int32) -> T {
|
||||
bb.read(def: T.self, position: Int(o &+ position))
|
||||
}
|
||||
|
||||
@@ -106,13 +106,13 @@ public struct Table {
|
||||
/// This should only be used by `Scalars`
|
||||
/// - Parameter off: Readable offset
|
||||
/// - Returns: Returns a vector of type [T]
|
||||
public func getVector<T>(at off: VOffset) -> [T]? {
|
||||
public func getVector<T>(at off: Int32) -> [T]? {
|
||||
let o = offset(off)
|
||||
guard o != 0 else { return nil }
|
||||
return bb.readSlice(index: Int(vector(at: o)), count: Int(vector(count: o)))
|
||||
}
|
||||
|
||||
public func vector<T>(at off: VOffset, byteSize: Int) -> FlatbufferVector<T> {
|
||||
public func vector<T>(at off: Int32, byteSize: Int) -> FlatbufferVector<T> {
|
||||
let off = offset(off)
|
||||
return FlatbufferVector(
|
||||
bb: bb,
|
||||
@@ -122,7 +122,7 @@ public struct Table {
|
||||
}
|
||||
|
||||
public func unionVector(
|
||||
at off: VOffset,
|
||||
at off: Int32,
|
||||
byteSize: Int) -> UnionFlatbufferVector
|
||||
{
|
||||
let off = offset(off)
|
||||
@@ -146,7 +146,7 @@ public struct Table {
|
||||
/// - Returns: Returns a pointer to the underlying data
|
||||
@inline(__always)
|
||||
public func withUnsafePointerToSlice<T>(
|
||||
at off: VOffset,
|
||||
at off: Int32,
|
||||
body: (UnsafeRawBufferPointer, Int) throws -> T) rethrows -> T?
|
||||
{
|
||||
let o = offset(off)
|
||||
|
||||
@@ -115,7 +115,7 @@ public struct TableVerifier {
|
||||
unionKeyName: String,
|
||||
fieldName: String,
|
||||
required: Bool,
|
||||
completion: (inout Verifier, T, Int) throws -> Void) throws
|
||||
completion: @escaping (inout Verifier, T, Int) throws -> Void) throws
|
||||
where T: UnionEnum
|
||||
{
|
||||
let keyPos = try dereference(key)
|
||||
|
||||
@@ -68,7 +68,7 @@ public struct FlatbufferVector<
|
||||
}
|
||||
|
||||
extension FlatbufferVector: Encodable where Element: Encodable {
|
||||
public func encode(to encoder: any Encoder) throws {
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.unkeyedContainer()
|
||||
for element in self {
|
||||
try container.encode(element)
|
||||
|
||||
@@ -49,8 +49,8 @@ public struct UnionFlatbufferVector {
|
||||
|
||||
public subscript(
|
||||
position: Int,
|
||||
Type: any FlatbuffersVectorInitializable
|
||||
.Type) -> any FlatbuffersVectorInitializable
|
||||
Type: FlatbuffersVectorInitializable
|
||||
.Type) -> FlatbuffersVectorInitializable
|
||||
{
|
||||
guard position < count else {
|
||||
fatalError(
|
||||
|
||||
@@ -56,15 +56,8 @@ extension Verifiable {
|
||||
let len: UOffset = try verifier.getValue(at: position)
|
||||
let intLen = Int(len)
|
||||
let start = Int(clamping: (position &+ MemoryLayout<Int32>.size).magnitude)
|
||||
let byteCount = intLen.multipliedReportingOverflow(
|
||||
by: MemoryLayout<T>.size)
|
||||
guard !byteCount.overflow else {
|
||||
throw FlatbuffersErrors.outOfBounds(
|
||||
position: UInt.max,
|
||||
end: verifier.capacity)
|
||||
}
|
||||
try verifier.isAligned(position: start, type: type.self)
|
||||
try verifier.rangeInBuffer(position: start, size: byteCount.partialValue)
|
||||
try verifier.rangeInBuffer(position: start, size: intLen)
|
||||
return (start, intLen)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ public struct Verifier {
|
||||
/// - Parameter position: Current position to be read
|
||||
/// - Throws: `inBuffer` errors
|
||||
/// - Returns: a value of type `T` usually a `VTable` or a table offset
|
||||
internal func getValue<T: BitwiseCopyable>(at position: Int) throws -> T {
|
||||
internal func getValue<T>(at position: Int) throws -> T {
|
||||
try inBuffer(position: position, of: T.self)
|
||||
return _buffer.read(def: T.self, position: position)
|
||||
}
|
||||
@@ -215,16 +215,12 @@ public struct Verifier {
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
func verify(id: String, at position: Int) throws {
|
||||
func verify(id: String) throws {
|
||||
let size = MemoryLayout<Int32>.size
|
||||
guard
|
||||
position >= 0,
|
||||
position <= storage.capacity,
|
||||
storage.capacity - position >= size &* 2
|
||||
else {
|
||||
guard storage.capacity >= (size &* 2) else {
|
||||
throw FlatbuffersErrors.bufferDoesntContainID
|
||||
}
|
||||
let str = _buffer.readString(at: position &+ size, count: size)
|
||||
let str = _buffer.readString(at: size, count: size)
|
||||
if id == str {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ struct _InternalByteBuffer {
|
||||
@usableFromInline
|
||||
final class Storage {
|
||||
/// pointer to the start of the buffer object in memory
|
||||
@exclusivity(unchecked) private(set) var memory: UnsafeMutableRawPointer
|
||||
private(set) var memory: UnsafeMutableRawPointer
|
||||
|
||||
@usableFromInline
|
||||
init(count: Int, alignment: Int) {
|
||||
@@ -146,7 +146,7 @@ struct _InternalByteBuffer {
|
||||
#if !os(WASI)
|
||||
@inline(__always)
|
||||
@usableFromInline
|
||||
mutating func push(bytes: any ContiguousBytes) {
|
||||
mutating func push(bytes: ContiguousBytes) {
|
||||
bytes.withUnsafeBytes { ptr in
|
||||
ensureSpace(size: ptr.count)
|
||||
memcpy(
|
||||
@@ -333,7 +333,6 @@ struct _InternalByteBuffer {
|
||||
|
||||
@discardableResult
|
||||
@inline(__always)
|
||||
@usableFromInline
|
||||
func readWithUnsafeRawPointer<T>(
|
||||
position: Int,
|
||||
_ body: (UnsafeRawPointer) throws -> T) rethrows -> T
|
||||
|
||||
@@ -27,32 +27,15 @@ public struct ByteBuffer {
|
||||
@usableFromInline
|
||||
final class Storage {
|
||||
@usableFromInline
|
||||
@frozen enum Blob: ~Copyable {
|
||||
enum Blob {
|
||||
#if !os(WASI)
|
||||
case data(Data)
|
||||
case bytes(any ContiguousBytes)
|
||||
case bytes(ContiguousBytes)
|
||||
#endif
|
||||
|
||||
case byteBuffer(_InternalByteBuffer)
|
||||
case array([UInt8])
|
||||
case pointer(UnsafeMutableRawPointer)
|
||||
|
||||
init(_ other: borrowing Blob) {
|
||||
switch other {
|
||||
#if !os(WASI)
|
||||
case .data(let data):
|
||||
self = .data(data)
|
||||
case .bytes(let contiguousBytes):
|
||||
self = .bytes(contiguousBytes)
|
||||
#endif
|
||||
case .byteBuffer(let internalByteBuffer):
|
||||
self = .byteBuffer(internalByteBuffer)
|
||||
case .array(let array):
|
||||
self = .array(array)
|
||||
case .pointer(let unsafeMutableRawPointer):
|
||||
self = .pointer(unsafeMutableRawPointer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This storage doesn't own the memory, therefore, we won't deallocate on deinit.
|
||||
@@ -61,7 +44,7 @@ public struct ByteBuffer {
|
||||
private let capacity: Int
|
||||
/// Retained blob of data that requires the storage to retain a pointer to.
|
||||
@usableFromInline
|
||||
let retainedBlob: Blob
|
||||
var retainedBlob: Blob
|
||||
|
||||
@usableFromInline
|
||||
init(count: Int) {
|
||||
@@ -74,9 +57,9 @@ public struct ByteBuffer {
|
||||
}
|
||||
|
||||
@usableFromInline
|
||||
init(blob: borrowing Blob, capacity count: Int) {
|
||||
init(blob: Blob, capacity count: Int) {
|
||||
capacity = count
|
||||
retainedBlob = .init(blob)
|
||||
retainedBlob = blob
|
||||
isOwned = false
|
||||
}
|
||||
|
||||
@@ -293,7 +276,7 @@ public struct ByteBuffer {
|
||||
/// - removeBytes: Removes a number of bytes from the current size
|
||||
@inline(__always)
|
||||
init(
|
||||
blob: borrowing Storage.Blob,
|
||||
blob: Storage.Blob,
|
||||
count: Int,
|
||||
removing removeBytes: Int)
|
||||
{
|
||||
@@ -333,7 +316,7 @@ public struct ByteBuffer {
|
||||
/// - def: Type of the object
|
||||
/// - position: the index of the object in the buffer
|
||||
@inline(__always)
|
||||
public func read<T: BitwiseCopyable>(def: T.Type, position: Int) -> T {
|
||||
public func read<T>(def: T.Type, position: Int) -> T {
|
||||
_storage.readWithUnsafeRawPointer(position: position) {
|
||||
$0.bindMemory(to: T.self, capacity: 1)
|
||||
.pointee
|
||||
@@ -377,10 +360,10 @@ public struct ByteBuffer {
|
||||
@inline(__always)
|
||||
func readSizedScalar<
|
||||
T: BinaryInteger,
|
||||
T1: BinaryInteger & BitwiseCopyable,
|
||||
T2: BinaryInteger & BitwiseCopyable,
|
||||
T3: BinaryInteger & BitwiseCopyable,
|
||||
T4: BinaryInteger & BitwiseCopyable
|
||||
T1: BinaryInteger,
|
||||
T2: BinaryInteger,
|
||||
T3: BinaryInteger,
|
||||
T4: BinaryInteger
|
||||
>(
|
||||
def: T.Type,
|
||||
t1: T1.Type,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum FlexBufferType: UInt64, Sendable {
|
||||
public enum FlexBufferType: UInt64 {
|
||||
case null = 0
|
||||
/// Variable width signed integer: `Int8, Int16, Int32, Int64`
|
||||
case int = 1
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Common
|
||||
import Foundation
|
||||
|
||||
enum FlexBuffersErrors: Error {
|
||||
@@ -24,10 +23,6 @@ enum FlexBuffersErrors: Error {
|
||||
|
||||
@inline(__always)
|
||||
public func getRoot(buffer: ByteBuffer) throws -> Reference? {
|
||||
assert(
|
||||
isLitteEndian,
|
||||
"Swift FlexBuffers currently only supports little-endian systems")
|
||||
|
||||
let end = buffer.count
|
||||
if buffer.count < 3 {
|
||||
throw FlexBuffersErrors.sizeOfBufferIsTooSmall
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import Foundation
|
||||
|
||||
@usableFromInline
|
||||
enum BitWidth: UInt64, CaseIterable, Sendable {
|
||||
enum BitWidth: UInt64, CaseIterable {
|
||||
case w8 = 0
|
||||
case w16 = 1
|
||||
case w32 = 2
|
||||
|
||||
@@ -20,10 +20,10 @@ import Foundation
|
||||
import Common
|
||||
#endif
|
||||
|
||||
public struct Value: Equatable, Sendable {
|
||||
public struct Value: Equatable {
|
||||
|
||||
@usableFromInline
|
||||
enum Union: Equatable, Sendable {
|
||||
enum Union: Equatable {
|
||||
case i(Int64)
|
||||
case u(UInt64)
|
||||
case f(Double)
|
||||
|
||||
@@ -37,15 +37,12 @@ public struct FlexBuffersWriter {
|
||||
private var hasDuplicatedKeys = false
|
||||
private var minBitWidth: BitWidth = .w8
|
||||
private var _bb: _InternalByteBuffer
|
||||
private var stack: Stack = Stack()
|
||||
private var stack: [Value] = []
|
||||
private var keyPool: [Int: UInt] = [:]
|
||||
private var stringPool: [Int: UInt] = [:]
|
||||
private var flags: BuilderFlag
|
||||
|
||||
public init(initialSize: Int = 1024, flags: BuilderFlag = .shareKeys) {
|
||||
assert(
|
||||
isLitteEndian,
|
||||
"Swift FlexBuffers currently only supports little-endian systems")
|
||||
_bb = _InternalByteBuffer(initialSize: initialSize)
|
||||
self.flags = flags
|
||||
}
|
||||
@@ -151,7 +148,7 @@ public struct FlexBuffersWriter {
|
||||
typed: typed,
|
||||
fixed: fixed,
|
||||
keys: nil)
|
||||
stack.popLast(start)
|
||||
stack = Array(stack[..<start])
|
||||
stack.append(vec)
|
||||
return vec.u
|
||||
}
|
||||
@@ -220,7 +217,7 @@ public struct FlexBuffersWriter {
|
||||
typed: false,
|
||||
fixed: false,
|
||||
keys: keys)
|
||||
stack.popLast(start)
|
||||
stack = Array(stack[..<start])
|
||||
stack.append(vec)
|
||||
return numericCast(vec.u)
|
||||
}
|
||||
@@ -724,7 +721,7 @@ public struct FlexBuffersWriter {
|
||||
assert(
|
||||
vectorType == stack[i].type,
|
||||
"""
|
||||
If you get this assert you are writing a typed vector
|
||||
If you get this assert you are writing a typed vector
|
||||
with elements that are not all the same type
|
||||
""")
|
||||
}
|
||||
@@ -760,7 +757,7 @@ public struct FlexBuffersWriter {
|
||||
}
|
||||
|
||||
if !fixed {
|
||||
write(value: UInt64(count), byteWidth: byteWidth)
|
||||
write(value: count, byteWidth: byteWidth)
|
||||
}
|
||||
|
||||
let vloc = _bb.writerIndex
|
||||
@@ -833,14 +830,13 @@ public struct FlexBuffersWriter {
|
||||
let key, value: Value
|
||||
}
|
||||
|
||||
stack.withUnsafeMutableBytes(start: start) { buffer in
|
||||
stack[start...].withUnsafeMutableBytes { buffer in
|
||||
var ptr = buffer.assumingMemoryBound(to: TwoValue.self)
|
||||
ptr.sort { a, b in
|
||||
let aMem = _bb.memory.advanced(by: numericCast(a.key.u))
|
||||
.assumingMemoryBound(to: CChar.self)
|
||||
let bMem = _bb.memory.advanced(by: numericCast(b.key.u))
|
||||
.assumingMemoryBound(to: CChar.self)
|
||||
|
||||
let comp = strcmp(aMem, bMem)
|
||||
if (comp == 0) && a != b { hasDuplicatedKeys = true }
|
||||
return comp < 0
|
||||
@@ -901,132 +897,3 @@ extension FlexBuffersWriter {
|
||||
return endMap(start: start)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate struct Stack: RandomAccessCollection {
|
||||
typealias Element = Value
|
||||
typealias Index = Int
|
||||
|
||||
private final class Storage {
|
||||
var memory: UnsafeMutableRawPointer
|
||||
|
||||
init(capacity: Int, alignment: Int) {
|
||||
memory = .allocate(byteCount: capacity, alignment: alignment)
|
||||
memset(memory, 0, capacity)
|
||||
}
|
||||
|
||||
deinit {
|
||||
memory.deallocate()
|
||||
}
|
||||
}
|
||||
|
||||
private static let initialCapacity = 10 &* MemoryLayout<Value>.stride
|
||||
private let storage: Storage
|
||||
private var capacity: Int
|
||||
private(set) var count: Int
|
||||
|
||||
var startIndex: Int {
|
||||
0
|
||||
}
|
||||
|
||||
var endIndex: Int {
|
||||
count
|
||||
}
|
||||
|
||||
init() {
|
||||
count = 0
|
||||
capacity = Self.initialCapacity
|
||||
|
||||
storage = Storage(
|
||||
capacity: capacity,
|
||||
alignment: MemoryLayout<Value>.alignment)
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
subscript(position: Int) -> Value {
|
||||
get {
|
||||
storage.memory.advanced(by: position &* MemoryLayout<Value>.stride)
|
||||
.assumingMemoryBound(to: Value.self).pointee
|
||||
}
|
||||
set {
|
||||
storage.memory.advanced(by: position &* MemoryLayout<Value>.stride)
|
||||
.assumingMemoryBound(to: Value.self).pointee = newValue
|
||||
}
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
mutating func popLast(_ val: Int) {
|
||||
count = if val < 0 {
|
||||
0
|
||||
} else {
|
||||
val
|
||||
}
|
||||
}
|
||||
|
||||
mutating func append(_ value: Value) {
|
||||
let writePosition = count &* MemoryLayout<Value>.stride
|
||||
if writePosition >= capacity {
|
||||
reallocate(writePosition: writePosition)
|
||||
}
|
||||
|
||||
storage.memory.advanced(by: writePosition).storeBytes(
|
||||
of: value,
|
||||
as: Value.self)
|
||||
count += 1
|
||||
}
|
||||
|
||||
mutating func removeAll(keepingCapacity keepCapacity: Bool = false) {
|
||||
count = 0
|
||||
if !keepCapacity {
|
||||
let ptr = storage.memory
|
||||
defer { ptr.deallocate() }
|
||||
|
||||
capacity = Self.initialCapacity
|
||||
storage.memory = UnsafeMutableRawPointer.allocate(
|
||||
byteCount: capacity,
|
||||
alignment: MemoryLayout<Value>.alignment)
|
||||
}
|
||||
memset(storage.memory, 0, capacity)
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
mutating func withUnsafeMutableBytes<R>(
|
||||
start: Int,
|
||||
_ body: (UnsafeMutableRawBufferPointer) throws -> R) rethrows -> R
|
||||
{
|
||||
let startingPosition = start &* MemoryLayout<Value>.stride
|
||||
let pointer = storage.memory.advanced(by: startingPosition)
|
||||
return try body(UnsafeMutableRawBufferPointer(
|
||||
start: pointer,
|
||||
count: (count &* MemoryLayout<Value>.stride) &- startingPosition))
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
mutating func withUnsafeMutableBytes<R>(
|
||||
_ body: (UnsafeMutableRawBufferPointer) throws
|
||||
-> R) rethrows -> R
|
||||
{
|
||||
return try body(UnsafeMutableRawBufferPointer(
|
||||
start: storage.memory,
|
||||
count: count &* MemoryLayout<Value>.stride))
|
||||
}
|
||||
|
||||
mutating private func reallocate(writePosition: Int) {
|
||||
while capacity <= writePosition {
|
||||
capacity = capacity << 1
|
||||
}
|
||||
|
||||
/// solution take from Apple-NIO
|
||||
capacity = capacity.convertToPowerofTwo
|
||||
|
||||
let newData = UnsafeMutableRawPointer.allocate(
|
||||
byteCount: capacity,
|
||||
alignment: MemoryLayout<Value>.alignment)
|
||||
memset(newData, 0, capacity)
|
||||
memcpy(
|
||||
newData,
|
||||
storage.memory,
|
||||
writePosition)
|
||||
storage.memory.deallocate()
|
||||
storage.memory = newData
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ struct _InternalByteBuffer {
|
||||
@usableFromInline
|
||||
final class Storage {
|
||||
/// pointer to the start of the buffer object in memory
|
||||
@exclusivity(unchecked) private(set) var memory: UnsafeMutableRawPointer
|
||||
var memory: UnsafeMutableRawPointer
|
||||
|
||||
@usableFromInline
|
||||
init(count: Int, alignment: Int) {
|
||||
@@ -60,7 +60,7 @@ struct _InternalByteBuffer {
|
||||
let newData = UnsafeMutableRawPointer.allocate(
|
||||
byteCount: capacity,
|
||||
alignment: alignment)
|
||||
memset(newData, 0, capacity)
|
||||
memset(newData, 0, capacity &- writerSize)
|
||||
memcpy(
|
||||
newData,
|
||||
memory,
|
||||
|
||||
Reference in New Issue
Block a user