1 /* 2 * Copyright 2021 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 import Foundation 18 19 @frozen 20 public struct Table { 21 public private(set) var bb: ByteBuffer 22 public private(set) var postion: Int32 23 24 public init(bb: ByteBuffer, position: Int32 = 0) { 25 guard isLitteEndian else { 26 fatalError("Reading/Writing a buffer in big endian machine is not supported on swift") 27 } 28 self.bb = bb 29 postion = position 30 } 31 offsetnull32 public func offset(_ o: Int32) -> Int32 { 33 let vtable = postion - bb.read(def: Int32.self, position: Int(postion)) 34 return o < bb.read(def: VOffset.self, position: Int(vtable)) ? Int32(bb.read( 35 def: Int16.self, 36 position: Int(vtable + o))) : 0 37 } 38 indirectnull39 public func indirect(_ o: Int32) -> Int32 { o + bb.read(def: Int32.self, position: Int(o)) } 40 41 /// String reads from the buffer with respect to position of the current table. 42 /// - Parameter offset: Offset of the string stringnull43 public func string(at offset: Int32) -> String? { 44 directString(at: offset + postion) 45 } 46 47 /// Direct string reads from the buffer disregarding the position of the table. 48 /// It would be preferable to use string unless the current position of the table is not needed 49 /// - Parameter offset: Offset of the string directStringnull50 public func directString(at offset: Int32) -> String? { 51 var offset = offset 52 offset += bb.read(def: Int32.self, position: Int(offset)) 53 let count = bb.read(def: Int32.self, position: Int(offset)) 54 let position = offset + Int32(MemoryLayout<Int32>.size) 55 return bb.readString(at: position, count: count) 56 } 57 58 /// Reads from the buffer with respect to the position in the table. 59 /// - Parameters: 60 /// - type: Type of Element that needs to be read from the buffer 61 /// - o: Offset of the Element readBuffer<T>null62 public func readBuffer<T>(of type: T.Type, at o: Int32) -> T { 63 directRead(of: T.self, offset: o + postion) 64 } 65 66 /// Reads from the buffer disregarding the position of the table. 67 /// It would be used when reading from an 68 /// ``` 69 /// let offset = __t.offset(10) 70 /// //Only used when the we already know what is the 71 /// // position in the table since __t.vector(at:) 72 /// // returns the index with respect to the position 73 /// __t.directRead(of: Byte.self, 74 /// offset: __t.vector(at: offset) + index * 1) 75 /// ``` 76 /// - Parameters: 77 /// - type: Type of Element that needs to be read from the buffer 78 /// - o: Offset of the Element directRead<T>null79 public func directRead<T>(of type: T.Type, offset o: Int32) -> T { 80 let r = bb.read(def: T.self, position: Int(o)) 81 return r 82 } 83 union<T: FlatbuffersInitializable>null84 public func union<T: FlatbuffersInitializable>(_ o: Int32) -> T { 85 let o = o + postion 86 return directUnion(o) 87 } 88 directUnion<T: FlatbuffersInitializable>null89 public func directUnion<T: FlatbuffersInitializable>(_ o: Int32) -> T { 90 T.init(bb, o: o + bb.read(def: Int32.self, position: Int(o))) 91 } 92 getVector<T>null93 public func getVector<T>(at off: Int32) -> [T]? { 94 let o = offset(off) 95 guard o != 0 else { return nil } 96 return bb.readSlice(index: vector(at: o), count: vector(count: o)) 97 } 98 99 /// Vector count gets the count of Elements within the array 100 /// - Parameter o: start offset of the vector 101 /// - returns: Count of elements vectornull102 public func vector(count o: Int32) -> Int32 { 103 var o = o 104 o += postion 105 o += bb.read(def: Int32.self, position: Int(o)) 106 return bb.read(def: Int32.self, position: Int(o)) 107 } 108 109 /// Vector start index in the buffer 110 /// - Parameter o:start offset of the vector 111 /// - returns: the start index of the vector vectornull112 public func vector(at o: Int32) -> Int32 { 113 var o = o 114 o += postion 115 return o + bb.read(def: Int32.self, position: Int(o)) + 4 116 } 117 indirectnull118 static public func indirect(_ o: Int32, _ fbb: ByteBuffer) -> Int32 { o + fbb.read( 119 def: Int32.self, 120 position: Int(o)) } 121 offsetnull122 static public func offset(_ o: Int32, vOffset: Int32, fbb: ByteBuffer) -> Int32 { 123 let vTable = Int32(fbb.capacity) - o 124 return vTable + Int32(fbb.read( 125 def: Int16.self, 126 position: Int(vTable + vOffset - fbb.read(def: Int32.self, position: Int(vTable))))) 127 } 128 comparenull129 static public func compare(_ off1: Int32, _ off2: Int32, fbb: ByteBuffer) -> Int32 { 130 let memorySize = Int32(MemoryLayout<Int32>.size) 131 let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1)) 132 let _off2 = off2 + fbb.read(def: Int32.self, position: Int(off2)) 133 let len1 = fbb.read(def: Int32.self, position: Int(_off1)) 134 let len2 = fbb.read(def: Int32.self, position: Int(_off2)) 135 let startPos1 = _off1 + memorySize 136 let startPos2 = _off2 + memorySize 137 let minValue = min(len1, len2) 138 for i in 0...minValue { 139 let b1 = fbb.read(def: Int8.self, position: Int(i + startPos1)) 140 let b2 = fbb.read(def: Int8.self, position: Int(i + startPos2)) 141 if b1 != b2 { 142 return Int32(b2 - b1) 143 } 144 } 145 return len1 - len2 146 } 147 comparenull148 static public func compare(_ off1: Int32, _ key: [Byte], fbb: ByteBuffer) -> Int32 { 149 let memorySize = Int32(MemoryLayout<Int32>.size) 150 let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1)) 151 let len1 = fbb.read(def: Int32.self, position: Int(_off1)) 152 let len2 = Int32(key.count) 153 let startPos1 = _off1 + memorySize 154 let minValue = min(len1, len2) 155 for i in 0..<minValue { 156 let b = fbb.read(def: Int8.self, position: Int(i + startPos1)) 157 let byte = key[Int(i)] 158 if b != byte { 159 return Int32(b - Int8(byte)) 160 } 161 } 162 return len1 - len2 163 } 164 } 165