diff --git a/swift/Sources/FlexBuffers/Reader/Reference.swift b/swift/Sources/FlexBuffers/Reader/Reference.swift index f771ba24c80..e78efecce7d 100644 --- a/swift/Sources/FlexBuffers/Reader/Reference.swift +++ b/swift/Sources/FlexBuffers/Reader/Reference.swift @@ -14,6 +14,7 @@ * limitations under the License. */ +import Common import Foundation enum FlexBuffersErrors: Error { @@ -23,6 +24,10 @@ 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 diff --git a/swift/Sources/FlexBuffers/Writer/FlexBuffersWriter.swift b/swift/Sources/FlexBuffers/Writer/FlexBuffersWriter.swift index 6836ec70ae4..449ab5891a6 100644 --- a/swift/Sources/FlexBuffers/Writer/FlexBuffersWriter.swift +++ b/swift/Sources/FlexBuffers/Writer/FlexBuffersWriter.swift @@ -37,12 +37,15 @@ public struct FlexBuffersWriter { private var hasDuplicatedKeys = false private var minBitWidth: BitWidth = .w8 private var _bb: _InternalByteBuffer - private var stack: [Value] = [] + private var stack: Stack = Stack() 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 } @@ -148,7 +151,7 @@ public struct FlexBuffersWriter { typed: typed, fixed: fixed, keys: nil) - stack = Array(stack[...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.alignment) + } + + @inline(__always) + subscript(position: Int) -> Value { + get { + storage.memory.advanced(by: position &* MemoryLayout.stride) + .assumingMemoryBound(to: Value.self).pointee + } + set { + storage.memory.advanced(by: position &* MemoryLayout.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.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 { + capacity = Self.initialCapacity + storage.memory = UnsafeMutableRawPointer.allocate( + byteCount: capacity, + alignment: MemoryLayout.alignment) + } + memset(storage.memory, 0, capacity) + } + + @discardableResult + mutating func withUnsafeMutableBytes( + start: Int, + _ body: (UnsafeMutableRawBufferPointer) throws -> R) rethrows -> R + { + let startingPosition = start &* MemoryLayout.stride + let pointer = storage.memory.advanced(by: startingPosition) + return try body(UnsafeMutableRawBufferPointer( + start: pointer, + count: (count &* MemoryLayout.stride) &- startingPosition)) + } + + @discardableResult + mutating func withUnsafeMutableBytes( + _ body: (UnsafeMutableRawBufferPointer) throws + -> R) rethrows -> R + { + return try body(UnsafeMutableRawBufferPointer( + start: storage.memory, + count: count &* MemoryLayout.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.alignment) + memset(newData, 0, capacity) + memcpy( + newData, + storage.memory, + writePosition) + storage.memory.deallocate() + storage.memory = newData + } +} diff --git a/swift/Sources/FlexBuffers/_InternalByteBuffer.swift b/swift/Sources/FlexBuffers/_InternalByteBuffer.swift index fcf7577aac0..5df4ff31a0c 100644 --- a/swift/Sources/FlexBuffers/_InternalByteBuffer.swift +++ b/swift/Sources/FlexBuffers/_InternalByteBuffer.swift @@ -60,7 +60,7 @@ struct _InternalByteBuffer { let newData = UnsafeMutableRawPointer.allocate( byteCount: capacity, alignment: alignment) - memset(newData, 0, capacity &- writerSize) + memset(newData, 0, capacity) memcpy( newData, memory, diff --git a/tests/swift/Wasm.tests/Package.swift b/tests/swift/Wasm.tests/Package.swift index c5e34a625bd..24a41c86ca8 100644 --- a/tests/swift/Wasm.tests/Package.swift +++ b/tests/swift/Wasm.tests/Package.swift @@ -24,7 +24,7 @@ let package = Package( ], dependencies: [ .package(path: "../../.."), - .package(url: "https://github.com/swiftwasm/WasmKit", exact: "0.1.6") + .package(url: "https://github.com/swiftwasm/WasmKit", exact: "0.1.6"), ], targets: [ .target(name: "Wasm"), @@ -37,5 +37,5 @@ let package = Package( name: "FlexBuffers.Test.Swift.WasmTests", dependencies: [ .product(name: "FlexBuffers", package: "flatbuffers"), - ]) + ]), ])