1*890232f2SAndroid Build Coastguard Worker /* 2*890232f2SAndroid Build Coastguard Worker * Copyright 2021 Google Inc. All rights reserved. 3*890232f2SAndroid Build Coastguard Worker * 4*890232f2SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*890232f2SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*890232f2SAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*890232f2SAndroid Build Coastguard Worker * 8*890232f2SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*890232f2SAndroid Build Coastguard Worker * 10*890232f2SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*890232f2SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*890232f2SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*890232f2SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*890232f2SAndroid Build Coastguard Worker * limitations under the License. 15*890232f2SAndroid Build Coastguard Worker */ 16*890232f2SAndroid Build Coastguard Worker 17*890232f2SAndroid Build Coastguard Worker #if !os(WASI) 18*890232f2SAndroid Build Coastguard Worker import Foundation 19*890232f2SAndroid Build Coastguard Worker #else 20*890232f2SAndroid Build Coastguard Worker import SwiftOverlayShims 21*890232f2SAndroid Build Coastguard Worker #endif 22*890232f2SAndroid Build Coastguard Worker 23*890232f2SAndroid Build Coastguard Worker /// `ByteBuffer` is the interface that stores the data for a `Flatbuffers` object 24*890232f2SAndroid Build Coastguard Worker /// it allows users to write and read data directly from memory thus the use of its 25*890232f2SAndroid Build Coastguard Worker /// functions should be used 26*890232f2SAndroid Build Coastguard Worker @frozen 27*890232f2SAndroid Build Coastguard Worker public struct ByteBuffer { 28*890232f2SAndroid Build Coastguard Worker 29*890232f2SAndroid Build Coastguard Worker /// Storage is a container that would hold the memory pointer to solve the issue of 30*890232f2SAndroid Build Coastguard Worker /// deallocating the memory that was held by (memory: UnsafeMutableRawPointer) 31*890232f2SAndroid Build Coastguard Worker @usableFromInline 32*890232f2SAndroid Build Coastguard Worker final class Storage { 33*890232f2SAndroid Build Coastguard Worker // This storage doesn't own the memory, therefore, we won't deallocate on deinit. 34*890232f2SAndroid Build Coastguard Worker private let unowned: Bool 35*890232f2SAndroid Build Coastguard Worker /// pointer to the start of the buffer object in memory 36*890232f2SAndroid Build Coastguard Worker var memory: UnsafeMutableRawPointer 37*890232f2SAndroid Build Coastguard Worker /// Capacity of UInt8 the buffer can hold 38*890232f2SAndroid Build Coastguard Worker var capacity: Int 39*890232f2SAndroid Build Coastguard Worker 40*890232f2SAndroid Build Coastguard Worker @usableFromInline 41*890232f2SAndroid Build Coastguard Worker init(count: Int, alignment: Int) { 42*890232f2SAndroid Build Coastguard Worker memory = UnsafeMutableRawPointer.allocate( 43*890232f2SAndroid Build Coastguard Worker byteCount: count, 44*890232f2SAndroid Build Coastguard Worker alignment: alignment) 45*890232f2SAndroid Build Coastguard Worker capacity = count 46*890232f2SAndroid Build Coastguard Worker unowned = false 47*890232f2SAndroid Build Coastguard Worker } 48*890232f2SAndroid Build Coastguard Worker 49*890232f2SAndroid Build Coastguard Worker @usableFromInline 50*890232f2SAndroid Build Coastguard Worker init(memory: UnsafeMutableRawPointer, capacity: Int, unowned: Bool) { 51*890232f2SAndroid Build Coastguard Worker self.memory = memory 52*890232f2SAndroid Build Coastguard Worker self.capacity = capacity 53*890232f2SAndroid Build Coastguard Worker self.unowned = unowned 54*890232f2SAndroid Build Coastguard Worker } 55*890232f2SAndroid Build Coastguard Worker 56*890232f2SAndroid Build Coastguard Worker deinit { 57*890232f2SAndroid Build Coastguard Worker if !unowned { 58*890232f2SAndroid Build Coastguard Worker memory.deallocate() 59*890232f2SAndroid Build Coastguard Worker } 60*890232f2SAndroid Build Coastguard Worker } 61*890232f2SAndroid Build Coastguard Worker 62*890232f2SAndroid Build Coastguard Worker @usableFromInline copynull63*890232f2SAndroid Build Coastguard Worker func copy(from ptr: UnsafeRawPointer, count: Int) { 64*890232f2SAndroid Build Coastguard Worker assert( 65*890232f2SAndroid Build Coastguard Worker !unowned, 66*890232f2SAndroid Build Coastguard Worker "copy should NOT be called on a buffer that is built by assumingMemoryBound") 67*890232f2SAndroid Build Coastguard Worker memory.copyMemory(from: ptr, byteCount: count) 68*890232f2SAndroid Build Coastguard Worker } 69*890232f2SAndroid Build Coastguard Worker 70*890232f2SAndroid Build Coastguard Worker @usableFromInline initializenull71*890232f2SAndroid Build Coastguard Worker func initialize(for size: Int) { 72*890232f2SAndroid Build Coastguard Worker assert( 73*890232f2SAndroid Build Coastguard Worker !unowned, 74*890232f2SAndroid Build Coastguard Worker "initalize should NOT be called on a buffer that is built by assumingMemoryBound") 75*890232f2SAndroid Build Coastguard Worker memset(memory, 0, size) 76*890232f2SAndroid Build Coastguard Worker } 77*890232f2SAndroid Build Coastguard Worker 78*890232f2SAndroid Build Coastguard Worker /// Reallocates the buffer incase the object to be written doesnt fit in the current buffer 79*890232f2SAndroid Build Coastguard Worker /// - Parameter size: Size of the current object 80*890232f2SAndroid Build Coastguard Worker @usableFromInline reallocatenull81*890232f2SAndroid Build Coastguard Worker func reallocate(_ size: Int, writerSize: Int, alignment: Int) { 82*890232f2SAndroid Build Coastguard Worker let currentWritingIndex = capacity &- writerSize 83*890232f2SAndroid Build Coastguard Worker while capacity <= writerSize &+ size { 84*890232f2SAndroid Build Coastguard Worker capacity = capacity << 1 85*890232f2SAndroid Build Coastguard Worker } 86*890232f2SAndroid Build Coastguard Worker 87*890232f2SAndroid Build Coastguard Worker /// solution take from Apple-NIO 88*890232f2SAndroid Build Coastguard Worker capacity = capacity.convertToPowerofTwo 89*890232f2SAndroid Build Coastguard Worker 90*890232f2SAndroid Build Coastguard Worker let newData = UnsafeMutableRawPointer.allocate( 91*890232f2SAndroid Build Coastguard Worker byteCount: capacity, 92*890232f2SAndroid Build Coastguard Worker alignment: alignment) 93*890232f2SAndroid Build Coastguard Worker memset(newData, 0, capacity &- writerSize) 94*890232f2SAndroid Build Coastguard Worker memcpy( 95*890232f2SAndroid Build Coastguard Worker newData.advanced(by: capacity &- writerSize), 96*890232f2SAndroid Build Coastguard Worker memory.advanced(by: currentWritingIndex), 97*890232f2SAndroid Build Coastguard Worker writerSize) 98*890232f2SAndroid Build Coastguard Worker memory.deallocate() 99*890232f2SAndroid Build Coastguard Worker memory = newData 100*890232f2SAndroid Build Coastguard Worker } 101*890232f2SAndroid Build Coastguard Worker } 102*890232f2SAndroid Build Coastguard Worker 103*890232f2SAndroid Build Coastguard Worker @usableFromInline var _storage: Storage 104*890232f2SAndroid Build Coastguard Worker 105*890232f2SAndroid Build Coastguard Worker /// The size of the elements written to the buffer + their paddings 106*890232f2SAndroid Build Coastguard Worker private var _writerSize: Int = 0 107*890232f2SAndroid Build Coastguard Worker /// Aliginment of the current memory being written to the buffer 108*890232f2SAndroid Build Coastguard Worker var alignment = 1 109*890232f2SAndroid Build Coastguard Worker /// Current Index which is being used to write to the buffer, it is written from the end to the start of the buffer 110*890232f2SAndroid Build Coastguard Worker var writerIndex: Int { _storage.capacity &- _writerSize } 111*890232f2SAndroid Build Coastguard Worker 112*890232f2SAndroid Build Coastguard Worker /// Reader is the position of the current Writer Index (capacity - size) 113*890232f2SAndroid Build Coastguard Worker public var reader: Int { writerIndex } 114*890232f2SAndroid Build Coastguard Worker /// Current size of the buffer 115*890232f2SAndroid Build Coastguard Worker public var size: UOffset { UOffset(_writerSize) } 116*890232f2SAndroid Build Coastguard Worker /// Public Pointer to the buffer object in memory. This should NOT be modified for any reason 117*890232f2SAndroid Build Coastguard Worker public var memory: UnsafeMutableRawPointer { _storage.memory } 118*890232f2SAndroid Build Coastguard Worker /// Current capacity for the buffer 119*890232f2SAndroid Build Coastguard Worker public var capacity: Int { _storage.capacity } 120*890232f2SAndroid Build Coastguard Worker 121*890232f2SAndroid Build Coastguard Worker /// Constructor that creates a Flatbuffer object from a UInt8 122*890232f2SAndroid Build Coastguard Worker /// - Parameter bytes: Array of UInt8 123*890232f2SAndroid Build Coastguard Worker public init(bytes: [UInt8]) { 124*890232f2SAndroid Build Coastguard Worker var b = bytes 125*890232f2SAndroid Build Coastguard Worker _storage = Storage(count: bytes.count, alignment: alignment) 126*890232f2SAndroid Build Coastguard Worker _writerSize = _storage.capacity 127*890232f2SAndroid Build Coastguard Worker b.withUnsafeMutableBytes { bufferPointer in 128*890232f2SAndroid Build Coastguard Worker self._storage.copy(from: bufferPointer.baseAddress!, count: bytes.count) 129*890232f2SAndroid Build Coastguard Worker } 130*890232f2SAndroid Build Coastguard Worker } 131*890232f2SAndroid Build Coastguard Worker 132*890232f2SAndroid Build Coastguard Worker #if !os(WASI) 133*890232f2SAndroid Build Coastguard Worker /// Constructor that creates a Flatbuffer from the Swift Data type object 134*890232f2SAndroid Build Coastguard Worker /// - Parameter data: Swift data Object 135*890232f2SAndroid Build Coastguard Worker public init(data: Data) { 136*890232f2SAndroid Build Coastguard Worker var b = data 137*890232f2SAndroid Build Coastguard Worker _storage = Storage(count: data.count, alignment: alignment) 138*890232f2SAndroid Build Coastguard Worker _writerSize = _storage.capacity 139*890232f2SAndroid Build Coastguard Worker b.withUnsafeMutableBytes { bufferPointer in 140*890232f2SAndroid Build Coastguard Worker self._storage.copy(from: bufferPointer.baseAddress!, count: data.count) 141*890232f2SAndroid Build Coastguard Worker } 142*890232f2SAndroid Build Coastguard Worker } 143*890232f2SAndroid Build Coastguard Worker #endif 144*890232f2SAndroid Build Coastguard Worker 145*890232f2SAndroid Build Coastguard Worker /// Constructor that creates a Flatbuffer instance with a size 146*890232f2SAndroid Build Coastguard Worker /// - Parameter size: Length of the buffer 147*890232f2SAndroid Build Coastguard Worker init(initialSize size: Int) { 148*890232f2SAndroid Build Coastguard Worker let size = size.convertToPowerofTwo 149*890232f2SAndroid Build Coastguard Worker _storage = Storage(count: size, alignment: alignment) 150*890232f2SAndroid Build Coastguard Worker _storage.initialize(for: size) 151*890232f2SAndroid Build Coastguard Worker } 152*890232f2SAndroid Build Coastguard Worker 153*890232f2SAndroid Build Coastguard Worker #if swift(>=5.0) && !os(WASI) 154*890232f2SAndroid Build Coastguard Worker /// Constructor that creates a Flatbuffer object from a ContiguousBytes 155*890232f2SAndroid Build Coastguard Worker /// - Parameters: 156*890232f2SAndroid Build Coastguard Worker /// - contiguousBytes: Binary stripe to use as the buffer 157*890232f2SAndroid Build Coastguard Worker /// - count: amount of readable bytes 158*890232f2SAndroid Build Coastguard Worker public init<Bytes: ContiguousBytes>( 159*890232f2SAndroid Build Coastguard Worker contiguousBytes: Bytes, 160*890232f2SAndroid Build Coastguard Worker count: Int) 161*890232f2SAndroid Build Coastguard Worker { 162*890232f2SAndroid Build Coastguard Worker _storage = Storage(count: count, alignment: alignment) 163*890232f2SAndroid Build Coastguard Worker _writerSize = _storage.capacity 164*890232f2SAndroid Build Coastguard Worker contiguousBytes.withUnsafeBytes { buf in 165*890232f2SAndroid Build Coastguard Worker _storage.copy(from: buf.baseAddress!, count: buf.count) 166*890232f2SAndroid Build Coastguard Worker } 167*890232f2SAndroid Build Coastguard Worker } 168*890232f2SAndroid Build Coastguard Worker #endif 169*890232f2SAndroid Build Coastguard Worker 170*890232f2SAndroid Build Coastguard Worker /// Constructor that creates a Flatbuffer from unsafe memory region without copying 171*890232f2SAndroid Build Coastguard Worker /// - Parameter assumingMemoryBound: The unsafe memory region 172*890232f2SAndroid Build Coastguard Worker /// - Parameter capacity: The size of the given memory region 173*890232f2SAndroid Build Coastguard Worker public init( 174*890232f2SAndroid Build Coastguard Worker assumingMemoryBound memory: UnsafeMutableRawPointer, 175*890232f2SAndroid Build Coastguard Worker capacity: Int) 176*890232f2SAndroid Build Coastguard Worker { 177*890232f2SAndroid Build Coastguard Worker _storage = Storage(memory: memory, capacity: capacity, unowned: true) 178*890232f2SAndroid Build Coastguard Worker _writerSize = capacity 179*890232f2SAndroid Build Coastguard Worker } 180*890232f2SAndroid Build Coastguard Worker 181*890232f2SAndroid Build Coastguard Worker /// Creates a copy of the buffer that's being built by calling sizedBuffer 182*890232f2SAndroid Build Coastguard Worker /// - Parameters: 183*890232f2SAndroid Build Coastguard Worker /// - memory: Current memory of the buffer 184*890232f2SAndroid Build Coastguard Worker /// - count: count of bytes 185*890232f2SAndroid Build Coastguard Worker init(memory: UnsafeMutableRawPointer, count: Int) { 186*890232f2SAndroid Build Coastguard Worker _storage = Storage(count: count, alignment: alignment) 187*890232f2SAndroid Build Coastguard Worker _storage.copy(from: memory, count: count) 188*890232f2SAndroid Build Coastguard Worker _writerSize = _storage.capacity 189*890232f2SAndroid Build Coastguard Worker } 190*890232f2SAndroid Build Coastguard Worker 191*890232f2SAndroid Build Coastguard Worker /// Creates a copy of the existing flatbuffer, by copying it to a different memory. 192*890232f2SAndroid Build Coastguard Worker /// - Parameters: 193*890232f2SAndroid Build Coastguard Worker /// - memory: Current memory of the buffer 194*890232f2SAndroid Build Coastguard Worker /// - count: count of bytes 195*890232f2SAndroid Build Coastguard Worker /// - removeBytes: Removes a number of bytes from the current size 196*890232f2SAndroid Build Coastguard Worker init( 197*890232f2SAndroid Build Coastguard Worker memory: UnsafeMutableRawPointer, 198*890232f2SAndroid Build Coastguard Worker count: Int, 199*890232f2SAndroid Build Coastguard Worker removing removeBytes: Int) 200*890232f2SAndroid Build Coastguard Worker { 201*890232f2SAndroid Build Coastguard Worker _storage = Storage(count: count, alignment: alignment) 202*890232f2SAndroid Build Coastguard Worker _storage.copy(from: memory, count: count) 203*890232f2SAndroid Build Coastguard Worker _writerSize = removeBytes 204*890232f2SAndroid Build Coastguard Worker } 205*890232f2SAndroid Build Coastguard Worker 206*890232f2SAndroid Build Coastguard Worker /// Fills the buffer with padding by adding to the writersize 207*890232f2SAndroid Build Coastguard Worker /// - Parameter padding: Amount of padding between two to be serialized objects 208*890232f2SAndroid Build Coastguard Worker @inline(__always) 209*890232f2SAndroid Build Coastguard Worker @usableFromInline fillnull210*890232f2SAndroid Build Coastguard Worker mutating func fill(padding: Int) { 211*890232f2SAndroid Build Coastguard Worker assert(padding >= 0, "Fill should be larger than or equal to zero") 212*890232f2SAndroid Build Coastguard Worker ensureSpace(size: padding) 213*890232f2SAndroid Build Coastguard Worker _writerSize = _writerSize &+ (MemoryLayout<UInt8>.size &* padding) 214*890232f2SAndroid Build Coastguard Worker } 215*890232f2SAndroid Build Coastguard Worker 216*890232f2SAndroid Build Coastguard Worker /// Adds an array of type Scalar to the buffer memory 217*890232f2SAndroid Build Coastguard Worker /// - Parameter elements: An array of Scalars 218*890232f2SAndroid Build Coastguard Worker @inline(__always) 219*890232f2SAndroid Build Coastguard Worker @usableFromInline push<T: Scalar>null220*890232f2SAndroid Build Coastguard Worker mutating func push<T: Scalar>(elements: [T]) { 221*890232f2SAndroid Build Coastguard Worker let size = elements.count &* MemoryLayout<T>.size 222*890232f2SAndroid Build Coastguard Worker ensureSpace(size: size) 223*890232f2SAndroid Build Coastguard Worker elements.reversed().forEach { s in 224*890232f2SAndroid Build Coastguard Worker push(value: s, len: MemoryLayout.size(ofValue: s)) 225*890232f2SAndroid Build Coastguard Worker } 226*890232f2SAndroid Build Coastguard Worker } 227*890232f2SAndroid Build Coastguard Worker 228*890232f2SAndroid Build Coastguard Worker /// Adds an object of type NativeStruct into the buffer 229*890232f2SAndroid Build Coastguard Worker /// - Parameters: 230*890232f2SAndroid Build Coastguard Worker /// - value: Object that will be written to the buffer 231*890232f2SAndroid Build Coastguard Worker /// - size: size to subtract from the WriterIndex 232*890232f2SAndroid Build Coastguard Worker @usableFromInline 233*890232f2SAndroid Build Coastguard Worker @inline(__always) push<T: NativeStruct>null234*890232f2SAndroid Build Coastguard Worker mutating func push<T: NativeStruct>(struct value: T, size: Int) { 235*890232f2SAndroid Build Coastguard Worker ensureSpace(size: size) 236*890232f2SAndroid Build Coastguard Worker var v = value 237*890232f2SAndroid Build Coastguard Worker memcpy(_storage.memory.advanced(by: writerIndex &- size), &v, size) 238*890232f2SAndroid Build Coastguard Worker _writerSize = _writerSize &+ size 239*890232f2SAndroid Build Coastguard Worker } 240*890232f2SAndroid Build Coastguard Worker 241*890232f2SAndroid Build Coastguard Worker /// Adds an object of type Scalar into the buffer 242*890232f2SAndroid Build Coastguard Worker /// - Parameters: 243*890232f2SAndroid Build Coastguard Worker /// - value: Object that will be written to the buffer 244*890232f2SAndroid Build Coastguard Worker /// - len: Offset to subtract from the WriterIndex 245*890232f2SAndroid Build Coastguard Worker @inline(__always) 246*890232f2SAndroid Build Coastguard Worker @usableFromInline push<T: Scalar>null247*890232f2SAndroid Build Coastguard Worker mutating func push<T: Scalar>(value: T, len: Int) { 248*890232f2SAndroid Build Coastguard Worker ensureSpace(size: len) 249*890232f2SAndroid Build Coastguard Worker var v = value 250*890232f2SAndroid Build Coastguard Worker memcpy(_storage.memory.advanced(by: writerIndex &- len), &v, len) 251*890232f2SAndroid Build Coastguard Worker _writerSize = _writerSize &+ len 252*890232f2SAndroid Build Coastguard Worker } 253*890232f2SAndroid Build Coastguard Worker 254*890232f2SAndroid Build Coastguard Worker /// Adds a string to the buffer using swift.utf8 object 255*890232f2SAndroid Build Coastguard Worker /// - Parameter str: String that will be added to the buffer 256*890232f2SAndroid Build Coastguard Worker /// - Parameter len: length of the string 257*890232f2SAndroid Build Coastguard Worker @inline(__always) 258*890232f2SAndroid Build Coastguard Worker @usableFromInline pushnull259*890232f2SAndroid Build Coastguard Worker mutating func push(string str: String, len: Int) { 260*890232f2SAndroid Build Coastguard Worker ensureSpace(size: len) 261*890232f2SAndroid Build Coastguard Worker if str.utf8 262*890232f2SAndroid Build Coastguard Worker .withContiguousStorageIfAvailable({ self.push(bytes: $0, len: len) }) != 263*890232f2SAndroid Build Coastguard Worker nil 264*890232f2SAndroid Build Coastguard Worker { 265*890232f2SAndroid Build Coastguard Worker } else { 266*890232f2SAndroid Build Coastguard Worker let utf8View = str.utf8 267*890232f2SAndroid Build Coastguard Worker for c in utf8View.reversed() { 268*890232f2SAndroid Build Coastguard Worker push(value: c, len: 1) 269*890232f2SAndroid Build Coastguard Worker } 270*890232f2SAndroid Build Coastguard Worker } 271*890232f2SAndroid Build Coastguard Worker } 272*890232f2SAndroid Build Coastguard Worker 273*890232f2SAndroid Build Coastguard Worker /// Writes a string to Bytebuffer using UTF8View 274*890232f2SAndroid Build Coastguard Worker /// - Parameters: 275*890232f2SAndroid Build Coastguard Worker /// - bytes: Pointer to the view 276*890232f2SAndroid Build Coastguard Worker /// - len: Size of string 277*890232f2SAndroid Build Coastguard Worker @usableFromInline 278*890232f2SAndroid Build Coastguard Worker @inline(__always) 279*890232f2SAndroid Build Coastguard Worker mutating func push( 280*890232f2SAndroid Build Coastguard Worker bytes: UnsafeBufferPointer<String.UTF8View.Element>, 281*890232f2SAndroid Build Coastguard Worker len: Int) -> Bool 282*890232f2SAndroid Build Coastguard Worker { 283*890232f2SAndroid Build Coastguard Worker memcpy( 284*890232f2SAndroid Build Coastguard Worker _storage.memory.advanced(by: writerIndex &- len), 285*890232f2SAndroid Build Coastguard Worker UnsafeRawPointer(bytes.baseAddress!), 286*890232f2SAndroid Build Coastguard Worker len) 287*890232f2SAndroid Build Coastguard Worker _writerSize = _writerSize &+ len 288*890232f2SAndroid Build Coastguard Worker return true 289*890232f2SAndroid Build Coastguard Worker } 290*890232f2SAndroid Build Coastguard Worker 291*890232f2SAndroid Build Coastguard Worker /// Write stores an object into the buffer directly or indirectly. 292*890232f2SAndroid Build Coastguard Worker /// 293*890232f2SAndroid Build Coastguard Worker /// Direct: ignores the capacity of buffer which would mean we are referring to the direct point in memory 294*890232f2SAndroid Build Coastguard Worker /// indirect: takes into respect the current capacity of the buffer (capacity - index), writing to the buffer from the end 295*890232f2SAndroid Build Coastguard Worker /// - Parameters: 296*890232f2SAndroid Build Coastguard Worker /// - value: Value that needs to be written to the buffer 297*890232f2SAndroid Build Coastguard Worker /// - index: index to write to 298*890232f2SAndroid Build Coastguard Worker /// - direct: Should take into consideration the capacity of the buffer 299*890232f2SAndroid Build Coastguard Worker @inline(__always) write<T>null300*890232f2SAndroid Build Coastguard Worker func write<T>(value: T, index: Int, direct: Bool = false) { 301*890232f2SAndroid Build Coastguard Worker var index = index 302*890232f2SAndroid Build Coastguard Worker if !direct { 303*890232f2SAndroid Build Coastguard Worker index = _storage.capacity &- index 304*890232f2SAndroid Build Coastguard Worker } 305*890232f2SAndroid Build Coastguard Worker assert(index < _storage.capacity, "Write index is out of writing bound") 306*890232f2SAndroid Build Coastguard Worker assert(index >= 0, "Writer index should be above zero") 307*890232f2SAndroid Build Coastguard Worker _storage.memory.storeBytes(of: value, toByteOffset: index, as: T.self) 308*890232f2SAndroid Build Coastguard Worker } 309*890232f2SAndroid Build Coastguard Worker 310*890232f2SAndroid Build Coastguard Worker /// Makes sure that buffer has enouch space for each of the objects that will be written into it 311*890232f2SAndroid Build Coastguard Worker /// - Parameter size: size of object 312*890232f2SAndroid Build Coastguard Worker @discardableResult 313*890232f2SAndroid Build Coastguard Worker @usableFromInline 314*890232f2SAndroid Build Coastguard Worker @inline(__always) ensureSpacenull315*890232f2SAndroid Build Coastguard Worker mutating func ensureSpace(size: Int) -> Int { 316*890232f2SAndroid Build Coastguard Worker if size &+ _writerSize > _storage.capacity { 317*890232f2SAndroid Build Coastguard Worker _storage.reallocate(size, writerSize: _writerSize, alignment: alignment) 318*890232f2SAndroid Build Coastguard Worker } 319*890232f2SAndroid Build Coastguard Worker assert(size < FlatBufferMaxSize, "Buffer can't grow beyond 2 Gigabytes") 320*890232f2SAndroid Build Coastguard Worker return size 321*890232f2SAndroid Build Coastguard Worker } 322*890232f2SAndroid Build Coastguard Worker 323*890232f2SAndroid Build Coastguard Worker /// pops the written VTable if it's already written into the buffer 324*890232f2SAndroid Build Coastguard Worker /// - Parameter size: size of the `VTable` 325*890232f2SAndroid Build Coastguard Worker @usableFromInline 326*890232f2SAndroid Build Coastguard Worker @inline(__always) popnull327*890232f2SAndroid Build Coastguard Worker mutating func pop(_ size: Int) { 328*890232f2SAndroid Build Coastguard Worker assert( 329*890232f2SAndroid Build Coastguard Worker (_writerSize &- size) > 0, 330*890232f2SAndroid Build Coastguard Worker "New size should NOT be a negative number") 331*890232f2SAndroid Build Coastguard Worker memset(_storage.memory.advanced(by: writerIndex), 0, _writerSize &- size) 332*890232f2SAndroid Build Coastguard Worker _writerSize = size 333*890232f2SAndroid Build Coastguard Worker } 334*890232f2SAndroid Build Coastguard Worker 335*890232f2SAndroid Build Coastguard Worker /// Clears the current size of the buffer 336*890232f2SAndroid Build Coastguard Worker @inline(__always) clearSizenull337*890232f2SAndroid Build Coastguard Worker mutating public func clearSize() { 338*890232f2SAndroid Build Coastguard Worker _writerSize = 0 339*890232f2SAndroid Build Coastguard Worker } 340*890232f2SAndroid Build Coastguard Worker 341*890232f2SAndroid Build Coastguard Worker /// Clears the current instance of the buffer, replacing it with new memory 342*890232f2SAndroid Build Coastguard Worker @inline(__always) clearnull343*890232f2SAndroid Build Coastguard Worker mutating public func clear() { 344*890232f2SAndroid Build Coastguard Worker _writerSize = 0 345*890232f2SAndroid Build Coastguard Worker alignment = 1 346*890232f2SAndroid Build Coastguard Worker _storage.initialize(for: _storage.capacity) 347*890232f2SAndroid Build Coastguard Worker } 348*890232f2SAndroid Build Coastguard Worker 349*890232f2SAndroid Build Coastguard Worker /// Reads an object from the buffer 350*890232f2SAndroid Build Coastguard Worker /// - Parameters: 351*890232f2SAndroid Build Coastguard Worker /// - def: Type of the object 352*890232f2SAndroid Build Coastguard Worker /// - position: the index of the object in the buffer 353*890232f2SAndroid Build Coastguard Worker @inline(__always) read<T>null354*890232f2SAndroid Build Coastguard Worker public func read<T>(def: T.Type, position: Int) -> T { 355*890232f2SAndroid Build Coastguard Worker _storage.memory.advanced(by: position).load(as: T.self) 356*890232f2SAndroid Build Coastguard Worker } 357*890232f2SAndroid Build Coastguard Worker 358*890232f2SAndroid Build Coastguard Worker /// Reads a slice from the memory assuming a type of T 359*890232f2SAndroid Build Coastguard Worker /// - Parameters: 360*890232f2SAndroid Build Coastguard Worker /// - index: index of the object to be read from the buffer 361*890232f2SAndroid Build Coastguard Worker /// - count: count of bytes in memory 362*890232f2SAndroid Build Coastguard Worker @inline(__always) 363*890232f2SAndroid Build Coastguard Worker public func readSlice<T>( 364*890232f2SAndroid Build Coastguard Worker index: Int, 365*890232f2SAndroid Build Coastguard Worker count: Int) -> [T] 366*890232f2SAndroid Build Coastguard Worker { 367*890232f2SAndroid Build Coastguard Worker assert( 368*890232f2SAndroid Build Coastguard Worker index + count <= _storage.capacity, 369*890232f2SAndroid Build Coastguard Worker "Reading out of bounds is illegal") 370*890232f2SAndroid Build Coastguard Worker let start = _storage.memory.advanced(by: index) 371*890232f2SAndroid Build Coastguard Worker .assumingMemoryBound(to: T.self) 372*890232f2SAndroid Build Coastguard Worker let array = UnsafeBufferPointer(start: start, count: count) 373*890232f2SAndroid Build Coastguard Worker return Array(array) 374*890232f2SAndroid Build Coastguard Worker } 375*890232f2SAndroid Build Coastguard Worker 376*890232f2SAndroid Build Coastguard Worker #if !os(WASI) 377*890232f2SAndroid Build Coastguard Worker /// Reads a string from the buffer and encodes it to a swift string 378*890232f2SAndroid Build Coastguard Worker /// - Parameters: 379*890232f2SAndroid Build Coastguard Worker /// - index: index of the string in the buffer 380*890232f2SAndroid Build Coastguard Worker /// - count: length of the string 381*890232f2SAndroid Build Coastguard Worker /// - type: Encoding of the string 382*890232f2SAndroid Build Coastguard Worker @inline(__always) 383*890232f2SAndroid Build Coastguard Worker public func readString( 384*890232f2SAndroid Build Coastguard Worker at index: Int, 385*890232f2SAndroid Build Coastguard Worker count: Int, 386*890232f2SAndroid Build Coastguard Worker type: String.Encoding = .utf8) -> String? 387*890232f2SAndroid Build Coastguard Worker { 388*890232f2SAndroid Build Coastguard Worker assert( 389*890232f2SAndroid Build Coastguard Worker index + count <= _storage.capacity, 390*890232f2SAndroid Build Coastguard Worker "Reading out of bounds is illegal") 391*890232f2SAndroid Build Coastguard Worker let start = _storage.memory.advanced(by: index) 392*890232f2SAndroid Build Coastguard Worker .assumingMemoryBound(to: UInt8.self) 393*890232f2SAndroid Build Coastguard Worker let bufprt = UnsafeBufferPointer(start: start, count: count) 394*890232f2SAndroid Build Coastguard Worker return String(bytes: Array(bufprt), encoding: type) 395*890232f2SAndroid Build Coastguard Worker } 396*890232f2SAndroid Build Coastguard Worker #else 397*890232f2SAndroid Build Coastguard Worker /// Reads a string from the buffer and encodes it to a swift string 398*890232f2SAndroid Build Coastguard Worker /// - Parameters: 399*890232f2SAndroid Build Coastguard Worker /// - index: index of the string in the buffer 400*890232f2SAndroid Build Coastguard Worker /// - count: length of the string 401*890232f2SAndroid Build Coastguard Worker /// - type: Encoding of the string 402*890232f2SAndroid Build Coastguard Worker @inline(__always) 403*890232f2SAndroid Build Coastguard Worker public func readString( 404*890232f2SAndroid Build Coastguard Worker at index: Int, 405*890232f2SAndroid Build Coastguard Worker count: Int) -> String? 406*890232f2SAndroid Build Coastguard Worker { 407*890232f2SAndroid Build Coastguard Worker assert( 408*890232f2SAndroid Build Coastguard Worker index + count <= _storage.capacity, 409*890232f2SAndroid Build Coastguard Worker "Reading out of bounds is illegal") 410*890232f2SAndroid Build Coastguard Worker let start = _storage.memory.advanced(by: index) 411*890232f2SAndroid Build Coastguard Worker .assumingMemoryBound(to: UInt8.self) 412*890232f2SAndroid Build Coastguard Worker let bufprt = UnsafeBufferPointer(start: start, count: count) 413*890232f2SAndroid Build Coastguard Worker return String(cString: bufprt.baseAddress!) 414*890232f2SAndroid Build Coastguard Worker } 415*890232f2SAndroid Build Coastguard Worker #endif 416*890232f2SAndroid Build Coastguard Worker 417*890232f2SAndroid Build Coastguard Worker /// Creates a new Flatbuffer object that's duplicated from the current one 418*890232f2SAndroid Build Coastguard Worker /// - Parameter removeBytes: the amount of bytes to remove from the current Size 419*890232f2SAndroid Build Coastguard Worker @inline(__always) duplicatenull420*890232f2SAndroid Build Coastguard Worker public func duplicate(removing removeBytes: Int = 0) -> ByteBuffer { 421*890232f2SAndroid Build Coastguard Worker assert(removeBytes > 0, "Can NOT remove negative bytes") 422*890232f2SAndroid Build Coastguard Worker assert( 423*890232f2SAndroid Build Coastguard Worker removeBytes < _storage.capacity, 424*890232f2SAndroid Build Coastguard Worker "Can NOT remove more bytes than the ones allocated") 425*890232f2SAndroid Build Coastguard Worker return ByteBuffer( 426*890232f2SAndroid Build Coastguard Worker memory: _storage.memory, 427*890232f2SAndroid Build Coastguard Worker count: _storage.capacity, 428*890232f2SAndroid Build Coastguard Worker removing: _writerSize &- removeBytes) 429*890232f2SAndroid Build Coastguard Worker } 430*890232f2SAndroid Build Coastguard Worker 431*890232f2SAndroid Build Coastguard Worker /// Returns the written bytes into the ``ByteBuffer`` 432*890232f2SAndroid Build Coastguard Worker public var underlyingBytes: [UInt8] { 433*890232f2SAndroid Build Coastguard Worker let cp = capacity &- writerIndex 434*890232f2SAndroid Build Coastguard Worker let start = memory.advanced(by: writerIndex) 435*890232f2SAndroid Build Coastguard Worker .bindMemory(to: UInt8.self, capacity: cp) 436*890232f2SAndroid Build Coastguard Worker 437*890232f2SAndroid Build Coastguard Worker let ptr = UnsafeBufferPointer<UInt8>(start: start, count: cp) 438*890232f2SAndroid Build Coastguard Worker return Array(ptr) 439*890232f2SAndroid Build Coastguard Worker } 440*890232f2SAndroid Build Coastguard Worker 441*890232f2SAndroid Build Coastguard Worker /// SkipPrefix Skips the first 4 bytes in case one of the following 442*890232f2SAndroid Build Coastguard Worker /// functions are called `getPrefixedSizeCheckedRoot` & `getPrefixedSizeRoot` 443*890232f2SAndroid Build Coastguard Worker /// which allows us to skip the first 4 bytes instead of recreating the buffer 444*890232f2SAndroid Build Coastguard Worker @discardableResult 445*890232f2SAndroid Build Coastguard Worker @usableFromInline 446*890232f2SAndroid Build Coastguard Worker @inline(__always) skipPrefixnull447*890232f2SAndroid Build Coastguard Worker mutating func skipPrefix() -> Int32 { 448*890232f2SAndroid Build Coastguard Worker _writerSize = _writerSize &- MemoryLayout<Int32>.size 449*890232f2SAndroid Build Coastguard Worker return read(def: Int32.self, position: 0) 450*890232f2SAndroid Build Coastguard Worker } 451*890232f2SAndroid Build Coastguard Worker 452*890232f2SAndroid Build Coastguard Worker } 453*890232f2SAndroid Build Coastguard Worker 454*890232f2SAndroid Build Coastguard Worker extension ByteBuffer: CustomDebugStringConvertible { 455*890232f2SAndroid Build Coastguard Worker 456*890232f2SAndroid Build Coastguard Worker public var debugDescription: String { 457*890232f2SAndroid Build Coastguard Worker """ 458*890232f2SAndroid Build Coastguard Worker buffer located at: \(_storage.memory), with capacity of \(_storage.capacity) 459*890232f2SAndroid Build Coastguard Worker { writerSize: \(_writerSize), readerSize: \(reader), writerIndex: \(writerIndex) } 460*890232f2SAndroid Build Coastguard Worker """ 461*890232f2SAndroid Build Coastguard Worker } 462*890232f2SAndroid Build Coastguard Worker } 463