Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions swift/Sources/FlexBuffers/Reader/Reference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import Common
import Foundation

enum FlexBuffersErrors: Error {
Expand All @@ -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
Expand Down
142 changes: 136 additions & 6 deletions swift/Sources/FlexBuffers/Writer/FlexBuffersWriter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -148,7 +151,7 @@ public struct FlexBuffersWriter {
typed: typed,
fixed: fixed,
keys: nil)
stack = Array(stack[..<start])
stack.popLast(start)
stack.append(vec)
return vec.u
}
Expand Down Expand Up @@ -217,7 +220,7 @@ public struct FlexBuffersWriter {
typed: false,
fixed: false,
keys: keys)
stack = Array(stack[..<start])
stack.popLast(start)
stack.append(vec)
return numericCast(vec.u)
}
Expand Down Expand Up @@ -721,7 +724,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
""")
}
Expand Down Expand Up @@ -757,7 +760,7 @@ public struct FlexBuffersWriter {
}

if !fixed {
write(value: count, byteWidth: byteWidth)
write(value: UInt64(count), byteWidth: byteWidth)
}

let vloc = _bb.writerIndex
Expand Down Expand Up @@ -830,13 +833,14 @@ public struct FlexBuffersWriter {
let key, value: Value
}

stack[start...].withUnsafeMutableBytes { buffer in
stack.withUnsafeMutableBytes(start: start) { 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
Expand Down Expand Up @@ -897,3 +901,129 @@ 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 {
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
}
}
2 changes: 1 addition & 1 deletion swift/Sources/FlexBuffers/_InternalByteBuffer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions tests/swift/Wasm.tests/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand All @@ -37,5 +37,5 @@ let package = Package(
name: "FlexBuffers.Test.Swift.WasmTests",
dependencies: [
.product(name: "FlexBuffers", package: "flatbuffers"),
])
]),
])
Loading