From 7cb4762a61fc6ac3543558e7e7836985bffa07fe Mon Sep 17 00:00:00 2001 From: mustiikhalil Date: Thu, 11 Jun 2020 18:53:32 +0300 Subject: [PATCH] [Swift] Improving reallocation time by using memcpy and moving reallocation code to storage (#5960) Removes stride Use capacity - current size to initialize Fixes memory leak Updated test code for linux --- swift/Sources/FlatBuffers/ByteBuffer.swift | 44 +++++++++++----------- swift/Sources/FlatBuffers/FlatBufferBuilder.swift | 7 ++-- .../XCTestManifests.swift | 1 + 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/swift/Sources/FlatBuffers/ByteBuffer.swift b/swift/Sources/FlatBuffers/ByteBuffer.swift index 75ad075..40b9cd7 100644 --- a/swift/Sources/FlatBuffers/ByteBuffer.swift +++ b/swift/Sources/FlatBuffers/ByteBuffer.swift @@ -27,6 +27,24 @@ public struct ByteBuffer { func initalize(for size: Int) { memory.initializeMemory(as: UInt8.self, repeating: 0, count: 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) { + capacity = capacity << 1 + } + + /// solution take from Apple-NIO + 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) + memory.deallocate() + memory = newData + } } @usableFromInline var _storage: Storage @@ -208,31 +226,13 @@ public struct ByteBuffer { /// - Parameter size: size of object @discardableResult @usableFromInline mutating func ensureSpace(size: UInt32) -> UInt32 { - if Int(size) + _writerSize > _storage.capacity { reallocate(size) } + if Int(size) + _writerSize > _storage.capacity { + _storage.reallocate(size, writerSize: _writerSize, alignment: alignment) + } assert(size < FlatBufferMaxSize, "Buffer can't grow beyond 2 Gigabytes") return size } - - /// Reallocates the buffer incase the object to be written doesnt fit in the current buffer - /// - Parameter size: Size of the current object - @usableFromInline mutating internal func reallocate(_ size: UInt32) { - let currentWritingIndex = writerIndex - while _storage.capacity <= _writerSize + Int(size) { - _storage.capacity = _storage.capacity << 1 - } - - /// solution take from Apple-NIO - _storage.capacity = _storage.capacity.convertToPowerofTwo - - let newData = UnsafeMutableRawPointer.allocate(byteCount: _storage.capacity, alignment: alignment) - newData.initializeMemory(as: UInt8.self, repeating: 0, count: _storage.capacity) - newData - .advanced(by: writerIndex) - .copyMemory(from: _storage.memory.advanced(by: currentWritingIndex), byteCount: _writerSize) - _storage.memory.deallocate() - _storage.memory = newData - } - + /// Clears the current size of the buffer mutating public func clearSize() { _writerSize = 0 diff --git a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift index cd2523f..2501a39 100644 --- a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift +++ b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift @@ -135,7 +135,6 @@ public struct FlatBufferBuilder { return _bb.size } - /// Endtable will let the builder know that the object that's written to it is completed /// /// This would be called after all the elements are serialized, it will add the vtable into the buffer. @@ -156,8 +155,10 @@ public struct FlatBufferBuilder { _bb.write(value: VOffset(tableObjectSize), index: _bb.writerIndex + sizeofVoffset, direct: true) _bb.write(value: VOffset(_max), index: _bb.writerIndex, direct: true) - for index in stride(from: 0, to: _vtableStorage.writtenIndex, by: _vtableStorage.size) { - let loaded = _vtableStorage.load(at: index) + var itr = 0 + while itr < _vtableStorage.writtenIndex { + let loaded = _vtableStorage.load(at: 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) diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/XCTestManifests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/XCTestManifests.swift index 18ad6a0..d9e118d 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/XCTestManifests.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/XCTestManifests.swift @@ -36,6 +36,7 @@ extension FlatBuffersStructsTests { ("testCreatingVectorStructWithForcedDefaults", testCreatingVectorStructWithForcedDefaults), ("testReadingStruct", testReadingStruct), ("testReadingStructWithEnums", testReadingStructWithEnums), + ("testWritingAndMutatingBools", testWritingAndMutatingBools), ] } -- 2.7.4