Skip to content

Commit a95d5ed

Browse files
committed
Moves the internal stack to use a pointer stack instead of the native array for improved performance
1 parent 8914d06 commit a95d5ed

File tree

4 files changed

+135
-8
lines changed

4 files changed

+135
-8
lines changed

swift/Sources/FlexBuffers/Utils/Value.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ public struct Value: Equatable {
3030
}
3131

3232
var sloc: Union
33-
let type: FlexBufferType
3433
let bitWidth: BitWidth
34+
let type: FlexBufferType
3535

3636
@inline(__always)
3737
private init() {

swift/Sources/FlexBuffers/Writer/FlexBuffersWriter.swift

Lines changed: 131 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public struct FlexBuffersWriter {
3737
private var hasDuplicatedKeys = false
3838
private var minBitWidth: BitWidth = .w8
3939
private var _bb: _InternalByteBuffer
40-
private var stack: [Value] = []
40+
private var stack: Stack = Stack()
4141
private var keyPool: [Int: UInt] = [:]
4242
private var stringPool: [Int: UInt] = [:]
4343
private var flags: BuilderFlag
@@ -148,7 +148,7 @@ public struct FlexBuffersWriter {
148148
typed: typed,
149149
fixed: fixed,
150150
keys: nil)
151-
stack = Array(stack[..<start])
151+
stack.popLast(start)
152152
stack.append(vec)
153153
return vec.u
154154
}
@@ -217,7 +217,7 @@ public struct FlexBuffersWriter {
217217
typed: false,
218218
fixed: false,
219219
keys: keys)
220-
stack = Array(stack[..<start])
220+
stack.popLast(start)
221221
stack.append(vec)
222222
return numericCast(vec.u)
223223
}
@@ -830,13 +830,14 @@ public struct FlexBuffersWriter {
830830
let key, value: Value
831831
}
832832

833-
stack[start...].withUnsafeMutableBytes { buffer in
833+
stack.withUnsafeMutableBytes(start: start) { buffer in
834834
var ptr = buffer.assumingMemoryBound(to: TwoValue.self)
835835
ptr.sort { a, b in
836836
let aMem = _bb.memory.advanced(by: numericCast(a.key.u))
837837
.assumingMemoryBound(to: CChar.self)
838838
let bMem = _bb.memory.advanced(by: numericCast(b.key.u))
839839
.assumingMemoryBound(to: CChar.self)
840+
840841
let comp = strcmp(aMem, bMem)
841842
if (comp == 0) && a != b { hasDuplicatedKeys = true }
842843
return comp < 0
@@ -897,3 +898,129 @@ extension FlexBuffersWriter {
897898
return endMap(start: start)
898899
}
899900
}
901+
902+
fileprivate struct Stack: RandomAccessCollection {
903+
typealias Element = Value
904+
typealias Index = Int
905+
906+
private final class Storage {
907+
var memory: UnsafeMutableRawPointer
908+
909+
init(capacity: Int, alignment: Int) {
910+
memory = .allocate(byteCount: capacity, alignment: alignment)
911+
memset(memory, 0, capacity)
912+
}
913+
914+
deinit {
915+
memory.deallocate()
916+
}
917+
}
918+
919+
private static let initialCapacity = 10 &* MemoryLayout<Value>.stride
920+
private let storage: Storage
921+
private var capacity: Int
922+
private(set) var count: Int
923+
924+
var startIndex: Int {
925+
0
926+
}
927+
928+
var endIndex: Int {
929+
count
930+
}
931+
932+
init() {
933+
count = 0
934+
capacity = Self.initialCapacity
935+
936+
storage = Storage(
937+
capacity: capacity,
938+
alignment: MemoryLayout<Value>.alignment)
939+
}
940+
941+
@inline(__always)
942+
subscript(position: Int) -> Value {
943+
get {
944+
storage.memory.advanced(by: position &* MemoryLayout<Value>.stride)
945+
.assumingMemoryBound(to: Value.self).pointee
946+
}
947+
set {
948+
storage.memory.advanced(by: position &* MemoryLayout<Value>.stride)
949+
.assumingMemoryBound(to: Value.self).pointee = newValue
950+
}
951+
}
952+
953+
@inline(__always)
954+
mutating func popLast(_ val: Int) {
955+
count = if val < 0 {
956+
0
957+
} else {
958+
val
959+
}
960+
}
961+
962+
mutating func append(_ value: Value) {
963+
let writePosition = count &* MemoryLayout<Value>.stride
964+
if writePosition >= capacity {
965+
reallocate(writePosition: writePosition)
966+
}
967+
968+
storage.memory.advanced(by: writePosition).storeBytes(
969+
of: value,
970+
as: Value.self)
971+
count += 1
972+
}
973+
974+
mutating func removeAll(keepingCapacity keepCapacity: Bool = false) {
975+
count = 0
976+
if !keepCapacity {
977+
capacity = Self.initialCapacity
978+
storage.memory = UnsafeMutableRawPointer.allocate(
979+
byteCount: capacity,
980+
alignment: MemoryLayout<Value>.alignment)
981+
}
982+
memset(storage.memory, 0, capacity)
983+
}
984+
985+
@discardableResult
986+
mutating func withUnsafeMutableBytes<R>(
987+
start: Int,
988+
_ body: (UnsafeMutableRawBufferPointer) throws -> R) rethrows -> R
989+
{
990+
let startingPosition = start &* MemoryLayout<Value>.stride
991+
let pointer = storage.memory.advanced(by: startingPosition)
992+
return try body(UnsafeMutableRawBufferPointer(
993+
start: pointer,
994+
count: (count &* MemoryLayout<Value>.stride) &- startingPosition))
995+
}
996+
997+
@discardableResult
998+
mutating func withUnsafeMutableBytes<R>(
999+
_ body: (UnsafeMutableRawBufferPointer) throws
1000+
-> R) rethrows -> R
1001+
{
1002+
return try body(UnsafeMutableRawBufferPointer(
1003+
start: storage.memory,
1004+
count: count &* MemoryLayout<Value>.stride))
1005+
}
1006+
1007+
mutating private func reallocate(writePosition: Int) {
1008+
while capacity <= writePosition {
1009+
capacity = capacity << 1
1010+
}
1011+
1012+
/// solution take from Apple-NIO
1013+
capacity = capacity.convertToPowerofTwo
1014+
1015+
let newData = UnsafeMutableRawPointer.allocate(
1016+
byteCount: capacity,
1017+
alignment: MemoryLayout<Value>.alignment)
1018+
memset(newData, 0, capacity)
1019+
memcpy(
1020+
newData,
1021+
storage.memory,
1022+
writePosition)
1023+
storage.memory.deallocate()
1024+
storage.memory = newData
1025+
}
1026+
}

swift/Sources/FlexBuffers/_InternalByteBuffer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ struct _InternalByteBuffer {
6060
let newData = UnsafeMutableRawPointer.allocate(
6161
byteCount: capacity,
6262
alignment: alignment)
63-
memset(newData, 0, capacity &- writerSize)
63+
memset(newData, 0, capacity)
6464
memcpy(
6565
newData,
6666
memory,

tests/swift/Wasm.tests/Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ let package = Package(
2424
],
2525
dependencies: [
2626
.package(path: "../../.."),
27-
.package(url: "https://github.com/swiftwasm/WasmKit", exact: "0.1.6")
27+
.package(url: "https://github.com/swiftwasm/WasmKit", exact: "0.1.6"),
2828
],
2929
targets: [
3030
.target(name: "Wasm"),
@@ -37,5 +37,5 @@ let package = Package(
3737
name: "FlexBuffers.Test.Swift.WasmTests",
3838
dependencies: [
3939
.product(name: "FlexBuffers", package: "flatbuffers"),
40-
])
40+
]),
4141
])

0 commit comments

Comments
 (0)