[Swift] Moves capacity outside of Storage (#8650)

- Cleans up capacity usage within the lib and moves it outside of the Storage

-  Use overflow operators
This commit is contained in:
mustiikhalil
2025-07-29 23:21:20 +02:00
committed by GitHub
parent f32a7dcbd2
commit 575d616e60
13 changed files with 121 additions and 110 deletions

View File

@@ -40,11 +40,11 @@ public struct ByteBuffer {
/// This storage doesn't own the memory, therefore, we won't deallocate on deinit. /// This storage doesn't own the memory, therefore, we won't deallocate on deinit.
private let isOwned: Bool private let isOwned: Bool
/// Capacity of UInt8 the buffer can hold
private let capacity: Int
/// Retained blob of data that requires the storage to retain a pointer to. /// Retained blob of data that requires the storage to retain a pointer to.
@usableFromInline @usableFromInline
var retainedBlob: Blob var retainedBlob: Blob
/// Capacity of UInt8 the buffer can hold
var capacity: Int
@usableFromInline @usableFromInline
init(count: Int) { init(count: Int) {
@@ -179,11 +179,11 @@ public struct ByteBuffer {
/// The size of the elements written to the buffer + their paddings /// The size of the elements written to the buffer + their paddings
private var _readerIndex: Int = 0 private var _readerIndex: Int = 0
/// Reader is the position of the current Writer Index (capacity - size) /// Reader is the position of the current Writer Index (capacity - size)
public var reader: Int { _storage.capacity &- _readerIndex } public var reader: Int { capacity &- _readerIndex }
/// Current size of the buffer /// Current size of the buffer
public var size: UOffset { UOffset(_readerIndex) } public var size: UOffset { UOffset(_readerIndex) }
/// Current capacity for the buffer /// Current capacity for the buffer
public var capacity: Int { _storage.capacity } public let capacity: Int
/// Constructor that creates a Flatbuffer object from an InternalByteBuffer /// Constructor that creates a Flatbuffer object from an InternalByteBuffer
/// - Parameter /// - Parameter
@@ -194,6 +194,7 @@ public struct ByteBuffer {
blob: .byteBuffer(byteBuffer), blob: .byteBuffer(byteBuffer),
capacity: byteBuffer.capacity) capacity: byteBuffer.capacity)
_readerIndex = Int(byteBuffer.size) _readerIndex = Int(byteBuffer.size)
self.capacity = byteBuffer.capacity
} }
/// Constructor that creates a Flatbuffer from unsafe memory region by copying /// Constructor that creates a Flatbuffer from unsafe memory region by copying
@@ -209,7 +210,8 @@ public struct ByteBuffer {
{ {
_storage = Storage(count: capacity) _storage = Storage(count: capacity)
_storage.copy(from: memory, count: capacity) _storage.copy(from: memory, count: capacity)
_readerIndex = _storage.capacity _readerIndex = capacity
self.capacity = capacity
} }
/// Constructor that creates a Flatbuffer object from a UInt8 /// Constructor that creates a Flatbuffer object from a UInt8
@@ -218,7 +220,8 @@ public struct ByteBuffer {
@inline(__always) @inline(__always)
public init(bytes: [UInt8]) { public init(bytes: [UInt8]) {
_storage = Storage(blob: .array(bytes), capacity: bytes.count) _storage = Storage(blob: .array(bytes), capacity: bytes.count)
_readerIndex = _storage.capacity _readerIndex = bytes.count
capacity = bytes.count
} }
#if !os(WASI) #if !os(WASI)
@@ -228,7 +231,8 @@ public struct ByteBuffer {
@inline(__always) @inline(__always)
public init(data: Data) { public init(data: Data) {
_storage = Storage(blob: .data(data), capacity: data.count) _storage = Storage(blob: .data(data), capacity: data.count)
_readerIndex = _storage.capacity _readerIndex = data.count
capacity = data.count
} }
/// Constructor that creates a Flatbuffer object from a ContiguousBytes /// Constructor that creates a Flatbuffer object from a ContiguousBytes
@@ -241,7 +245,8 @@ public struct ByteBuffer {
count: Int) count: Int)
{ {
_storage = Storage(blob: .bytes(contiguousBytes), capacity: count) _storage = Storage(blob: .bytes(contiguousBytes), capacity: count)
_readerIndex = _storage.capacity _readerIndex = count
self.capacity = count
} }
#endif #endif
@@ -259,7 +264,8 @@ public struct ByteBuffer {
_storage = Storage( _storage = Storage(
blob: .pointer(memory), blob: .pointer(memory),
capacity: capacity) capacity: capacity)
_readerIndex = _storage.capacity _readerIndex = capacity
self.capacity = capacity
} }
/// Creates a copy of the existing flatbuffer, by copying it to a different memory. /// Creates a copy of the existing flatbuffer, by copying it to a different memory.
@@ -275,6 +281,7 @@ public struct ByteBuffer {
{ {
_storage = Storage(blob: blob, capacity: count) _storage = Storage(blob: blob, capacity: count)
_readerIndex = removeBytes _readerIndex = removeBytes
capacity = count
} }
/// Write stores an object into the buffer directly or indirectly. /// Write stores an object into the buffer directly or indirectly.
@@ -289,11 +296,11 @@ public struct ByteBuffer {
func write<T>(value: T, index: Int, direct: Bool = false) { func write<T>(value: T, index: Int, direct: Bool = false) {
var index = index var index = index
if !direct { if !direct {
index = _storage.capacity &- index index = capacity &- index
} }
assert(index < _storage.capacity, "Write index is out of writing bound") assert(index < capacity, "Write index is out of writing bound")
assert(index >= 0, "Writer index should be above zero") assert(index >= 0, "Writer index should be above zero")
withUnsafePointer(to: value) { ptr in _ = withUnsafePointer(to: value) { ptr in
_storage.withUnsafeRawPointer { _storage.withUnsafeRawPointer {
memcpy( memcpy(
$0.advanced(by: index), $0.advanced(by: index),
@@ -325,7 +332,7 @@ public struct ByteBuffer {
count: Int) -> [T] count: Int) -> [T]
{ {
assert( assert(
index + count <= _storage.capacity, index + count <= capacity,
"Reading out of bounds is illegal") "Reading out of bounds is illegal")
return _storage.readWithUnsafeRawPointer(position: index) { return _storage.readWithUnsafeRawPointer(position: index) {
@@ -348,7 +355,7 @@ public struct ByteBuffer {
body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T
{ {
assert( assert(
index + count <= _storage.capacity, index + count <= capacity,
"Reading out of bounds is illegal") "Reading out of bounds is illegal")
return try _storage.readWithUnsafeRawPointer(position: index) { return try _storage.readWithUnsafeRawPointer(position: index) {
try body(UnsafeRawBufferPointer(start: $0, count: count)) try body(UnsafeRawBufferPointer(start: $0, count: count))
@@ -368,7 +375,7 @@ public struct ByteBuffer {
type: String.Encoding = .utf8) -> String? type: String.Encoding = .utf8) -> String?
{ {
assert( assert(
index + count <= _storage.capacity, index + count <= capacity,
"Reading out of bounds is illegal") "Reading out of bounds is illegal")
return _storage.readWithUnsafeRawPointer(position: index) { return _storage.readWithUnsafeRawPointer(position: index) {
let buf = UnsafeBufferPointer( let buf = UnsafeBufferPointer(
@@ -390,7 +397,7 @@ public struct ByteBuffer {
count: Int) -> String? count: Int) -> String?
{ {
assert( assert(
index + count <= _storage.capacity, index + count <= capacity,
"Reading out of bounds is illegal") "Reading out of bounds is illegal")
return _storage.readWithUnsafeRawPointer(position: index) { return _storage.readWithUnsafeRawPointer(position: index) {
String(cString: $0.bindMemory(to: UInt8.self, capacity: count)) String(cString: $0.bindMemory(to: UInt8.self, capacity: count))
@@ -404,11 +411,11 @@ public struct ByteBuffer {
public func duplicate(removing removeBytes: Int = 0) -> ByteBuffer { public func duplicate(removing removeBytes: Int = 0) -> ByteBuffer {
assert(removeBytes > 0, "Can NOT remove negative bytes") assert(removeBytes > 0, "Can NOT remove negative bytes")
assert( assert(
removeBytes < _storage.capacity, removeBytes < capacity,
"Can NOT remove more bytes than the ones allocated") "Can NOT remove more bytes than the ones allocated")
return ByteBuffer( return ByteBuffer(
blob: _storage.retainedBlob, blob: _storage.retainedBlob,
count: _storage.capacity, count: capacity,
removing: _readerIndex &- removeBytes) removing: _readerIndex &- removeBytes)
} }
@@ -456,7 +463,7 @@ extension ByteBuffer: CustomDebugStringConvertible {
public var debugDescription: String { public var debugDescription: String {
""" """
buffer located at: \(_storage.retainedBlob), buffer located at: \(_storage.retainedBlob),
with capacity of \(_storage.capacity), with capacity of \(capacity),
{ writtenSize: \(_readerIndex), readerSize: \(reader), { writtenSize: \(_readerIndex), readerSize: \(reader),
size: \(size) } size: \(size) }
""" """

View File

@@ -49,7 +49,7 @@ extension Mutable where Self == Table {
/// - index: index of the Element /// - index: index of the Element
public func mutate<T: Scalar>(_ value: T, index: Int32) -> Bool { public func mutate<T: Scalar>(_ value: T, index: Int32) -> Bool {
guard index != 0 else { return false } guard index != 0 else { return false }
return mutate(value: value, o: index + position) return mutate(value: value, o: index &+ position)
} }
/// Directly mutates the element by calling mutate /// Directly mutates the element by calling mutate
@@ -70,7 +70,7 @@ extension Mutable where Self == Struct {
/// - value: New value to be inserted to the buffer /// - value: New value to be inserted to the buffer
/// - index: index of the Element /// - index: index of the Element
public func mutate<T: Scalar>(_ value: T, index: Int32) -> Bool { public func mutate<T: Scalar>(_ value: T, index: Int32) -> Bool {
mutate(value: value, o: index + position) mutate(value: value, o: index &+ position)
} }
/// Directly mutates the element by calling mutate /// Directly mutates the element by calling mutate

View File

@@ -45,7 +45,7 @@ public struct Struct {
/// - o: Current offset of the data /// - o: Current offset of the data
/// - Returns: Data of Type T that conforms to type Scalar /// - Returns: Data of Type T that conforms to type Scalar
public func readBuffer<T: Scalar>(of type: T.Type, at o: Int32) -> T { public func readBuffer<T: Scalar>(of type: T.Type, at o: Int32) -> T {
let r = bb.read(def: T.self, position: Int(o + position)) let r = bb.read(def: T.self, position: Int(o &+ position))
return r return r
} }
} }

View File

@@ -167,7 +167,7 @@ public struct Table {
public func vector(at o: Int32) -> Int32 { public func vector(at o: Int32) -> Int32 {
var o = o var o = o
o &+= position o &+= position
return o &+ bb.read(def: Int32.self, position: Int(o)) + 4 return o &+ bb.read(def: Int32.self, position: Int(o)) &+ 4
} }
/// Reading an indirect offset of a table. /// Reading an indirect offset of a table.
@@ -176,7 +176,7 @@ public struct Table {
/// - fbb: ByteBuffer /// - fbb: ByteBuffer
/// - Returns: table offset /// - Returns: table offset
static public func indirect(_ o: Int32, _ fbb: ByteBuffer) -> Int32 { static public func indirect(_ o: Int32, _ fbb: ByteBuffer) -> Int32 {
o + fbb.read(def: Int32.self, position: Int(o)) o &+ fbb.read(def: Int32.self, position: Int(o))
} }
/// Gets a vtable value according to an table Offset and a field offset /// Gets a vtable value according to an table Offset and a field offset

View File

@@ -31,15 +31,12 @@ struct _InternalByteBuffer {
final class Storage { final class Storage {
/// pointer to the start of the buffer object in memory /// pointer to the start of the buffer object in memory
private(set) var memory: UnsafeMutableRawPointer private(set) var memory: UnsafeMutableRawPointer
/// Capacity of UInt8 the buffer can hold
private(set) var capacity: Int
@usableFromInline @usableFromInline
init(count: Int, alignment: Int) { init(count: Int, alignment: Int) {
memory = UnsafeMutableRawPointer.allocate( memory = UnsafeMutableRawPointer.allocate(
byteCount: count, byteCount: count,
alignment: alignment) alignment: alignment)
capacity = count
} }
deinit { deinit {
@@ -54,15 +51,12 @@ struct _InternalByteBuffer {
/// Reallocates the buffer incase the object to be written doesnt fit in the current buffer /// Reallocates the buffer incase the object to be written doesnt fit in the current buffer
/// - Parameter size: Size of the current object /// - Parameter size: Size of the current object
@usableFromInline @usableFromInline
func reallocate(_ size: Int, writerSize: Int, alignment: Int) { func reallocate(
let currentWritingIndex = capacity &- writerSize capacity: Int,
while capacity <= writerSize &+ size { writerSize: Int,
capacity = capacity << 1 currentWritingIndex: Int,
} alignment: Int
) {
/// solution take from Apple-NIO
capacity = capacity.convertToPowerofTwo
let newData = UnsafeMutableRawPointer.allocate( let newData = UnsafeMutableRawPointer.allocate(
byteCount: capacity, byteCount: capacity,
alignment: alignment) alignment: alignment)
@@ -84,7 +78,7 @@ struct _InternalByteBuffer {
/// Alignment of the current memory being written to the buffer /// Alignment of the current memory being written to the buffer
var alignment = 1 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 /// Current Index which is being used to write to the buffer, it is written from the end to the start of the buffer
var writerIndex: Int { _storage.capacity &- _writerSize } var writerIndex: Int { capacity &- _writerSize }
/// Reader is the position of the current Writer Index (capacity - size) /// Reader is the position of the current Writer Index (capacity - size)
public var reader: Int { writerIndex } public var reader: Int { writerIndex }
@@ -94,7 +88,7 @@ struct _InternalByteBuffer {
@usableFromInline @usableFromInline
var memory: UnsafeMutableRawPointer { _storage.memory } var memory: UnsafeMutableRawPointer { _storage.memory }
/// Current capacity for the buffer /// Current capacity for the buffer
public var capacity: Int { _storage.capacity } public private(set) var capacity: Int
/// Constructor that creates a Flatbuffer instance with a size /// Constructor that creates a Flatbuffer instance with a size
/// - Parameter: /// - Parameter:
@@ -102,6 +96,7 @@ struct _InternalByteBuffer {
/// - allowReadingUnalignedBuffers: allow reading from unaligned buffer /// - allowReadingUnalignedBuffers: allow reading from unaligned buffer
init(initialSize size: Int) { init(initialSize size: Int) {
initialSize = size.convertToPowerofTwo initialSize = size.convertToPowerofTwo
capacity = initialSize
_storage = Storage(count: initialSize, alignment: alignment) _storage = Storage(count: initialSize, alignment: alignment)
_storage.initialize(for: initialSize) _storage.initialize(for: initialSize)
} }
@@ -246,11 +241,11 @@ struct _InternalByteBuffer {
func write<T>(value: T, index: Int, direct: Bool = false) { func write<T>(value: T, index: Int, direct: Bool = false) {
var index = index var index = index
if !direct { if !direct {
index = _storage.capacity &- index index = capacity &- index
} }
assert(index < _storage.capacity, "Write index is out of writing bound") assert(index < capacity, "Write index is out of writing bound")
assert(index >= 0, "Writer index should be above zero") assert(index >= 0, "Writer index should be above zero")
withUnsafePointer(to: value) { _ = withUnsafePointer(to: value) {
memcpy( memcpy(
_storage.memory.advanced(by: index), _storage.memory.advanced(by: index),
$0, $0,
@@ -262,10 +257,24 @@ struct _InternalByteBuffer {
/// - Parameter size: size of object /// - Parameter size: size of object
@discardableResult @discardableResult
@usableFromInline @usableFromInline
@inline(__always)
mutating func ensureSpace(size: Int) -> Int { mutating func ensureSpace(size: Int) -> Int {
if size &+ _writerSize > _storage.capacity { let expectedWriterIndex = size &+ _writerSize
_storage.reallocate(size, writerSize: _writerSize, alignment: alignment) if expectedWriterIndex > capacity {
let currentWritingIndex = capacity &- _writerSize
while capacity <= expectedWriterIndex {
capacity = capacity << 1
}
/// solution take from Apple-NIO
capacity = capacity.convertToPowerofTwo
_storage.reallocate(
capacity: capacity,
writerSize: _writerSize,
currentWritingIndex: currentWritingIndex,
alignment: alignment)
} }
assert(size < FlatBufferMaxSize, "Buffer can't grow beyond 2 Gigabytes") assert(size < FlatBufferMaxSize, "Buffer can't grow beyond 2 Gigabytes")
return size return size
@@ -295,8 +304,9 @@ struct _InternalByteBuffer {
_writerSize = 0 _writerSize = 0
alignment = 1 alignment = 1
if keepingCapacity { if keepingCapacity {
_storage.initialize(for: _storage.capacity) _storage.initialize(for: capacity)
} else { } else {
capacity = initialSize
_storage = Storage(count: initialSize, alignment: alignment) _storage = Storage(count: initialSize, alignment: alignment)
} }
} }
@@ -358,7 +368,7 @@ extension _InternalByteBuffer: CustomDebugStringConvertible {
public var debugDescription: String { public var debugDescription: String {
""" """
buffer located at: \(_storage.memory), with capacity of \(_storage.capacity) buffer located at: \(_storage.memory), with capacity of \(capacity)
{ writerSize: \(_writerSize), readerSize: \(reader), writerIndex: \( { writerSize: \(_writerSize), readerSize: \(reader), writerIndex: \(
writerIndex) } writerIndex) }
""" """

View File

@@ -40,11 +40,11 @@ public struct ByteBuffer {
/// This storage doesn't own the memory, therefore, we won't deallocate on deinit. /// This storage doesn't own the memory, therefore, we won't deallocate on deinit.
private let isOwned: Bool private let isOwned: Bool
/// Capacity of UInt8 the buffer can hold
private let capacity: Int
/// Retained blob of data that requires the storage to retain a pointer to. /// Retained blob of data that requires the storage to retain a pointer to.
@usableFromInline @usableFromInline
var retainedBlob: Blob var retainedBlob: Blob
/// Capacity of UInt8 the buffer can hold
var capacity: Int
@usableFromInline @usableFromInline
init(count: Int) { init(count: Int) {
@@ -178,12 +178,10 @@ public struct ByteBuffer {
/// The size of the elements written to the buffer + their paddings /// The size of the elements written to the buffer + their paddings
private var _readerIndex: Int = 0 private var _readerIndex: Int = 0
// /// Reader is the position of the current Writer Index (capacity - size)
// var reader: Int { _storage.capacity &- _readerIndex }
/// Current size of the buffer /// Current size of the buffer
public var count: Int { _readerIndex } public var count: Int { _readerIndex }
/// Current capacity for the buffer including unused space /// Current capacity for the buffer including unused space
public var capacity: Int { _storage.capacity } public let capacity: Int
/// Constructor that creates a Flatbuffer object from an InternalByteBuffer /// Constructor that creates a Flatbuffer object from an InternalByteBuffer
/// - Parameter /// - Parameter
@@ -194,6 +192,7 @@ public struct ByteBuffer {
blob: .byteBuffer(byteBuffer), blob: .byteBuffer(byteBuffer),
capacity: byteBuffer.capacity) capacity: byteBuffer.capacity)
_readerIndex = byteBuffer.writerIndex _readerIndex = byteBuffer.writerIndex
capacity = byteBuffer.capacity
} }
/// Constructor that creates a Flatbuffer from unsafe memory region by copying /// Constructor that creates a Flatbuffer from unsafe memory region by copying
@@ -209,7 +208,8 @@ public struct ByteBuffer {
{ {
_storage = Storage(count: capacity) _storage = Storage(count: capacity)
_storage.copy(from: memory, count: capacity) _storage.copy(from: memory, count: capacity)
_readerIndex = _storage.capacity _readerIndex = capacity
self.capacity = capacity
} }
/// Constructor that creates a Flatbuffer object from a UInt8 /// Constructor that creates a Flatbuffer object from a UInt8
@@ -218,7 +218,8 @@ public struct ByteBuffer {
@inline(__always) @inline(__always)
public init(bytes: [UInt8]) { public init(bytes: [UInt8]) {
_storage = Storage(blob: .array(bytes), capacity: bytes.count) _storage = Storage(blob: .array(bytes), capacity: bytes.count)
_readerIndex = _storage.capacity _readerIndex = bytes.count
capacity = bytes.count
} }
#if !os(WASI) #if !os(WASI)
@@ -228,7 +229,8 @@ public struct ByteBuffer {
@inline(__always) @inline(__always)
public init(data: Data) { public init(data: Data) {
_storage = Storage(blob: .data(data), capacity: data.count) _storage = Storage(blob: .data(data), capacity: data.count)
_readerIndex = _storage.capacity _readerIndex = data.count
capacity = data.count
} }
/// Constructor that creates a Flatbuffer object from a ContiguousBytes /// Constructor that creates a Flatbuffer object from a ContiguousBytes
@@ -241,7 +243,8 @@ public struct ByteBuffer {
count: Int) count: Int)
{ {
_storage = Storage(blob: .bytes(contiguousBytes), capacity: count) _storage = Storage(blob: .bytes(contiguousBytes), capacity: count)
_readerIndex = _storage.capacity _readerIndex = count
capacity = count
} }
#endif #endif
@@ -259,7 +262,8 @@ public struct ByteBuffer {
_storage = Storage( _storage = Storage(
blob: .pointer(memory), blob: .pointer(memory),
capacity: capacity) capacity: capacity)
_readerIndex = _storage.capacity _readerIndex = capacity
self.capacity = capacity
} }
/// Creates a copy of the existing flatbuffer, by copying it to a different memory. /// Creates a copy of the existing flatbuffer, by copying it to a different memory.
@@ -275,6 +279,7 @@ public struct ByteBuffer {
{ {
_storage = Storage(blob: blob, capacity: count) _storage = Storage(blob: blob, capacity: count)
_readerIndex = removeBytes _readerIndex = removeBytes
capacity = count
} }
/// Write stores an object into the buffer directly or indirectly. /// Write stores an object into the buffer directly or indirectly.
@@ -289,11 +294,11 @@ public struct ByteBuffer {
func write<T>(value: T, index: Int, direct: Bool = false) { func write<T>(value: T, index: Int, direct: Bool = false) {
var index = index var index = index
if !direct { if !direct {
index = _storage.capacity &- index index = capacity &- index
} }
assert(index < _storage.capacity, "Write index is out of writing bound") assert(index < capacity, "Write index is out of writing bound")
assert(index >= 0, "Writer index should be above zero") assert(index >= 0, "Writer index should be above zero")
withUnsafePointer(to: value) { ptr in _ = withUnsafePointer(to: value) { ptr in
_storage.withUnsafeRawPointer { _storage.withUnsafeRawPointer {
memcpy( memcpy(
$0.advanced(by: index), $0.advanced(by: index),
@@ -387,7 +392,7 @@ public struct ByteBuffer {
count: Int) -> [T] count: Int) -> [T]
{ {
assert( assert(
index + count <= _storage.capacity, index + count <= capacity,
"Reading out of bounds is illegal") "Reading out of bounds is illegal")
return _storage.readWithUnsafeRawPointer(position: index) { return _storage.readWithUnsafeRawPointer(position: index) {
@@ -405,7 +410,7 @@ public struct ByteBuffer {
type: String.Encoding) -> String? type: String.Encoding) -> String?
{ {
assert( assert(
index + count <= _storage.capacity, index + count <= capacity,
"Reading out of bounds is illegal") "Reading out of bounds is illegal")
return _storage.readWithUnsafeRawPointer(position: index) { return _storage.readWithUnsafeRawPointer(position: index) {
let buf = UnsafeBufferPointer( let buf = UnsafeBufferPointer(
@@ -427,7 +432,7 @@ public struct ByteBuffer {
count: Int) -> String? count: Int) -> String?
{ {
assert( assert(
index + count <= _storage.capacity, index + count <= capacity,
"Reading out of bounds is illegal") "Reading out of bounds is illegal")
return _storage.readWithUnsafeRawPointer(position: index) { return _storage.readWithUnsafeRawPointer(position: index) {
String(cString: $0.bindMemory(to: UInt8.self, capacity: count)) String(cString: $0.bindMemory(to: UInt8.self, capacity: count))
@@ -446,7 +451,7 @@ public struct ByteBuffer {
body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T
{ {
assert( assert(
index + count <= _storage.capacity, index + count <= capacity,
"Reading out of bounds is illegal") "Reading out of bounds is illegal")
return try _storage.readWithUnsafeRawPointer(position: index) { return try _storage.readWithUnsafeRawPointer(position: index) {
try body(UnsafeRawBufferPointer(start: $0, count: count)) try body(UnsafeRawBufferPointer(start: $0, count: count))

View File

@@ -25,7 +25,7 @@ extension FlexBufferVector {
json += "[" json += "["
for i in 0..<count { for i in 0..<count {
if let val = self[i]?.jsonString() { if let val = self[i]?.jsonString() {
let comma = i == count - 1 ? "" : ", " let comma = i == count &- 1 ? "" : ", "
json += "\(val)\(comma)" json += "\(val)\(comma)"
} }
} }

View File

@@ -52,7 +52,7 @@ extension Map {
json += "{" json += "{"
for i in 0..<count { for i in 0..<count {
if let key = keys[i]?.cString { if let key = keys[i]?.cString {
let comma = i == count - 1 ? "" : ", " let comma = i == count &- 1 ? "" : ", "
let value = values[i]?.jsonString() ?? StaticJSON.null let value = values[i]?.jsonString() ?? StaticJSON.null
json += "\"\(key)\": \(value)\(comma)" json += "\"\(key)\": \(value)\(comma)"
} }

View File

@@ -117,9 +117,9 @@ func toFixedTypedVectorElementType(type: FlexBufferType)
let fixedType: UInt64 = numericCast( let fixedType: UInt64 = numericCast(
type.rawValue &- FlexBufferType.vectorInt2 type.rawValue &- FlexBufferType.vectorInt2
.rawValue) .rawValue)
let len: Int = numericCast((fixedType / 3) + 2) let len: Int = numericCast(fixedType.dividedReportingOverflow(by: 3).partialValue &+ 2)
return ( return (
FlexBufferType(rawValue: (fixedType % 3) + FlexBufferType.int.rawValue), FlexBufferType(rawValue: (fixedType.quotientAndRemainder(dividingBy: 3).remainder) &+ FlexBufferType.int.rawValue),
len) len)
} }

View File

@@ -143,7 +143,7 @@ public struct FlexBuffersWriter {
{ {
let vec = createVector( let vec = createVector(
start: start, start: start,
count: stack.count - start, count: stack.count &- start,
step: 1, step: 1,
typed: typed, typed: typed,
fixed: fixed, fixed: fixed,
@@ -211,7 +211,7 @@ public struct FlexBuffersWriter {
typed: true, typed: true,
fixed: false) fixed: false)
let vec = createVector( let vec = createVector(
start: start + 1, start: start &+ 1,
count: len, count: len,
step: 2, step: 2,
typed: false, typed: false,
@@ -598,7 +598,7 @@ public struct FlexBuffersWriter {
var sloc: UInt = numericCast(writerIndex) var sloc: UInt = numericCast(writerIndex)
key.withCString { key.withCString {
_bb.writeBytes($0, len: len + 1) _bb.writeBytes($0, len: len &+ 1)
} }
if flags > .shareKeys { if flags > .shareKeys {
@@ -705,7 +705,7 @@ public struct FlexBuffersWriter {
/// If this vector is part of a map, we will pre-fix an offset to the keys /// If this vector is part of a map, we will pre-fix an offset to the keys
/// to this vector. /// to this vector.
bitWidth = max(bitWidth, keys!.elementWidth(size: writerIndex, index: 0)) bitWidth = max(bitWidth, keys!.elementWidth(size: writerIndex, index: 0))
prefixElements += 2 prefixElements = prefixElements &+ 2
} }
var vectorType: FlexBufferType = .key var vectorType: FlexBufferType = .key

View File

@@ -32,32 +32,18 @@ struct _InternalByteBuffer {
final class Storage { final class Storage {
/// pointer to the start of the buffer object in memory /// pointer to the start of the buffer object in memory
var memory: UnsafeMutableRawPointer var memory: UnsafeMutableRawPointer
/// Capacity of UInt8 the buffer can hold
var capacity: Int
@usableFromInline @usableFromInline
init(count: Int, alignment: Int) { init(count: Int, alignment: Int) {
memory = UnsafeMutableRawPointer.allocate( memory = UnsafeMutableRawPointer.allocate(
byteCount: count, byteCount: count,
alignment: alignment) alignment: alignment)
capacity = count
}
@usableFromInline
init(memory: UnsafeMutableRawPointer, capacity: Int, unowned: Bool) {
self.memory = memory
self.capacity = capacity
} }
deinit { deinit {
memory.deallocate() memory.deallocate()
} }
@usableFromInline
func copy(from ptr: UnsafeRawPointer, count: Int) {
memory.copyMemory(from: ptr, byteCount: count)
}
@usableFromInline @usableFromInline
func initialize(for size: Int) { func initialize(for size: Int) {
memset(memory, 0, size) memset(memory, 0, size)
@@ -66,14 +52,11 @@ struct _InternalByteBuffer {
/// Reallocates the buffer incase the object to be written doesnt fit in the current buffer /// Reallocates the buffer incase the object to be written doesnt fit in the current buffer
/// - Parameter size: Size of the current object /// - Parameter size: Size of the current object
@usableFromInline @usableFromInline
func reallocate(_ size: Int, writerSize: Int, alignment: Int) { func reallocate(
while capacity <= writerSize &+ size { capacity: Int,
capacity = capacity << 1 writerSize: Int,
} alignment: Int
) {
/// solution take from Apple-NIO
capacity = capacity.convertToPowerofTwo
let newData = UnsafeMutableRawPointer.allocate( let newData = UnsafeMutableRawPointer.allocate(
byteCount: capacity, byteCount: capacity,
alignment: alignment) alignment: alignment)
@@ -97,7 +80,7 @@ struct _InternalByteBuffer {
/// Public Pointer to the buffer object in memory. This should NOT be modified for any reason /// Public Pointer to the buffer object in memory. This should NOT be modified for any reason
public var memory: UnsafeMutableRawPointer { _storage.memory } public var memory: UnsafeMutableRawPointer { _storage.memory }
/// Current capacity for the buffer /// Current capacity for the buffer
public var capacity: Int { _storage.capacity } public private(set) var capacity: Int
/// Returns the written bytes into the ``ByteBuffer`` /// Returns the written bytes into the ``ByteBuffer``
public var underlyingBytes: [UInt8] { public var underlyingBytes: [UInt8] {
@@ -113,6 +96,7 @@ struct _InternalByteBuffer {
/// - allowReadingUnalignedBuffers: allow reading from unaligned buffer /// - allowReadingUnalignedBuffers: allow reading from unaligned buffer
init(initialSize size: Int) { init(initialSize size: Int) {
initialSize = size.convertToPowerofTwo initialSize = size.convertToPowerofTwo
capacity = initialSize
_storage = Storage(count: initialSize, alignment: alignment) _storage = Storage(count: initialSize, alignment: alignment)
_storage.initialize(for: initialSize) _storage.initialize(for: initialSize)
} }
@@ -123,8 +107,9 @@ struct _InternalByteBuffer {
writerIndex = 0 writerIndex = 0
alignment = 1 alignment = 1
if keepingCapacity { if keepingCapacity {
_storage.initialize(for: _storage.capacity) _storage.initialize(for: capacity)
} else { } else {
capacity = initialSize
_storage = Storage(count: initialSize, alignment: alignment) _storage = Storage(count: initialSize, alignment: alignment)
} }
} }
@@ -136,10 +121,22 @@ struct _InternalByteBuffer {
/// Makes sure that buffer has enouch space for each of the objects that will be written into it /// Makes sure that buffer has enouch space for each of the objects that will be written into it
/// - Parameter size: size of object /// - Parameter size: size of object
@inline(__always) @usableFromInline
mutating func ensureSpace(size: Int) { mutating func ensureSpace(size: Int) {
guard size &+ writerIndex > _storage.capacity else { return } guard size &+ writerIndex > capacity else { return }
_storage.reallocate(size, writerSize: writerIndex, alignment: alignment)
while capacity <= writerIndex &+ size {
capacity = capacity << 1
}
/// solution take from Apple-NIO
capacity = capacity.convertToPowerofTwo
_storage.reallocate(
capacity: capacity,
writerSize: writerIndex,
alignment: alignment
)
} }
@inline(__always) @inline(__always)
@@ -215,7 +212,7 @@ extension _InternalByteBuffer: CustomDebugStringConvertible {
public var debugDescription: String { public var debugDescription: String {
""" """
buffer located at: \(_storage.memory), with capacity of \(_storage.capacity) buffer located at: \(_storage.memory), with capacity of \(capacity)
{ writerIndex: \(writerIndex) } { writerIndex: \(writerIndex) }
""" """
} }

View File

@@ -42,7 +42,7 @@ final class ByteBufferTests: XCTestCase {
let byteBuffer = ByteBuffer(data: ptr) let byteBuffer = ByteBuffer(data: ptr)
byteBuffer.withUnsafeBytes { memory in byteBuffer.withUnsafeBytes { memory in
ptr.withUnsafeBytes { ptr in ptr.withUnsafeBytes { ptr in
XCTAssertEqual(memory.baseAddress!, ptr) XCTAssertEqual(memory.baseAddress!, ptr.baseAddress!)
} }
} }
} }

View File

@@ -19,13 +19,7 @@ import XCTest
final class FlatbuffersVerifierTests: XCTestCase { final class FlatbuffersVerifierTests: XCTestCase {
lazy var validStorage: ByteBuffer.Storage = ByteBuffer.Storage(
count: Int(FlatBufferMaxSize) - 1)
lazy var errorStorage: ByteBuffer.Storage = ByteBuffer.Storage(
count: Int(FlatBufferMaxSize) + 1)
var buffer: ByteBuffer! var buffer: ByteBuffer!
var validFlatbuffersObject: ByteBuffer! var validFlatbuffersObject: ByteBuffer!
var invalidFlatbuffersObject: ByteBuffer! var invalidFlatbuffersObject: ByteBuffer!
var invalidFlatbuffersObject2: ByteBuffer! var invalidFlatbuffersObject2: ByteBuffer!
@@ -52,15 +46,13 @@ final class FlatbuffersVerifierTests: XCTestCase {
func testVeriferInitPassing() { func testVeriferInitPassing() {
let memory = UnsafeMutableRawPointer.allocate(byteCount: 8, alignment: 1) let memory = UnsafeMutableRawPointer.allocate(byteCount: 8, alignment: 1)
var buffer = ByteBuffer(assumingMemoryBound: memory, capacity: 8) var buffer = ByteBuffer(assumingMemoryBound: memory, capacity: Int(FlatBufferMaxSize) - 1)
buffer._storage = validStorage
XCTAssertNoThrow(try Verifier(buffer: &buffer)) XCTAssertNoThrow(try Verifier(buffer: &buffer))
} }
func testVeriferInitFailing() { func testVeriferInitFailing() {
let memory = UnsafeMutableRawPointer.allocate(byteCount: 8, alignment: 1) let memory = UnsafeMutableRawPointer.allocate(byteCount: 8, alignment: 1)
var buffer = ByteBuffer(assumingMemoryBound: memory, capacity: 8) var buffer = ByteBuffer(assumingMemoryBound: memory, capacity: Int(FlatBufferMaxSize) + 1)
buffer._storage = errorStorage
XCTAssertThrowsError(try Verifier(buffer: &buffer)) XCTAssertThrowsError(try Verifier(buffer: &buffer))
} }