@@ -37,12 +37,19 @@ public struct FlexBuffersWriter {
3737 private var hasDuplicatedKeys = false
3838 private var minBitWidth : BitWidth = . w8
3939 private var _bb : _InternalByteBuffer
40+ #if os(Wasm)
4041 private var stack : [ Value ] = [ ]
42+ #else
43+ private var stack : Stack = Stack ( )
44+ #endif
4145 private var keyPool : [ Int : UInt ] = [ : ]
4246 private var stringPool : [ Int : UInt ] = [ : ]
4347 private var flags : BuilderFlag
4448
4549 public init ( initialSize: Int = 1024 , flags: BuilderFlag = . shareKeys) {
50+ assert (
51+ isLitteEndian,
52+ " Swift FlexBuffers currently only supports little-endian systems " )
4653 _bb = _InternalByteBuffer ( initialSize: initialSize)
4754 self . flags = flags
4855 }
@@ -148,7 +155,7 @@ public struct FlexBuffersWriter {
148155 typed: typed,
149156 fixed: fixed,
150157 keys: nil )
151- stack = Array ( stack [ ..< start] )
158+ stack. popLast ( start)
152159 stack. append ( vec)
153160 return vec. u
154161 }
@@ -217,7 +224,7 @@ public struct FlexBuffersWriter {
217224 typed: false ,
218225 fixed: false ,
219226 keys: keys)
220- stack = Array ( stack [ ..< start] )
227+ stack. popLast ( start)
221228 stack. append ( vec)
222229 return numericCast ( vec. u)
223230 }
@@ -721,7 +728,7 @@ public struct FlexBuffersWriter {
721728 assert (
722729 vectorType == stack [ i] . type,
723730 """
724- If you get this assert you are writing a typed vector
731+ If you get this assert you are writing a typed vector
725732 with elements that are not all the same type
726733 """ )
727734 }
@@ -830,13 +837,14 @@ public struct FlexBuffersWriter {
830837 let key , value : Value
831838 }
832839
833- stack [ start ... ] . withUnsafeMutableBytes { buffer in
840+ stack. withUnsafeMutableBytes ( start : start ) { buffer in
834841 var ptr = buffer. assumingMemoryBound ( to: TwoValue . self)
835842 ptr. sort { a, b in
836843 let aMem = _bb. memory. advanced ( by: numericCast ( a. key. u) )
837844 . assumingMemoryBound ( to: CChar . self)
838845 let bMem = _bb. memory. advanced ( by: numericCast ( b. key. u) )
839846 . assumingMemoryBound ( to: CChar . self)
847+
840848 let comp = strcmp ( aMem, bMem)
841849 if ( comp == 0 ) && a != b { hasDuplicatedKeys = true }
842850 return comp < 0
@@ -897,3 +905,145 @@ extension FlexBuffersWriter {
897905 return endMap ( start: start)
898906 }
899907}
908+
909+ private extension Array where Element == Value {
910+ mutating func popLast( _ val: Int ) {
911+ self = Array ( self [ ..< val] )
912+ }
913+
914+ @discardableResult
915+ mutating func withUnsafeMutableBytes< R> (
916+ start: Int ,
917+ _ body: ( UnsafeMutableRawBufferPointer ) throws -> R ) rethrows -> R
918+ {
919+ try self [ start... ] . withUnsafeMutableBytes { buffer in
920+ try body ( buffer)
921+ }
922+ }
923+ }
924+
925+ fileprivate struct Stack : RandomAccessCollection {
926+ typealias Element = Value
927+ typealias Index = Int
928+
929+ private final class Storage {
930+ var memory : UnsafeMutableRawPointer
931+
932+ init ( capacity: Int , alignment: Int ) {
933+ memory = . allocate( byteCount: capacity, alignment: alignment)
934+ memset ( memory, 0 , capacity)
935+ }
936+
937+ deinit {
938+ memory. deallocate ( )
939+ }
940+ }
941+
942+ private static let initialCapacity = 10 &* MemoryLayout< Value> . stride
943+ private let storage : Storage
944+ private var capacity : Int
945+ private( set) var count : Int
946+
947+ var startIndex : Int {
948+ 0
949+ }
950+
951+ var endIndex : Int {
952+ count
953+ }
954+
955+ init ( ) {
956+ count = 0
957+ capacity = Self . initialCapacity
958+
959+ storage = Storage (
960+ capacity: capacity,
961+ alignment: MemoryLayout< Value> . alignment)
962+ }
963+
964+ @inline ( __always)
965+ subscript( position: Int ) -> Value {
966+ get {
967+ storage. memory. advanced ( by: position &* MemoryLayout< Value> . stride)
968+ . assumingMemoryBound ( to: Value . self) . pointee
969+ }
970+ set {
971+ storage. memory. advanced ( by: position &* MemoryLayout< Value> . stride)
972+ . assumingMemoryBound ( to: Value . self) . pointee = newValue
973+ }
974+ }
975+
976+ @inline ( __always)
977+ mutating func popLast( _ val: Int ) {
978+ count = if val < 0 {
979+ 0
980+ } else {
981+ val
982+ }
983+ }
984+
985+ mutating func append( _ value: Value ) {
986+ let writePosition = count &* MemoryLayout< Value> . stride
987+ if writePosition >= capacity {
988+ reallocate ( writePosition: writePosition)
989+ }
990+
991+ storage. memory. advanced ( by: writePosition) . storeBytes (
992+ of: value,
993+ as: Value . self)
994+ count += 1
995+ }
996+
997+ mutating func removeAll( keepingCapacity keepCapacity: Bool = false ) {
998+ count = 0
999+ if !keepCapacity {
1000+ capacity = Self . initialCapacity
1001+ storage. memory = UnsafeMutableRawPointer . allocate (
1002+ byteCount: capacity,
1003+ alignment: MemoryLayout< Value> . alignment)
1004+ }
1005+ memset ( storage. memory, 0 , capacity)
1006+ }
1007+
1008+ @discardableResult
1009+ mutating func withUnsafeMutableBytes< R> (
1010+ start: Int ,
1011+ _ body: ( UnsafeMutableRawBufferPointer ) throws -> R ) rethrows -> R
1012+ {
1013+ let startingPosition = start &* MemoryLayout< Value> . stride
1014+ let pointer = storage. memory. advanced ( by: startingPosition)
1015+ return try body ( UnsafeMutableRawBufferPointer (
1016+ start: pointer,
1017+ count: ( count &* MemoryLayout< Value> . stride) &- startingPosition) )
1018+ }
1019+
1020+ @discardableResult
1021+ mutating func withUnsafeMutableBytes< R> (
1022+ _ body: ( UnsafeMutableRawBufferPointer ) throws
1023+ -> R ) rethrows -> R
1024+ {
1025+ return try body ( UnsafeMutableRawBufferPointer (
1026+ start: storage. memory,
1027+ count: count &* MemoryLayout< Value> . stride) )
1028+ }
1029+
1030+ mutating private func reallocate( writePosition: Int ) {
1031+ while capacity <= writePosition {
1032+ capacity = capacity << 1
1033+ }
1034+
1035+ /// solution take from Apple-NIO
1036+ capacity = capacity. convertToPowerofTwo
1037+
1038+ let newData = UnsafeMutableRawPointer . allocate (
1039+ byteCount: capacity,
1040+ alignment: MemoryLayout< Value> . alignment)
1041+ memset ( newData, 0 , capacity)
1042+ memcpy (
1043+ newData,
1044+ storage. memory,
1045+ writePosition)
1046+ storage. memory. deallocate ( )
1047+ storage. memory = newData
1048+ }
1049+ }
0 commit comments