diff options
author | mustiikhalil <mustii@mmk.one> | 2020-05-07 22:28:42 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-07 12:28:42 -0700 |
commit | 870ecbc09a3f9605aed4796b4ad3e97a733bebc3 (patch) | |
tree | 5e08336e5d887e68bced9121e160a894fc9ce43e /swift | |
parent | c2da8d5d8548fa3ca43e9216e971750b1ad95760 (diff) | |
download | flatbuffers-870ecbc09a3f9605aed4796b4ad3e97a733bebc3.tar.gz flatbuffers-870ecbc09a3f9605aed4796b4ad3e97a733bebc3.tar.bz2 flatbuffers-870ecbc09a3f9605aed4796b4ad3e97a733bebc3.zip |
[swift] Moves code to use VTablesStorage (#5888)
* Moves the code to use _vtablestorage
Rebuilt the test to confirm to the new API
Adds documentation + generates code for grpc
Reverts indentation
v0.4.0
Updated swift/readme.md
Updates VtableStorage to ensure space instead of reallocating each time
Fixes str count not being correct
* Fixes issue with boolean constant not being set + removes unused function
Diffstat (limited to 'swift')
-rw-r--r-- | swift/FlatBuffers.podspec | 2 | ||||
-rw-r--r-- | swift/README.md | 9 | ||||
-rw-r--r-- | swift/Sources/FlatBuffers/ByteBuffer.swift | 7 | ||||
-rw-r--r-- | swift/Sources/FlatBuffers/FlatBufferBuilder.swift | 129 |
4 files changed, 110 insertions, 37 deletions
diff --git a/swift/FlatBuffers.podspec b/swift/FlatBuffers.podspec index 6e5f4a08..0114d3c1 100644 --- a/swift/FlatBuffers.podspec +++ b/swift/FlatBuffers.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'FlatBuffers' - s.version = '0.3.0' + s.version = '0.4.0' s.summary = 'FlatBuffers: Memory Efficient Serialization Library' s.description = "FlatBuffers is a cross platform serialization library architected for diff --git a/swift/README.md b/swift/README.md index 909638e8..b50f43b4 100644 --- a/swift/README.md +++ b/swift/README.md @@ -2,11 +2,10 @@ FlatBuffers swift can be found in both SPM `.package(url: "https://github.com/mustiikhalil/flatbuffers.git", from: "X.Y.Z"),` -tags are provided in the repository, so you can select according to the version you want. - and Cocoapods -`pod 'FlatBuffers', :git => 'https://github.com/mustiikhalil/flatbuffers.git', :branch => 'swift'` - -To report any error please use the main repository. +`pod 'FlatBuffers'` +### Notes +1- To report any error please use the main repository. +2- The package 0.4.0 will break the generated code. You can download the [binary here](https://github.com/google/flatbuffers/actions) and select the latest push to master
\ No newline at end of file diff --git a/swift/Sources/FlatBuffers/ByteBuffer.swift b/swift/Sources/FlatBuffers/ByteBuffer.swift index a35f25da..75ad0750 100644 --- a/swift/Sources/FlatBuffers/ByteBuffer.swift +++ b/swift/Sources/FlatBuffers/ByteBuffer.swift @@ -121,7 +121,7 @@ public struct ByteBuffer { ensureSpace(size: padding) _writerSize += (MemoryLayout<UInt8>.size * Int(padding)) } - + ///Adds an array of type Scalar to the buffer memory /// - Parameter elements: An array of Scalars @usableFromInline mutating func push<T: Scalar>(elements: [T]) { @@ -249,6 +249,11 @@ 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) + var zero: UInt8 = 0 + for i in 0..<(_writerSize - size) { + memcpy(_storage.memory.advanced(by: writerIndex + i), &zero, MemoryLayout<UInt8>.size) + } _writerSize = size } diff --git a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift index 86dfb764..77f25b31 100644 --- a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift +++ b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift @@ -2,8 +2,9 @@ import Foundation public struct FlatBufferBuilder { - /// Vtables used in the buffer are stored in here, so they would be written later in EndTable - private var _vtable: [UInt32] = [] + /// Storage for the Vtables used in the buffer are stored in here, so they would be written later in EndTable + @usableFromInline internal var _vtableStorage = VTableStorage() + /// Reference Vtables that were already written to the buffer private var _vtables: [UOffset] = [] /// Flatbuffer data will be written into @@ -76,16 +77,11 @@ public struct FlatBufferBuilder { _minAlignment = 0 isNested = false stringOffsetMap = [:] - _vtable = [] _vtables = [] + _vtableStorage.clear() _bb.clear() } - - /// Removes all the offsets from the VTable - mutating public func clearOffsets() { - _vtable = [] - } - + // MARK: - Create Tables /// Checks if the required fields were serialized into the buffer @@ -124,7 +120,7 @@ public struct FlatBufferBuilder { preAlign(len: size + (prefix ? size : 0), alignment: _minAlignment) push(element: refer(to: offset.o)) if prefix { push(element: _bb.size) } - clearOffsets() + _vtableStorage.clear() finished = true } @@ -135,7 +131,7 @@ public struct FlatBufferBuilder { mutating public func startTable(with numOfFields: Int) -> UOffset { notNested() isNested = true - _vtable = [UInt32](repeating: 0, count: numOfFields) + _vtableStorage.start(count: numOfFields) return _bb.size } @@ -154,24 +150,20 @@ public struct FlatBufferBuilder { let tableObjectSize = vTableOffset - startOffset assert(tableObjectSize < 0x10000, "Buffer can't grow beyond 2 Gigabytes") + let _max = UInt32(_vtableStorage.maxOffset) + UInt32(sizeofVoffset) - var writeIndex = 0 - for (index,j) in _vtable.lazy.reversed().enumerated() { - if j != 0 { - writeIndex = _vtable.count - index - break - } - } + _bb.fill(padding: _max) + _bb.write(value: VOffset(tableObjectSize), index: _bb.writerIndex + sizeofVoffset, direct: true) + _bb.write(value: VOffset(_max), index: _bb.writerIndex, direct: true) - for i in stride(from: writeIndex - 1, to: -1, by: -1) { - let off = _vtable[i] == 0 ? 0 : vTableOffset - _vtable[i] - _bb.push(value: VOffset(off), len: sizeofVoffset) + for index in stride(from: 0, to: _vtableStorage.writtenIndex, by: _vtableStorage.size) { + let loaded = _vtableStorage.load(at: index) + guard loaded.offset != 0 else { continue } + let _index = (_bb.writerIndex + Int(loaded.position)) + _bb.write(value: VOffset(vTableOffset - loaded.offset), index: _index, direct: true) } - _bb.push(value: VOffset(tableObjectSize), len: sizeofVoffset) - _bb.push(value: (UInt16(writeIndex + 2) * UInt16(sizeofVoffset)), len: sizeofVoffset) - - clearOffsets() + _vtableStorage.clear() let vt_use = _bb.size var isAlreadyAdded: Int? @@ -255,7 +247,7 @@ public struct FlatBufferBuilder { /// - offset: The offset of the element witten /// - position: The position of the element @usableFromInline mutating internal func track(offset: UOffset, at position: VOffset) { - _vtable[Int(position)] = offset + _vtableStorage.add(loc: FieldLoc(offset: offset, position: position)) } // MARK: - Vectors @@ -400,9 +392,8 @@ public struct FlatBufferBuilder { /// /// The function fatalErrors if we pass an offset that is out of range /// - Parameter o: offset - mutating public func add(structOffset o: UOffset) { - guard Int(o) < _vtable.count else { fatalError("Out of the table range") } - _vtable[Int(o)] = _bb.size + mutating public func add(structOffset o: VOffset) { + _vtableStorage.add(loc: FieldLoc(offset: _bb.size, position: VOffset(o))) } // MARK: - Inserting Strings @@ -411,7 +402,7 @@ public struct FlatBufferBuilder { /// - Parameter str: String to be serialized /// - returns: The strings offset in the buffer mutating public func create(string str: String) -> Offset<String> { - let len = str.count + let len = str.utf8.count notNested() preAlign(len: len + 1, type: UOffset.self) _bb.fill(padding: 1) @@ -510,4 +501,82 @@ extension FlatBufferBuilder: CustomDebugStringConvertible { { finished: \(finished), serializeDefaults: \(serializeDefaults), isNested: \(isNested) } """ } + + /// VTableStorage is a class to contain the VTable buffer that would be serialized into buffer + @usableFromInline internal class VTableStorage { + /// Memory check since deallocating each time we want to clear would be expensive + /// and memory leaks would happen if we dont deallocate the first allocated memory. + /// memory is promised to be available before adding `FieldLoc` + private var memoryInUse = false + /// Size of FieldLoc in memory + let size = MemoryLayout<FieldLoc>.stride + /// Memeory buffer + var memory: UnsafeMutableRawBufferPointer! + /// Capacity of the current buffer + var capacity: Int = 0 + /// Maximuim offset written to the class + var maxOffset: VOffset = 0 + /// number of fields written into the buffer + var numOfFields: Int = 0 + /// Last written Index + var writtenIndex: Int = 0 + /// the amount of added elements into the buffer + var addedElements: Int { return capacity - (numOfFields * size) } + + /// Creates the memory to store the buffer in + init() { + memory = UnsafeMutableRawBufferPointer.allocate(byteCount: 0, alignment: 0) + } + + deinit { + memory.deallocate() + } + + /// 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 + ensure(space: capacity) + } + + /// Adds a FieldLoc into the buffer, which would track how many have been written, + /// and max offset + /// - 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 + maxOffset = max(loc.position, maxOffset) + } + + /// Clears the data stored related to the encoded buffer + func clear() { + maxOffset = 0 + numOfFields = 0 + writtenIndex = 0 + } + + /// 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 } + memory.deallocate() + memory = UnsafeMutableRawBufferPointer.allocate(byteCount: space, alignment: size) + capacity = space + } + + /// Loads an object of type `FieldLoc` from buffer memory + /// - Parameter index: index of element + /// - Returns: a FieldLoc at index + func load(at index: Int) -> FieldLoc { + return memory.load(fromByteOffset: index, as: FieldLoc.self) + } + + } + + internal struct FieldLoc { + var offset: UOffset + var position: VOffset + } + } |