Skip to content

Commit 575d616

Browse files
authored
[Swift] Moves capacity outside of Storage (#8650)
- Cleans up capacity usage within the lib and moves it outside of the Storage - Use overflow operators
1 parent f32a7dc commit 575d616

File tree

13 files changed

+121
-110
lines changed

13 files changed

+121
-110
lines changed

swift/Sources/FlatBuffers/ByteBuffer.swift

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ public struct ByteBuffer {
4040

4141
/// This storage doesn't own the memory, therefore, we won't deallocate on deinit.
4242
private let isOwned: Bool
43+
/// Capacity of UInt8 the buffer can hold
44+
private let capacity: Int
4345
/// Retained blob of data that requires the storage to retain a pointer to.
4446
@usableFromInline
4547
var retainedBlob: Blob
46-
/// Capacity of UInt8 the buffer can hold
47-
var capacity: Int
4848

4949
@usableFromInline
5050
init(count: Int) {
@@ -179,11 +179,11 @@ public struct ByteBuffer {
179179
/// The size of the elements written to the buffer + their paddings
180180
private var _readerIndex: Int = 0
181181
/// Reader is the position of the current Writer Index (capacity - size)
182-
public var reader: Int { _storage.capacity &- _readerIndex }
182+
public var reader: Int { capacity &- _readerIndex }
183183
/// Current size of the buffer
184184
public var size: UOffset { UOffset(_readerIndex) }
185185
/// Current capacity for the buffer
186-
public var capacity: Int { _storage.capacity }
186+
public let capacity: Int
187187

188188
/// Constructor that creates a Flatbuffer object from an InternalByteBuffer
189189
/// - Parameter
@@ -194,6 +194,7 @@ public struct ByteBuffer {
194194
blob: .byteBuffer(byteBuffer),
195195
capacity: byteBuffer.capacity)
196196
_readerIndex = Int(byteBuffer.size)
197+
self.capacity = byteBuffer.capacity
197198
}
198199

199200
/// Constructor that creates a Flatbuffer from unsafe memory region by copying
@@ -209,7 +210,8 @@ public struct ByteBuffer {
209210
{
210211
_storage = Storage(count: capacity)
211212
_storage.copy(from: memory, count: capacity)
212-
_readerIndex = _storage.capacity
213+
_readerIndex = capacity
214+
self.capacity = capacity
213215
}
214216

215217
/// Constructor that creates a Flatbuffer object from a UInt8
@@ -218,7 +220,8 @@ public struct ByteBuffer {
218220
@inline(__always)
219221
public init(bytes: [UInt8]) {
220222
_storage = Storage(blob: .array(bytes), capacity: bytes.count)
221-
_readerIndex = _storage.capacity
223+
_readerIndex = bytes.count
224+
capacity = bytes.count
222225
}
223226

224227
#if !os(WASI)
@@ -228,7 +231,8 @@ public struct ByteBuffer {
228231
@inline(__always)
229232
public init(data: Data) {
230233
_storage = Storage(blob: .data(data), capacity: data.count)
231-
_readerIndex = _storage.capacity
234+
_readerIndex = data.count
235+
capacity = data.count
232236
}
233237

234238
/// Constructor that creates a Flatbuffer object from a ContiguousBytes
@@ -241,7 +245,8 @@ public struct ByteBuffer {
241245
count: Int)
242246
{
243247
_storage = Storage(blob: .bytes(contiguousBytes), capacity: count)
244-
_readerIndex = _storage.capacity
248+
_readerIndex = count
249+
self.capacity = count
245250
}
246251
#endif
247252

@@ -259,7 +264,8 @@ public struct ByteBuffer {
259264
_storage = Storage(
260265
blob: .pointer(memory),
261266
capacity: capacity)
262-
_readerIndex = _storage.capacity
267+
_readerIndex = capacity
268+
self.capacity = capacity
263269
}
264270

265271
/// Creates a copy of the existing flatbuffer, by copying it to a different memory.
@@ -275,6 +281,7 @@ public struct ByteBuffer {
275281
{
276282
_storage = Storage(blob: blob, capacity: count)
277283
_readerIndex = removeBytes
284+
capacity = count
278285
}
279286

280287
/// Write stores an object into the buffer directly or indirectly.
@@ -289,11 +296,11 @@ public struct ByteBuffer {
289296
func write<T>(value: T, index: Int, direct: Bool = false) {
290297
var index = index
291298
if !direct {
292-
index = _storage.capacity &- index
299+
index = capacity &- index
293300
}
294-
assert(index < _storage.capacity, "Write index is out of writing bound")
301+
assert(index < capacity, "Write index is out of writing bound")
295302
assert(index >= 0, "Writer index should be above zero")
296-
withUnsafePointer(to: value) { ptr in
303+
_ = withUnsafePointer(to: value) { ptr in
297304
_storage.withUnsafeRawPointer {
298305
memcpy(
299306
$0.advanced(by: index),
@@ -325,7 +332,7 @@ public struct ByteBuffer {
325332
count: Int) -> [T]
326333
{
327334
assert(
328-
index + count <= _storage.capacity,
335+
index + count <= capacity,
329336
"Reading out of bounds is illegal")
330337

331338
return _storage.readWithUnsafeRawPointer(position: index) {
@@ -348,7 +355,7 @@ public struct ByteBuffer {
348355
body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T
349356
{
350357
assert(
351-
index + count <= _storage.capacity,
358+
index + count <= capacity,
352359
"Reading out of bounds is illegal")
353360
return try _storage.readWithUnsafeRawPointer(position: index) {
354361
try body(UnsafeRawBufferPointer(start: $0, count: count))
@@ -368,7 +375,7 @@ public struct ByteBuffer {
368375
type: String.Encoding = .utf8) -> String?
369376
{
370377
assert(
371-
index + count <= _storage.capacity,
378+
index + count <= capacity,
372379
"Reading out of bounds is illegal")
373380
return _storage.readWithUnsafeRawPointer(position: index) {
374381
let buf = UnsafeBufferPointer(
@@ -390,7 +397,7 @@ public struct ByteBuffer {
390397
count: Int) -> String?
391398
{
392399
assert(
393-
index + count <= _storage.capacity,
400+
index + count <= capacity,
394401
"Reading out of bounds is illegal")
395402
return _storage.readWithUnsafeRawPointer(position: index) {
396403
String(cString: $0.bindMemory(to: UInt8.self, capacity: count))
@@ -404,11 +411,11 @@ public struct ByteBuffer {
404411
public func duplicate(removing removeBytes: Int = 0) -> ByteBuffer {
405412
assert(removeBytes > 0, "Can NOT remove negative bytes")
406413
assert(
407-
removeBytes < _storage.capacity,
414+
removeBytes < capacity,
408415
"Can NOT remove more bytes than the ones allocated")
409416
return ByteBuffer(
410417
blob: _storage.retainedBlob,
411-
count: _storage.capacity,
418+
count: capacity,
412419
removing: _readerIndex &- removeBytes)
413420
}
414421

@@ -456,7 +463,7 @@ extension ByteBuffer: CustomDebugStringConvertible {
456463
public var debugDescription: String {
457464
"""
458465
buffer located at: \(_storage.retainedBlob),
459-
with capacity of \(_storage.capacity),
466+
with capacity of \(capacity),
460467
{ writtenSize: \(_readerIndex), readerSize: \(reader),
461468
size: \(size) }
462469
"""

swift/Sources/FlatBuffers/Mutable.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ extension Mutable where Self == Table {
4949
/// - index: index of the Element
5050
public func mutate<T: Scalar>(_ value: T, index: Int32) -> Bool {
5151
guard index != 0 else { return false }
52-
return mutate(value: value, o: index + position)
52+
return mutate(value: value, o: index &+ position)
5353
}
5454

5555
/// Directly mutates the element by calling mutate
@@ -70,7 +70,7 @@ extension Mutable where Self == Struct {
7070
/// - value: New value to be inserted to the buffer
7171
/// - index: index of the Element
7272
public func mutate<T: Scalar>(_ value: T, index: Int32) -> Bool {
73-
mutate(value: value, o: index + position)
73+
mutate(value: value, o: index &+ position)
7474
}
7575

7676
/// Directly mutates the element by calling mutate

swift/Sources/FlatBuffers/Struct.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public struct Struct {
4545
/// - o: Current offset of the data
4646
/// - Returns: Data of Type T that conforms to type Scalar
4747
public func readBuffer<T: Scalar>(of type: T.Type, at o: Int32) -> T {
48-
let r = bb.read(def: T.self, position: Int(o + position))
48+
let r = bb.read(def: T.self, position: Int(o &+ position))
4949
return r
5050
}
5151
}

swift/Sources/FlatBuffers/Table.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ public struct Table {
167167
public func vector(at o: Int32) -> Int32 {
168168
var o = o
169169
o &+= position
170-
return o &+ bb.read(def: Int32.self, position: Int(o)) + 4
170+
return o &+ bb.read(def: Int32.self, position: Int(o)) &+ 4
171171
}
172172

173173
/// Reading an indirect offset of a table.
@@ -176,7 +176,7 @@ public struct Table {
176176
/// - fbb: ByteBuffer
177177
/// - Returns: table offset
178178
static public func indirect(_ o: Int32, _ fbb: ByteBuffer) -> Int32 {
179-
o + fbb.read(def: Int32.self, position: Int(o))
179+
o &+ fbb.read(def: Int32.self, position: Int(o))
180180
}
181181

182182
/// Gets a vtable value according to an table Offset and a field offset

swift/Sources/FlatBuffers/_InternalByteBuffer.swift

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,12 @@ struct _InternalByteBuffer {
3131
final class Storage {
3232
/// pointer to the start of the buffer object in memory
3333
private(set) var memory: UnsafeMutableRawPointer
34-
/// Capacity of UInt8 the buffer can hold
35-
private(set) var capacity: Int
3634

3735
@usableFromInline
3836
init(count: Int, alignment: Int) {
3937
memory = UnsafeMutableRawPointer.allocate(
4038
byteCount: count,
4139
alignment: alignment)
42-
capacity = count
4340
}
4441

4542
deinit {
@@ -54,15 +51,12 @@ struct _InternalByteBuffer {
5451
/// Reallocates the buffer incase the object to be written doesnt fit in the current buffer
5552
/// - Parameter size: Size of the current object
5653
@usableFromInline
57-
func reallocate(_ size: Int, writerSize: Int, alignment: Int) {
58-
let currentWritingIndex = capacity &- writerSize
59-
while capacity <= writerSize &+ size {
60-
capacity = capacity << 1
61-
}
62-
63-
/// solution take from Apple-NIO
64-
capacity = capacity.convertToPowerofTwo
65-
54+
func reallocate(
55+
capacity: Int,
56+
writerSize: Int,
57+
currentWritingIndex: Int,
58+
alignment: Int
59+
) {
6660
let newData = UnsafeMutableRawPointer.allocate(
6761
byteCount: capacity,
6862
alignment: alignment)
@@ -84,7 +78,7 @@ struct _InternalByteBuffer {
8478
/// Alignment of the current memory being written to the buffer
8579
var alignment = 1
8680
/// Current Index which is being used to write to the buffer, it is written from the end to the start of the buffer
87-
var writerIndex: Int { _storage.capacity &- _writerSize }
81+
var writerIndex: Int { capacity &- _writerSize }
8882

8983
/// Reader is the position of the current Writer Index (capacity - size)
9084
public var reader: Int { writerIndex }
@@ -94,14 +88,15 @@ struct _InternalByteBuffer {
9488
@usableFromInline
9589
var memory: UnsafeMutableRawPointer { _storage.memory }
9690
/// Current capacity for the buffer
97-
public var capacity: Int { _storage.capacity }
91+
public private(set) var capacity: Int
9892

9993
/// Constructor that creates a Flatbuffer instance with a size
10094
/// - Parameter:
10195
/// - size: Length of the buffer
10296
/// - allowReadingUnalignedBuffers: allow reading from unaligned buffer
10397
init(initialSize size: Int) {
10498
initialSize = size.convertToPowerofTwo
99+
capacity = initialSize
105100
_storage = Storage(count: initialSize, alignment: alignment)
106101
_storage.initialize(for: initialSize)
107102
}
@@ -246,11 +241,11 @@ struct _InternalByteBuffer {
246241
func write<T>(value: T, index: Int, direct: Bool = false) {
247242
var index = index
248243
if !direct {
249-
index = _storage.capacity &- index
244+
index = capacity &- index
250245
}
251-
assert(index < _storage.capacity, "Write index is out of writing bound")
246+
assert(index < capacity, "Write index is out of writing bound")
252247
assert(index >= 0, "Writer index should be above zero")
253-
withUnsafePointer(to: value) {
248+
_ = withUnsafePointer(to: value) {
254249
memcpy(
255250
_storage.memory.advanced(by: index),
256251
$0,
@@ -262,10 +257,24 @@ struct _InternalByteBuffer {
262257
/// - Parameter size: size of object
263258
@discardableResult
264259
@usableFromInline
265-
@inline(__always)
266260
mutating func ensureSpace(size: Int) -> Int {
267-
if size &+ _writerSize > _storage.capacity {
268-
_storage.reallocate(size, writerSize: _writerSize, alignment: alignment)
261+
let expectedWriterIndex = size &+ _writerSize
262+
if expectedWriterIndex > capacity {
263+
264+
let currentWritingIndex = capacity &- _writerSize
265+
while capacity <= expectedWriterIndex {
266+
capacity = capacity << 1
267+
}
268+
269+
/// solution take from Apple-NIO
270+
capacity = capacity.convertToPowerofTwo
271+
272+
273+
_storage.reallocate(
274+
capacity: capacity,
275+
writerSize: _writerSize,
276+
currentWritingIndex: currentWritingIndex,
277+
alignment: alignment)
269278
}
270279
assert(size < FlatBufferMaxSize, "Buffer can't grow beyond 2 Gigabytes")
271280
return size
@@ -295,8 +304,9 @@ struct _InternalByteBuffer {
295304
_writerSize = 0
296305
alignment = 1
297306
if keepingCapacity {
298-
_storage.initialize(for: _storage.capacity)
307+
_storage.initialize(for: capacity)
299308
} else {
309+
capacity = initialSize
300310
_storage = Storage(count: initialSize, alignment: alignment)
301311
}
302312
}
@@ -358,7 +368,7 @@ extension _InternalByteBuffer: CustomDebugStringConvertible {
358368

359369
public var debugDescription: String {
360370
"""
361-
buffer located at: \(_storage.memory), with capacity of \(_storage.capacity)
371+
buffer located at: \(_storage.memory), with capacity of \(capacity)
362372
{ writerSize: \(_writerSize), readerSize: \(reader), writerIndex: \(
363373
writerIndex) }
364374
"""

0 commit comments

Comments
 (0)