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 /// `Table` is a Flatbuffers object that can read, 24*890232f2SAndroid Build Coastguard Worker /// mutate scalar fields within a valid flatbuffers buffer 25*890232f2SAndroid Build Coastguard Worker @frozen 26*890232f2SAndroid Build Coastguard Worker public struct Table { 27*890232f2SAndroid Build Coastguard Worker 28*890232f2SAndroid Build Coastguard Worker /// Hosting Bytebuffer 29*890232f2SAndroid Build Coastguard Worker public private(set) var bb: ByteBuffer 30*890232f2SAndroid Build Coastguard Worker /// Current position of the table within the buffer 31*890232f2SAndroid Build Coastguard Worker public private(set) var postion: Int32 32*890232f2SAndroid Build Coastguard Worker 33*890232f2SAndroid Build Coastguard Worker /// Initializer for the table interface to allow generated code to read 34*890232f2SAndroid Build Coastguard Worker /// data from memory 35*890232f2SAndroid Build Coastguard Worker /// - Parameters: 36*890232f2SAndroid Build Coastguard Worker /// - bb: ByteBuffer that stores data 37*890232f2SAndroid Build Coastguard Worker /// - position: Current table position 38*890232f2SAndroid Build Coastguard Worker /// - Note: This will `CRASH` if read on a big endian machine 39*890232f2SAndroid Build Coastguard Worker public init(bb: ByteBuffer, position: Int32 = 0) { 40*890232f2SAndroid Build Coastguard Worker guard isLitteEndian else { 41*890232f2SAndroid Build Coastguard Worker fatalError( 42*890232f2SAndroid Build Coastguard Worker "Reading/Writing a buffer in big endian machine is not supported on swift") 43*890232f2SAndroid Build Coastguard Worker } 44*890232f2SAndroid Build Coastguard Worker self.bb = bb 45*890232f2SAndroid Build Coastguard Worker postion = position 46*890232f2SAndroid Build Coastguard Worker } 47*890232f2SAndroid Build Coastguard Worker 48*890232f2SAndroid Build Coastguard Worker /// Gets the offset of the current field within the buffer by reading 49*890232f2SAndroid Build Coastguard Worker /// the vtable 50*890232f2SAndroid Build Coastguard Worker /// - Parameter o: current offset 51*890232f2SAndroid Build Coastguard Worker /// - Returns: offset of field within buffer offsetnull52*890232f2SAndroid Build Coastguard Worker public func offset(_ o: Int32) -> Int32 { 53*890232f2SAndroid Build Coastguard Worker let vtable = postion - bb.read(def: Int32.self, position: Int(postion)) 54*890232f2SAndroid Build Coastguard Worker return o < bb 55*890232f2SAndroid Build Coastguard Worker .read(def: VOffset.self, position: Int(vtable)) ? Int32(bb.read( 56*890232f2SAndroid Build Coastguard Worker def: Int16.self, 57*890232f2SAndroid Build Coastguard Worker position: Int(vtable + o))) : 0 58*890232f2SAndroid Build Coastguard Worker } 59*890232f2SAndroid Build Coastguard Worker 60*890232f2SAndroid Build Coastguard Worker /// Gets the indirect offset of the current stored object 61*890232f2SAndroid Build Coastguard Worker /// (applicable only for object arrays) 62*890232f2SAndroid Build Coastguard Worker /// - Parameter o: current offset 63*890232f2SAndroid Build Coastguard Worker /// - Returns: offset of field within buffer indirectnull64*890232f2SAndroid Build Coastguard Worker public func indirect(_ o: Int32) -> Int32 { 65*890232f2SAndroid Build Coastguard Worker o + bb.read(def: Int32.self, position: Int(o)) 66*890232f2SAndroid Build Coastguard Worker } 67*890232f2SAndroid Build Coastguard Worker 68*890232f2SAndroid Build Coastguard Worker /// String reads from the buffer with respect to position of the current table. 69*890232f2SAndroid Build Coastguard Worker /// - Parameter offset: Offset of the string stringnull70*890232f2SAndroid Build Coastguard Worker public func string(at offset: Int32) -> String? { 71*890232f2SAndroid Build Coastguard Worker directString(at: offset + postion) 72*890232f2SAndroid Build Coastguard Worker } 73*890232f2SAndroid Build Coastguard Worker 74*890232f2SAndroid Build Coastguard Worker /// Direct string reads from the buffer disregarding the position of the table. 75*890232f2SAndroid Build Coastguard Worker /// It would be preferable to use string unless the current position of the table 76*890232f2SAndroid Build Coastguard Worker /// is not needed 77*890232f2SAndroid Build Coastguard Worker /// - Parameter offset: Offset of the string directStringnull78*890232f2SAndroid Build Coastguard Worker public func directString(at offset: Int32) -> String? { 79*890232f2SAndroid Build Coastguard Worker var offset = offset 80*890232f2SAndroid Build Coastguard Worker offset += bb.read(def: Int32.self, position: Int(offset)) 81*890232f2SAndroid Build Coastguard Worker let count = bb.read(def: Int32.self, position: Int(offset)) 82*890232f2SAndroid Build Coastguard Worker let position = Int(offset) + MemoryLayout<Int32>.size 83*890232f2SAndroid Build Coastguard Worker return bb.readString(at: position, count: Int(count)) 84*890232f2SAndroid Build Coastguard Worker } 85*890232f2SAndroid Build Coastguard Worker 86*890232f2SAndroid Build Coastguard Worker /// Reads from the buffer with respect to the position in the table. 87*890232f2SAndroid Build Coastguard Worker /// - Parameters: 88*890232f2SAndroid Build Coastguard Worker /// - type: Type of Element that needs to be read from the buffer 89*890232f2SAndroid Build Coastguard Worker /// - o: Offset of the Element readBuffer<T>null90*890232f2SAndroid Build Coastguard Worker public func readBuffer<T>(of type: T.Type, at o: Int32) -> T { 91*890232f2SAndroid Build Coastguard Worker directRead(of: T.self, offset: o + postion) 92*890232f2SAndroid Build Coastguard Worker } 93*890232f2SAndroid Build Coastguard Worker 94*890232f2SAndroid Build Coastguard Worker /// Reads from the buffer disregarding the position of the table. 95*890232f2SAndroid Build Coastguard Worker /// It would be used when reading from an 96*890232f2SAndroid Build Coastguard Worker /// ``` 97*890232f2SAndroid Build Coastguard Worker /// let offset = __t.offset(10) 98*890232f2SAndroid Build Coastguard Worker /// //Only used when the we already know what is the 99*890232f2SAndroid Build Coastguard Worker /// // position in the table since __t.vector(at:) 100*890232f2SAndroid Build Coastguard Worker /// // returns the index with respect to the position 101*890232f2SAndroid Build Coastguard Worker /// __t.directRead(of: Byte.self, 102*890232f2SAndroid Build Coastguard Worker /// offset: __t.vector(at: offset) + index * 1) 103*890232f2SAndroid Build Coastguard Worker /// ``` 104*890232f2SAndroid Build Coastguard Worker /// - Parameters: 105*890232f2SAndroid Build Coastguard Worker /// - type: Type of Element that needs to be read from the buffer 106*890232f2SAndroid Build Coastguard Worker /// - o: Offset of the Element directRead<T>null107*890232f2SAndroid Build Coastguard Worker public func directRead<T>(of type: T.Type, offset o: Int32) -> T { 108*890232f2SAndroid Build Coastguard Worker let r = bb.read(def: T.self, position: Int(o)) 109*890232f2SAndroid Build Coastguard Worker return r 110*890232f2SAndroid Build Coastguard Worker } 111*890232f2SAndroid Build Coastguard Worker 112*890232f2SAndroid Build Coastguard Worker /// Returns that current `Union` object at a specific offset 113*890232f2SAndroid Build Coastguard Worker /// by adding offset to the current position of table 114*890232f2SAndroid Build Coastguard Worker /// - Parameter o: offset 115*890232f2SAndroid Build Coastguard Worker /// - Returns: A flatbuffers object union<T: FlatbuffersInitializable>null116*890232f2SAndroid Build Coastguard Worker public func union<T: FlatbuffersInitializable>(_ o: Int32) -> T { 117*890232f2SAndroid Build Coastguard Worker let o = o + postion 118*890232f2SAndroid Build Coastguard Worker return directUnion(o) 119*890232f2SAndroid Build Coastguard Worker } 120*890232f2SAndroid Build Coastguard Worker 121*890232f2SAndroid Build Coastguard Worker /// Returns a direct `Union` object at a specific offset 122*890232f2SAndroid Build Coastguard Worker /// - Parameter o: offset 123*890232f2SAndroid Build Coastguard Worker /// - Returns: A flatbuffers object directUnion<T: FlatbuffersInitializable>null124*890232f2SAndroid Build Coastguard Worker public func directUnion<T: FlatbuffersInitializable>(_ o: Int32) -> T { 125*890232f2SAndroid Build Coastguard Worker T.init(bb, o: o + bb.read(def: Int32.self, position: Int(o))) 126*890232f2SAndroid Build Coastguard Worker } 127*890232f2SAndroid Build Coastguard Worker 128*890232f2SAndroid Build Coastguard Worker /// Returns a vector of type T at a specific offset 129*890232f2SAndroid Build Coastguard Worker /// This should only be used by `Scalars` 130*890232f2SAndroid Build Coastguard Worker /// - Parameter off: Readable offset 131*890232f2SAndroid Build Coastguard Worker /// - Returns: Returns a vector of type [T] getVector<T>null132*890232f2SAndroid Build Coastguard Worker public func getVector<T>(at off: Int32) -> [T]? { 133*890232f2SAndroid Build Coastguard Worker let o = offset(off) 134*890232f2SAndroid Build Coastguard Worker guard o != 0 else { return nil } 135*890232f2SAndroid Build Coastguard Worker return bb.readSlice(index: Int(vector(at: o)), count: Int(vector(count: o))) 136*890232f2SAndroid Build Coastguard Worker } 137*890232f2SAndroid Build Coastguard Worker 138*890232f2SAndroid Build Coastguard Worker /// Vector count gets the count of Elements within the array 139*890232f2SAndroid Build Coastguard Worker /// - Parameter o: start offset of the vector 140*890232f2SAndroid Build Coastguard Worker /// - returns: Count of elements vectornull141*890232f2SAndroid Build Coastguard Worker public func vector(count o: Int32) -> Int32 { 142*890232f2SAndroid Build Coastguard Worker var o = o 143*890232f2SAndroid Build Coastguard Worker o += postion 144*890232f2SAndroid Build Coastguard Worker o += bb.read(def: Int32.self, position: Int(o)) 145*890232f2SAndroid Build Coastguard Worker return bb.read(def: Int32.self, position: Int(o)) 146*890232f2SAndroid Build Coastguard Worker } 147*890232f2SAndroid Build Coastguard Worker 148*890232f2SAndroid Build Coastguard Worker /// Vector start index in the buffer 149*890232f2SAndroid Build Coastguard Worker /// - Parameter o:start offset of the vector 150*890232f2SAndroid Build Coastguard Worker /// - returns: the start index of the vector vectornull151*890232f2SAndroid Build Coastguard Worker public func vector(at o: Int32) -> Int32 { 152*890232f2SAndroid Build Coastguard Worker var o = o 153*890232f2SAndroid Build Coastguard Worker o += postion 154*890232f2SAndroid Build Coastguard Worker return o + bb.read(def: Int32.self, position: Int(o)) + 4 155*890232f2SAndroid Build Coastguard Worker } 156*890232f2SAndroid Build Coastguard Worker 157*890232f2SAndroid Build Coastguard Worker /// Reading an indirect offset of a table. 158*890232f2SAndroid Build Coastguard Worker /// - Parameters: 159*890232f2SAndroid Build Coastguard Worker /// - o: position within the buffer 160*890232f2SAndroid Build Coastguard Worker /// - fbb: ByteBuffer 161*890232f2SAndroid Build Coastguard Worker /// - Returns: table offset indirectnull162*890232f2SAndroid Build Coastguard Worker static public func indirect(_ o: Int32, _ fbb: ByteBuffer) -> Int32 { 163*890232f2SAndroid Build Coastguard Worker o + fbb.read(def: Int32.self, position: Int(o)) 164*890232f2SAndroid Build Coastguard Worker } 165*890232f2SAndroid Build Coastguard Worker 166*890232f2SAndroid Build Coastguard Worker /// Gets a vtable value according to an table Offset and a field offset 167*890232f2SAndroid Build Coastguard Worker /// - Parameters: 168*890232f2SAndroid Build Coastguard Worker /// - o: offset relative to entire buffer 169*890232f2SAndroid Build Coastguard Worker /// - vOffset: Field offset within a vtable 170*890232f2SAndroid Build Coastguard Worker /// - fbb: ByteBuffer 171*890232f2SAndroid Build Coastguard Worker /// - Returns: an position of a field 172*890232f2SAndroid Build Coastguard Worker static public func offset( 173*890232f2SAndroid Build Coastguard Worker _ o: Int32, 174*890232f2SAndroid Build Coastguard Worker vOffset: Int32, 175*890232f2SAndroid Build Coastguard Worker fbb: ByteBuffer) -> Int32 176*890232f2SAndroid Build Coastguard Worker { 177*890232f2SAndroid Build Coastguard Worker let vTable = Int32(fbb.capacity) - o 178*890232f2SAndroid Build Coastguard Worker return vTable + Int32(fbb.read( 179*890232f2SAndroid Build Coastguard Worker def: Int16.self, 180*890232f2SAndroid Build Coastguard Worker position: Int(vTable + vOffset - fbb.read( 181*890232f2SAndroid Build Coastguard Worker def: Int32.self, 182*890232f2SAndroid Build Coastguard Worker position: Int(vTable))))) 183*890232f2SAndroid Build Coastguard Worker } 184*890232f2SAndroid Build Coastguard Worker 185*890232f2SAndroid Build Coastguard Worker /// Compares two objects at offset A and offset B within a ByteBuffer 186*890232f2SAndroid Build Coastguard Worker /// - Parameters: 187*890232f2SAndroid Build Coastguard Worker /// - off1: first offset to compare 188*890232f2SAndroid Build Coastguard Worker /// - off2: second offset to compare 189*890232f2SAndroid Build Coastguard Worker /// - fbb: Bytebuffer 190*890232f2SAndroid Build Coastguard Worker /// - Returns: returns the difference between 191*890232f2SAndroid Build Coastguard Worker static public func compare( 192*890232f2SAndroid Build Coastguard Worker _ off1: Int32, 193*890232f2SAndroid Build Coastguard Worker _ off2: Int32, 194*890232f2SAndroid Build Coastguard Worker fbb: ByteBuffer) -> Int32 195*890232f2SAndroid Build Coastguard Worker { 196*890232f2SAndroid Build Coastguard Worker let memorySize = Int32(MemoryLayout<Int32>.size) 197*890232f2SAndroid Build Coastguard Worker let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1)) 198*890232f2SAndroid Build Coastguard Worker let _off2 = off2 + fbb.read(def: Int32.self, position: Int(off2)) 199*890232f2SAndroid Build Coastguard Worker let len1 = fbb.read(def: Int32.self, position: Int(_off1)) 200*890232f2SAndroid Build Coastguard Worker let len2 = fbb.read(def: Int32.self, position: Int(_off2)) 201*890232f2SAndroid Build Coastguard Worker let startPos1 = _off1 + memorySize 202*890232f2SAndroid Build Coastguard Worker let startPos2 = _off2 + memorySize 203*890232f2SAndroid Build Coastguard Worker let minValue = min(len1, len2) 204*890232f2SAndroid Build Coastguard Worker for i in 0...minValue { 205*890232f2SAndroid Build Coastguard Worker let b1 = fbb.read(def: Int8.self, position: Int(i + startPos1)) 206*890232f2SAndroid Build Coastguard Worker let b2 = fbb.read(def: Int8.self, position: Int(i + startPos2)) 207*890232f2SAndroid Build Coastguard Worker if b1 != b2 { 208*890232f2SAndroid Build Coastguard Worker return Int32(b2 - b1) 209*890232f2SAndroid Build Coastguard Worker } 210*890232f2SAndroid Build Coastguard Worker } 211*890232f2SAndroid Build Coastguard Worker return len1 - len2 212*890232f2SAndroid Build Coastguard Worker } 213*890232f2SAndroid Build Coastguard Worker 214*890232f2SAndroid Build Coastguard Worker /// Compares two objects at offset A and array of `Bytes` within a ByteBuffer 215*890232f2SAndroid Build Coastguard Worker /// - Parameters: 216*890232f2SAndroid Build Coastguard Worker /// - off1: Offset to compare to 217*890232f2SAndroid Build Coastguard Worker /// - key: bytes array to compare to 218*890232f2SAndroid Build Coastguard Worker /// - fbb: Bytebuffer 219*890232f2SAndroid Build Coastguard Worker /// - Returns: returns the difference between 220*890232f2SAndroid Build Coastguard Worker static public func compare( 221*890232f2SAndroid Build Coastguard Worker _ off1: Int32, 222*890232f2SAndroid Build Coastguard Worker _ key: [Byte], 223*890232f2SAndroid Build Coastguard Worker fbb: ByteBuffer) -> Int32 224*890232f2SAndroid Build Coastguard Worker { 225*890232f2SAndroid Build Coastguard Worker let memorySize = Int32(MemoryLayout<Int32>.size) 226*890232f2SAndroid Build Coastguard Worker let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1)) 227*890232f2SAndroid Build Coastguard Worker let len1 = fbb.read(def: Int32.self, position: Int(_off1)) 228*890232f2SAndroid Build Coastguard Worker let len2 = Int32(key.count) 229*890232f2SAndroid Build Coastguard Worker let startPos1 = _off1 + memorySize 230*890232f2SAndroid Build Coastguard Worker let minValue = min(len1, len2) 231*890232f2SAndroid Build Coastguard Worker for i in 0..<minValue { 232*890232f2SAndroid Build Coastguard Worker let b = fbb.read(def: Int8.self, position: Int(i + startPos1)) 233*890232f2SAndroid Build Coastguard Worker let byte = key[Int(i)] 234*890232f2SAndroid Build Coastguard Worker if b != byte { 235*890232f2SAndroid Build Coastguard Worker return Int32(b - Int8(byte)) 236*890232f2SAndroid Build Coastguard Worker } 237*890232f2SAndroid Build Coastguard Worker } 238*890232f2SAndroid Build Coastguard Worker return len1 - len2 239*890232f2SAndroid Build Coastguard Worker } 240*890232f2SAndroid Build Coastguard Worker } 241