This commit is contained in:
2026-08-17 01:21:55 +02:00
parent 5761d6e67a
commit 4bd1e24e75
265 changed files with 20617 additions and 24457 deletions
+1 -1
View File
@@ -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 }
}
+11 -48
View File
@@ -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) }
+1 -1
View File
@@ -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
+30 -59
View File
@@ -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)
}
}
+8 -38
View File
@@ -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
+7 -7
View File
@@ -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(
+1 -8
View File
@@ -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)
}
}
+4 -8
View File
@@ -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
+11 -28
View File
@@ -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
+2 -2
View File
@@ -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,