Table.swift (8385B)
1 /* 2 * Copyright 2023 Google Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #if !os(WASI) 18 import Foundation 19 #else 20 import SwiftOverlayShims 21 #endif 22 23 /// `Table` is a Flatbuffers object that can read, 24 /// mutate scalar fields within a valid flatbuffers buffer 25 @frozen 26 public struct Table { 27 28 /// Hosting Bytebuffer 29 public private(set) var bb: ByteBuffer 30 /// Current position of the table within the buffer 31 public private(set) var postion: Int32 32 33 /// Initializer for the table interface to allow generated code to read 34 /// data from memory 35 /// - Parameters: 36 /// - bb: ByteBuffer that stores data 37 /// - position: Current table position 38 /// - Note: This will `CRASH` if read on a big endian machine 39 public init(bb: ByteBuffer, position: Int32 = 0) { 40 guard isLitteEndian else { 41 fatalError( 42 "Reading/Writing a buffer in big endian machine is not supported on swift") 43 } 44 self.bb = bb 45 postion = position 46 } 47 48 /// Gets the offset of the current field within the buffer by reading 49 /// the vtable 50 /// - Parameter o: current offset 51 /// - Returns: offset of field within buffer 52 public func offset(_ o: Int32) -> Int32 { 53 let vtable = postion - bb.read(def: Int32.self, position: Int(postion)) 54 return o < bb 55 .read(def: VOffset.self, position: Int(vtable)) ? Int32(bb.read( 56 def: Int16.self, 57 position: Int(vtable + o))) : 0 58 } 59 60 /// Gets the indirect offset of the current stored object 61 /// (applicable only for object arrays) 62 /// - Parameter o: current offset 63 /// - Returns: offset of field within buffer 64 public func indirect(_ o: Int32) -> Int32 { 65 o + bb.read(def: Int32.self, position: Int(o)) 66 } 67 68 /// String reads from the buffer with respect to position of the current table. 69 /// - Parameter offset: Offset of the string 70 public func string(at offset: Int32) -> String? { 71 directString(at: offset + postion) 72 } 73 74 /// Direct string reads from the buffer disregarding the position of the table. 75 /// It would be preferable to use string unless the current position of the table 76 /// is not needed 77 /// - Parameter offset: Offset of the string 78 public func directString(at offset: Int32) -> String? { 79 var offset = offset 80 offset += bb.read(def: Int32.self, position: Int(offset)) 81 let count = bb.read(def: Int32.self, position: Int(offset)) 82 let position = Int(offset) + MemoryLayout<Int32>.size 83 return bb.readString(at: position, count: Int(count)) 84 } 85 86 /// Reads from the buffer with respect to the position in the table. 87 /// - Parameters: 88 /// - type: Type of Element that needs to be read from the buffer 89 /// - o: Offset of the Element 90 public func readBuffer<T>(of type: T.Type, at o: Int32) -> T { 91 directRead(of: T.self, offset: o + postion) 92 } 93 94 /// Reads from the buffer disregarding the position of the table. 95 /// It would be used when reading from an 96 /// ``` 97 /// let offset = __t.offset(10) 98 /// //Only used when the we already know what is the 99 /// // position in the table since __t.vector(at:) 100 /// // returns the index with respect to the position 101 /// __t.directRead(of: Byte.self, 102 /// offset: __t.vector(at: offset) + index * 1) 103 /// ``` 104 /// - Parameters: 105 /// - type: Type of Element that needs to be read from the buffer 106 /// - o: Offset of the Element 107 public func directRead<T>(of type: T.Type, offset o: Int32) -> T { 108 let r = bb.read(def: T.self, position: Int(o)) 109 return r 110 } 111 112 /// Returns that current `Union` object at a specific offset 113 /// by adding offset to the current position of table 114 /// - Parameter o: offset 115 /// - Returns: A flatbuffers object 116 public func union<T: FlatbuffersInitializable>(_ o: Int32) -> T { 117 let o = o + postion 118 return directUnion(o) 119 } 120 121 /// Returns a direct `Union` object at a specific offset 122 /// - Parameter o: offset 123 /// - Returns: A flatbuffers object 124 public func directUnion<T: FlatbuffersInitializable>(_ o: Int32) -> T { 125 T.init(bb, o: o + bb.read(def: Int32.self, position: Int(o))) 126 } 127 128 /// Returns a vector of type T at a specific offset 129 /// This should only be used by `Scalars` 130 /// - Parameter off: Readable offset 131 /// - Returns: Returns a vector of type [T] 132 public func getVector<T>(at off: Int32) -> [T]? { 133 let o = offset(off) 134 guard o != 0 else { return nil } 135 return bb.readSlice(index: Int(vector(at: o)), count: Int(vector(count: o))) 136 } 137 138 /// Vector count gets the count of Elements within the array 139 /// - Parameter o: start offset of the vector 140 /// - returns: Count of elements 141 public func vector(count o: Int32) -> Int32 { 142 var o = o 143 o += postion 144 o += bb.read(def: Int32.self, position: Int(o)) 145 return bb.read(def: Int32.self, position: Int(o)) 146 } 147 148 /// Vector start index in the buffer 149 /// - Parameter o:start offset of the vector 150 /// - returns: the start index of the vector 151 public func vector(at o: Int32) -> Int32 { 152 var o = o 153 o += postion 154 return o + bb.read(def: Int32.self, position: Int(o)) + 4 155 } 156 157 /// Reading an indirect offset of a table. 158 /// - Parameters: 159 /// - o: position within the buffer 160 /// - fbb: ByteBuffer 161 /// - Returns: table offset 162 static public func indirect(_ o: Int32, _ fbb: ByteBuffer) -> Int32 { 163 o + fbb.read(def: Int32.self, position: Int(o)) 164 } 165 166 /// Gets a vtable value according to an table Offset and a field offset 167 /// - Parameters: 168 /// - o: offset relative to entire buffer 169 /// - vOffset: Field offset within a vtable 170 /// - fbb: ByteBuffer 171 /// - Returns: an position of a field 172 static public func offset( 173 _ o: Int32, 174 vOffset: Int32, 175 fbb: ByteBuffer) -> Int32 176 { 177 let vTable = Int32(fbb.capacity) - o 178 return vTable + Int32(fbb.read( 179 def: Int16.self, 180 position: Int(vTable + vOffset - fbb.read( 181 def: Int32.self, 182 position: Int(vTable))))) 183 } 184 185 /// Compares two objects at offset A and offset B within a ByteBuffer 186 /// - Parameters: 187 /// - off1: first offset to compare 188 /// - off2: second offset to compare 189 /// - fbb: Bytebuffer 190 /// - Returns: returns the difference between 191 static public func compare( 192 _ off1: Int32, 193 _ off2: Int32, 194 fbb: ByteBuffer) -> Int32 195 { 196 let memorySize = Int32(MemoryLayout<Int32>.size) 197 let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1)) 198 let _off2 = off2 + fbb.read(def: Int32.self, position: Int(off2)) 199 let len1 = fbb.read(def: Int32.self, position: Int(_off1)) 200 let len2 = fbb.read(def: Int32.self, position: Int(_off2)) 201 let startPos1 = _off1 + memorySize 202 let startPos2 = _off2 + memorySize 203 let minValue = min(len1, len2) 204 for i in 0...minValue { 205 let b1 = fbb.read(def: Int8.self, position: Int(i + startPos1)) 206 let b2 = fbb.read(def: Int8.self, position: Int(i + startPos2)) 207 if b1 != b2 { 208 return Int32(b2 - b1) 209 } 210 } 211 return len1 - len2 212 } 213 214 /// Compares two objects at offset A and array of `Bytes` within a ByteBuffer 215 /// - Parameters: 216 /// - off1: Offset to compare to 217 /// - key: bytes array to compare to 218 /// - fbb: Bytebuffer 219 /// - Returns: returns the difference between 220 static public func compare( 221 _ off1: Int32, 222 _ key: [Byte], 223 fbb: ByteBuffer) -> Int32 224 { 225 let memorySize = Int32(MemoryLayout<Int32>.size) 226 let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1)) 227 let len1 = fbb.read(def: Int32.self, position: Int(_off1)) 228 let len2 = Int32(key.count) 229 let startPos1 = _off1 + memorySize 230 let minValue = min(len1, len2) 231 for i in 0..<minValue { 232 let b = fbb.read(def: Int8.self, position: Int(i + startPos1)) 233 let byte = key[Int(i)] 234 if b != byte { 235 return Int32(b - Int8(byte)) 236 } 237 } 238 return len1 - len2 239 } 240 }