From 2e57d80b13d501272612170bb0cfabffd595c91e Mon Sep 17 00:00:00 2001 From: mustiikhalil Date: Thu, 18 Jun 2020 20:14:38 +0300 Subject: [PATCH] [Swift] Internal library improvements (#5965) * Moves addition to overflow addition in swift by using &+ Moves code to use Int instead of UInt32 & fixes functions Updates swift performance to great Updated version to 0.5.2 Updated swift package version to 5.2 Updated docker to swift 5.2 Removed all none & arithmetic operations * Small refactoring --- docs/source/Support.md | 2 +- swift/FlatBuffers.podspec | 2 +- swift/Package.swift | 2 +- swift/Sources/FlatBuffers/ByteBuffer.swift | 60 +++++++------- swift/Sources/FlatBuffers/Constants.swift | 5 +- .../FlatBuffers/FlatBufferBuilder.swift | 78 +++++++++---------- ...swift_5_1 => Dockerfile.testing.swift_5_2} | 2 +- 7 files changed, 71 insertions(+), 80 deletions(-) rename tests/docker/languages/{Dockerfile.testing.swift_5_1 => Dockerfile.testing.swift_5_2} (91%) diff --git a/docs/source/Support.md b/docs/source/Support.md index cc6fcb1d1..ab3b4bdf8 100644 --- a/docs/source/Support.md +++ b/docs/source/Support.md @@ -27,7 +27,7 @@ Reflection | Yes | No | No | No | No | No Buffer verifier | Yes | No | No | No | No | No | No | Yes | No | No | No | No | No Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | Yes | Yes | Yes | Yes Testing: fuzz | Yes | No | No | Yes | Yes | No | No | No | ? | No | No | Yes | No -Performance: | Superb | Great | Great | Great | Ok | ? | ? | Superb | ? | ? | Great | Superb | ? +Performance: | Superb | Great | Great | Great | Ok | ? | ? | Superb | ? | ? | Great | Superb | Great Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | Yes | VS2010 | ? | Yes | Yes | Yes | No Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | Yes | ? | Yes | Yes | Yes | Yes Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | Yes | ? | Yes | Yes | Yes | Yes diff --git a/swift/FlatBuffers.podspec b/swift/FlatBuffers.podspec index 65ec025e8..6cf2c13f7 100644 --- a/swift/FlatBuffers.podspec +++ b/swift/FlatBuffers.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FlatBuffers' - s.version = '0.5.1' + s.version = '0.5.2' s.summary = 'FlatBuffers: Memory Efficient Serialization Library' s.description = "FlatBuffers is a cross platform serialization library architected for diff --git a/swift/Package.swift b/swift/Package.swift index 18bb90a4e..729ad40bb 100644 --- a/swift/Package.swift +++ b/swift/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.1 +// swift-tools-version:5.2 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription diff --git a/swift/Sources/FlatBuffers/ByteBuffer.swift b/swift/Sources/FlatBuffers/ByteBuffer.swift index 40b9cd7a4..28d19e326 100644 --- a/swift/Sources/FlatBuffers/ByteBuffer.swift +++ b/swift/Sources/FlatBuffers/ByteBuffer.swift @@ -25,14 +25,14 @@ public struct ByteBuffer { } func initalize(for size: Int) { - memory.initializeMemory(as: UInt8.self, repeating: 0, count: size) + memset(memory, 0, size) } /// Reallocates the buffer incase the object to be written doesnt fit in the current buffer /// - Parameter size: Size of the current object - @usableFromInline internal func reallocate(_ size: UInt32, writerSize: Int, alignment: Int) { - let currentWritingIndex = capacity - writerSize - while capacity <= writerSize + Int(size) { + @usableFromInline internal func reallocate(_ size: Int, writerSize: Int, alignment: Int) { + let currentWritingIndex = capacity &- writerSize + while capacity <= writerSize &+ size { capacity = capacity << 1 } @@ -40,8 +40,8 @@ public struct ByteBuffer { capacity = capacity.convertToPowerofTwo let newData = UnsafeMutableRawPointer.allocate(byteCount: capacity, alignment: alignment) - memset(newData, 0, capacity - writerSize) - memcpy(newData.advanced(by: capacity - writerSize), memory.advanced(by: currentWritingIndex), writerSize) + memset(newData, 0, capacity &- writerSize) + memcpy(newData.advanced(by: capacity &- writerSize), memory.advanced(by: currentWritingIndex), writerSize) memory.deallocate() memory = newData } @@ -54,7 +54,7 @@ public struct ByteBuffer { /// Aliginment of the current memory being written to the buffer internal var alignment = 1 /// Current Index which is being used to write to the buffer, it is written from the end to the start of the buffer - internal var writerIndex: Int { return _storage.capacity - _writerSize } + internal var writerIndex: Int { return _storage.capacity &- _writerSize } /// Reader is the position of the current Writer Index (capacity - size) public var reader: Int { return writerIndex } @@ -135,16 +135,16 @@ public struct ByteBuffer { /// Fills the buffer with padding by adding to the writersize /// - Parameter padding: Amount of padding between two to be serialized objects - @usableFromInline mutating func fill(padding: UInt32) { + @usableFromInline mutating func fill(padding: Int) { ensureSpace(size: padding) - _writerSize += (MemoryLayout.size * Int(padding)) + _writerSize = _writerSize &+ (MemoryLayout.size &* padding) } ///Adds an array of type Scalar to the buffer memory /// - Parameter elements: An array of Scalars @usableFromInline mutating func push(elements: [T]) { - let size = elements.count * MemoryLayout.size - ensureSpace(size: UInt32(size)) + let size = elements.count &* MemoryLayout.size + ensureSpace(size: size) elements.lazy.reversed().forEach { (s) in push(value: s, len: MemoryLayout.size(ofValue: s)) } @@ -153,8 +153,8 @@ public struct ByteBuffer { ///Adds an array of type Bool to the buffer memory /// - Parameter elements: An array of Bool @usableFromInline mutating func push(elements: [Bool]) { - let size = elements.count * MemoryLayout.size - ensureSpace(size: UInt32(size)) + let size = elements.count &* MemoryLayout.size + ensureSpace(size: size) elements.lazy.reversed().forEach { (s) in push(value: s ? 1 : 0, len: MemoryLayout.size(ofValue: s)) } @@ -165,10 +165,10 @@ public struct ByteBuffer { /// - value: Pointer to the object in memory /// - size: Size of Value being written to the buffer @usableFromInline mutating func push(struct value: UnsafeMutableRawPointer, size: Int) { - ensureSpace(size: UInt32(size)) - memcpy(_storage.memory.advanced(by: writerIndex - size), value, size) + ensureSpace(size: size) + memcpy(_storage.memory.advanced(by: writerIndex &- size), value, size) defer { value.deallocate() } - _writerSize += size + _writerSize = _writerSize &+ size } /// Adds an object of type Scalar into the buffer @@ -176,17 +176,17 @@ public struct ByteBuffer { /// - value: Object that will be written to the buffer /// - len: Offset to subtract from the WriterIndex @usableFromInline mutating func push(value: T, len: Int) { - ensureSpace(size: UInt32(len)) - var v = value.convertedEndian - memcpy(_storage.memory.advanced(by: writerIndex - len), &v, len) - _writerSize += len + ensureSpace(size: len) + var v = value + memcpy(_storage.memory.advanced(by: writerIndex &- len), &v, len) + _writerSize = _writerSize &+ len } /// Adds a string to the buffer using swift.utf8 object /// - Parameter str: String that will be added to the buffer /// - Parameter len: length of the string @usableFromInline mutating func push(string str: String, len: Int) { - ensureSpace(size: UInt32(len)) + ensureSpace(size: len) if str.utf8.withContiguousStorageIfAvailable({ self.push(bytes: $0, len: len) }) != nil { } else { let utf8View = str.utf8 @@ -201,8 +201,8 @@ public struct ByteBuffer { /// - bytes: Pointer to the view /// - len: Size of string @usableFromInline mutating internal func push(bytes: UnsafeBufferPointer, len: Int) -> Bool { - memcpy(_storage.memory.advanced(by: writerIndex - len), UnsafeRawPointer(bytes.baseAddress!), len) - _writerSize += len + memcpy(_storage.memory.advanced(by: writerIndex &- len), UnsafeRawPointer(bytes.baseAddress!), len) + _writerSize = _writerSize &+ len return true } @@ -217,7 +217,7 @@ public struct ByteBuffer { func write(value: T, index: Int, direct: Bool = false) { var index = index if !direct { - index = _storage.capacity - index + index = _storage.capacity &- index } _storage.memory.storeBytes(of: value, toByteOffset: index, as: T.self) } @@ -225,8 +225,8 @@ public struct ByteBuffer { /// Makes sure that buffer has enouch space for each of the objects that will be written into it /// - Parameter size: size of object @discardableResult - @usableFromInline mutating func ensureSpace(size: UInt32) -> UInt32 { - if Int(size) + _writerSize > _storage.capacity { + @usableFromInline mutating func ensureSpace(size: Int) -> Int { + if size &+ _writerSize > _storage.capacity { _storage.reallocate(size, writerSize: _writerSize, alignment: alignment) } assert(size < FlatBufferMaxSize, "Buffer can't grow beyond 2 Gigabytes") @@ -249,10 +249,10 @@ public struct ByteBuffer { /// Resizes the buffer size /// - Parameter size: new size for the buffer @usableFromInline mutating internal func resize(_ size: Int) { - assert((_writerSize - size) > 0) + assert((_writerSize &- size) > 0) var zero: UInt8 = 0 - for i in 0..<(_writerSize - size) { - memcpy(_storage.memory.advanced(by: writerIndex + i), &zero, MemoryLayout.size) + for i in 0..<(_writerSize &- size) { + memcpy(_storage.memory.advanced(by: writerIndex &+ i), &zero, MemoryLayout.size) } _writerSize = size } @@ -292,7 +292,7 @@ public struct ByteBuffer { /// Creates a new Flatbuffer object that's duplicated from the current one /// - Parameter removeBytes: the amount of bytes to remove from the current Size public func duplicate(removing removeBytes: Int = 0) -> ByteBuffer { - return ByteBuffer(memory: _storage.memory, count: _storage.capacity, removing: _writerSize - removeBytes) + return ByteBuffer(memory: _storage.memory, count: _storage.capacity, removing: _writerSize &- removeBytes) } } diff --git a/swift/Sources/FlatBuffers/Constants.swift b/swift/Sources/FlatBuffers/Constants.swift index 03ea398b1..2b55250d3 100644 --- a/swift/Sources/FlatBuffers/Constants.swift +++ b/swift/Sources/FlatBuffers/Constants.swift @@ -29,8 +29,7 @@ extension Scalar where Self: FixedWidthInteger { /// /// Converts values to little endian on machines that work with BigEndian, however this is NOT TESTED yet. public var convertedEndian: NumericValue { - if isLitteEndian { return self as! Self.NumericValue } - fatalError("This is not tested! please report an issue on the offical flatbuffers repo") + return self as! Self.NumericValue } } @@ -38,7 +37,6 @@ extension Double: Scalar { public typealias NumericValue = UInt64 public var convertedEndian: UInt64 { - if isLitteEndian { return self.bitPattern } return self.bitPattern.littleEndian } } @@ -47,7 +45,6 @@ extension Float32: Scalar { public typealias NumericValue = UInt32 public var convertedEndian: UInt32 { - if isLitteEndian { return self.bitPattern } return self.bitPattern.littleEndian } } diff --git a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift index 2501a3976..fd0628188 100644 --- a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift +++ b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift @@ -31,7 +31,7 @@ public struct FlatBufferBuilder { public var data: Data { assert(finished, "Data shouldn't be called before finish()") return Data(bytes: _bb.memory.advanced(by: _bb.writerIndex), - count: _bb.capacity - _bb.writerIndex) + count: _bb.capacity &- _bb.writerIndex) } /// Get's the fully sized buffer stored in memory public var fullSizedByteArray: [UInt8] { @@ -41,7 +41,7 @@ public struct FlatBufferBuilder { } /// Returns the written size of the buffer public var sizedByteArray: [UInt8] { - let cp = _bb.capacity - _bb.writerIndex + let cp = _bb.capacity &- _bb.writerIndex let start = _bb.memory.advanced(by: _bb.writerIndex) .bindMemory(to: UInt8.self, capacity: cp) @@ -90,9 +90,9 @@ public struct FlatBufferBuilder { /// - fields: Array of all the important fields to be serialized mutating public func require(table: Offset, fields: [Int32]) { for field in fields { - let start = _bb.capacity - Int(table.o) - let startTable = start - Int(_bb.read(def: Int32.self, position: start)) - let isOkay = _bb.read(def: VOffset.self, position: startTable + Int(field)) != 0 + let start = _bb.capacity &- Int(table.o) + let startTable = start &- Int(_bb.read(def: Int32.self, position: start)) + let isOkay = _bb.read(def: VOffset.self, position: startTable &+ Int(field)) != 0 assert(isOkay, "Flatbuffers requires the following field") } } @@ -104,7 +104,7 @@ public struct FlatBufferBuilder { /// - prefix: if false it wont add the size of the buffer mutating public func finish(offset: Offset, fileId: String, addPrefix prefix: Bool = false) { let size = MemoryLayout.size - preAlign(len: size + (prefix ? size : 0) + FileIdLength, alignment: _minAlignment) + preAlign(len: size &+ (prefix ? size : 0) &+ FileIdLength, alignment: _minAlignment) assert(fileId.count == FileIdLength, "Flatbuffers requires file id to be 4") _bb.push(string: fileId, len: 4) finish(offset: offset, addPrefix: prefix) @@ -117,7 +117,7 @@ public struct FlatBufferBuilder { mutating public func finish(offset: Offset, addPrefix prefix: Bool = false) { notNested() let size = MemoryLayout.size - preAlign(len: size + (prefix ? size : 0), alignment: _minAlignment) + preAlign(len: size &+ (prefix ? size : 0), alignment: _minAlignment) push(element: refer(to: offset.o)) if prefix { push(element: _bb.size) } _vtableStorage.clear() @@ -147,21 +147,21 @@ public struct FlatBufferBuilder { let sizeofVoffset = MemoryLayout.size let vTableOffset = push(element: SOffset(0)) - let tableObjectSize = vTableOffset - startOffset + let tableObjectSize = vTableOffset &- startOffset assert(tableObjectSize < 0x10000, "Buffer can't grow beyond 2 Gigabytes") - let _max = UInt32(_vtableStorage.maxOffset) + UInt32(sizeofVoffset) + let _max = Int(_vtableStorage.maxOffset) &+ sizeofVoffset _bb.fill(padding: _max) - _bb.write(value: VOffset(tableObjectSize), index: _bb.writerIndex + sizeofVoffset, direct: true) + _bb.write(value: VOffset(tableObjectSize), index: _bb.writerIndex &+ sizeofVoffset, direct: true) _bb.write(value: VOffset(_max), index: _bb.writerIndex, direct: true) var itr = 0 while itr < _vtableStorage.writtenIndex { let loaded = _vtableStorage.load(at: itr) - itr += _vtableStorage.size + itr = itr &+ _vtableStorage.size guard loaded.offset != 0 else { continue } - let _index = (_bb.writerIndex + Int(loaded.position)) - _bb.write(value: VOffset(vTableOffset - loaded.offset), index: _index, direct: true) + let _index = (_bb.writerIndex &+ Int(loaded.position)) + _bb.write(value: VOffset(vTableOffset &- loaded.offset), index: _index, direct: true) } _vtableStorage.clear() @@ -173,7 +173,7 @@ public struct FlatBufferBuilder { let len2 = vt2.load(fromByteOffset: 0, as: Int16.self) for table in _vtables { - let position = _bb.capacity - Int(table) + let position = _bb.capacity &- Int(table) let vt1 = _bb.memory.advanced(by: position) let len1 = _bb.read(def: Int16.self, position: position) if (len2 != len1 || 0 != memcmp(vt1, vt2, Int(len2))) { continue } @@ -184,11 +184,11 @@ public struct FlatBufferBuilder { if let offset = isAlreadyAdded { let vTableOff = Int(vTableOffset) - let space = _bb.capacity - vTableOff - _bb.write(value: Int32(offset - vTableOff), index: space, direct: true) - _bb.resize(_bb.capacity - space) + let space = _bb.capacity &- vTableOff + _bb.write(value: Int32(offset &- vTableOff), index: space, direct: true) + _bb.resize(_bb.capacity &- space) } else { - _bb.write(value: Int32(vt_use) - Int32(vTableOffset), index: Int(vTableOffset)) + _bb.write(value: Int32(vt_use &- vTableOffset), index: Int(vTableOffset)) _vtables.append(_bb.size) } isNested = false @@ -224,7 +224,7 @@ public struct FlatBufferBuilder { /// - alignment: Alignment type @usableFromInline mutating internal func preAlign(len: Int, alignment: Int) { minAlignment(size: alignment) - _bb.fill(padding: padding(bufSize: _bb.size + UOffset(len), elementSize: UOffset(alignment))) + _bb.fill(padding: Int(padding(bufSize: _bb.size &+ UOffset(len), elementSize: UOffset(alignment)))) } /// Prealigns the buffer before writting a new object into the buffer @@ -240,7 +240,7 @@ public struct FlatBufferBuilder { @usableFromInline mutating internal func refer(to off: UOffset) -> UOffset { let size = MemoryLayout.size preAlign(len: size, alignment: size) - return _bb.size - off + UInt32(size) + return _bb.size &- off &+ UInt32(size) } /// Tracks the elements written into the buffer @@ -257,8 +257,8 @@ public struct FlatBufferBuilder { mutating public func startVector(_ len: Int, elementSize: Int) { notNested() isNested = true - preAlign(len: len * elementSize, type: UOffset.self) - preAlign(len: len * elementSize, alignment: elementSize) + preAlign(len: len &* elementSize, type: UOffset.self) + preAlign(len: len &* elementSize, alignment: elementSize) } /// Ends the vector of at length @@ -348,7 +348,7 @@ public struct FlatBufferBuilder { /// - returns: Offset of the vector mutating public func createVector(structs: [UnsafeMutableRawPointer], type: T.Type) -> Offset { - startVector(structs.count * T.size, elementSize: T.alignment) + startVector(structs.count &* T.size, elementSize: T.alignment) for i in structs.lazy.reversed() { create(struct: i, type: T.self) } @@ -387,7 +387,7 @@ public struct FlatBufferBuilder { mutating public func create(string str: String) -> Offset { let len = str.utf8.count notNested() - preAlign(len: len + 1, type: UOffset.self) + preAlign(len: len &+ 1, type: UOffset.self) _bb.fill(padding: 1) _bb.push(string: str, len: len) push(element: UOffset(len)) @@ -415,10 +415,7 @@ public struct FlatBufferBuilder { /// - offset: Offset of another object to be written /// - position: The predefined position of the object mutating public func add(offset: Offset, at position: VOffset) { - if offset.isEmpty { - track(offset: 0, at: position) - return - } + if offset.isEmpty { return } add(element: refer(to: offset.o), def: 0, at: position) } @@ -439,12 +436,8 @@ public struct FlatBufferBuilder { /// - def: Default value for that element /// - position: The predefined position of the element mutating public func add(element: T, def: T, at position: VOffset) { - if (element == def && !serializeDefaults) { - track(offset: 0, at: position) - return - } - let off = push(element: element) - track(offset: off, at: position) + if (element == def && !serializeDefaults) { return } + track(offset: push(element: element), at: position) } /// Adds Boolean values into the buffer @@ -467,9 +460,10 @@ public struct FlatBufferBuilder { /// - returns: Postion of the Element @discardableResult mutating public func push(element: T) -> UOffset { - preAlign(len: MemoryLayout.size, - alignment: MemoryLayout.size) - _bb.push(value: element, len: MemoryLayout.size) + let size = MemoryLayout.size + preAlign(len: size, + alignment: size) + _bb.push(value: element, len: size) return _bb.size } @@ -505,7 +499,7 @@ extension FlatBufferBuilder: CustomDebugStringConvertible { /// Last written Index var writtenIndex: Int = 0 /// the amount of added elements into the buffer - var addedElements: Int { return capacity - (numOfFields * size) } + var addedElements: Int { return capacity - (numOfFields &* size) } /// Creates the memory to store the buffer in init() { @@ -519,7 +513,7 @@ extension FlatBufferBuilder: CustomDebugStringConvertible { /// Builds a buffer with byte count of fieldloc.size * count of field numbers /// - Parameter count: number of fields to be written func start(count: Int) { - let capacity = count * size + let capacity = count &* size ensure(space: capacity) } @@ -528,8 +522,8 @@ extension FlatBufferBuilder: CustomDebugStringConvertible { /// - Parameter loc: Location of encoded element func add(loc: FieldLoc) { memory.baseAddress?.advanced(by: writtenIndex).storeBytes(of: loc, as: FieldLoc.self) - writtenIndex += size - numOfFields += 1 + writtenIndex = writtenIndex &+ size + numOfFields = numOfFields &+ 1 maxOffset = max(loc.position, maxOffset) } @@ -543,7 +537,7 @@ extension FlatBufferBuilder: CustomDebugStringConvertible { /// Ensure that the buffer has enough space instead of recreating the buffer each time. /// - Parameter space: space required for the new vtable func ensure(space: Int) { - guard space + writtenIndex > capacity else { return } + guard space &+ writtenIndex > capacity else { return } memory.deallocate() memory = UnsafeMutableRawBufferPointer.allocate(byteCount: space, alignment: size) capacity = space diff --git a/tests/docker/languages/Dockerfile.testing.swift_5_1 b/tests/docker/languages/Dockerfile.testing.swift_5_2 similarity index 91% rename from tests/docker/languages/Dockerfile.testing.swift_5_1 rename to tests/docker/languages/Dockerfile.testing.swift_5_2 index e98e4be1f..b30947775 100644 --- a/tests/docker/languages/Dockerfile.testing.swift_5_1 +++ b/tests/docker/languages/Dockerfile.testing.swift_5_2 @@ -1,4 +1,4 @@ -FROM swift:5.1 +FROM swift:5.2 WORKDIR /code ADD . . RUN cp flatc_debian_stretch flatc