blob: ff501fc9b9fc4129b5d0d59f11079e8e9e7ec1d7 [file] [log] [blame]
Austin Schuh58b9b472020-11-25 19:12:44 -08001/*
James Kuszmaul8e62b022022-03-22 09:33:25 -07002 * Copyright 2021 Google Inc. All rights reserved.
Austin Schuh58b9b472020-11-25 19:12:44 -08003 *
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
Austin Schuh272c6132020-11-14 16:37:52 -080017import Foundation
18
James Kuszmaul8e62b022022-03-22 09:33:25 -070019/// `Table` is a Flatbuffers object that can read,
20/// mutate scalar fields within a valid flatbuffers buffer
21@frozen
Austin Schuh272c6132020-11-14 16:37:52 -080022public struct Table {
James Kuszmaul8e62b022022-03-22 09:33:25 -070023
24 /// Hosting Bytebuffer
Austin Schuh58b9b472020-11-25 19:12:44 -080025 public private(set) var bb: ByteBuffer
James Kuszmaul8e62b022022-03-22 09:33:25 -070026 /// Current position of the table within the buffer
Austin Schuh58b9b472020-11-25 19:12:44 -080027 public private(set) var postion: Int32
Austin Schuh272c6132020-11-14 16:37:52 -080028
James Kuszmaul8e62b022022-03-22 09:33:25 -070029 /// Initializer for the table interface to allow generated code to read
30 /// data from memory
31 /// - Parameters:
32 /// - bb: ByteBuffer that stores data
33 /// - position: Current table position
34 /// - Note: This will `CRASH` if read on a big endian machine
Austin Schuh58b9b472020-11-25 19:12:44 -080035 public init(bb: ByteBuffer, position: Int32 = 0) {
36 guard isLitteEndian else {
James Kuszmaul8e62b022022-03-22 09:33:25 -070037 fatalError(
38 "Reading/Writing a buffer in big endian machine is not supported on swift")
Austin Schuh272c6132020-11-14 16:37:52 -080039 }
Austin Schuh58b9b472020-11-25 19:12:44 -080040 self.bb = bb
41 postion = position
42 }
Austin Schuh272c6132020-11-14 16:37:52 -080043
James Kuszmaul8e62b022022-03-22 09:33:25 -070044 /// Gets the offset of the current field within the buffer by reading
45 /// the vtable
46 /// - Parameter o: current offset
47 /// - Returns: offset of field within buffer
Austin Schuh58b9b472020-11-25 19:12:44 -080048 public func offset(_ o: Int32) -> Int32 {
49 let vtable = postion - bb.read(def: Int32.self, position: Int(postion))
James Kuszmaul8e62b022022-03-22 09:33:25 -070050 return o < bb
51 .read(def: VOffset.self, position: Int(vtable)) ? Int32(bb.read(
52 def: Int16.self,
53 position: Int(vtable + o))) : 0
Austin Schuh58b9b472020-11-25 19:12:44 -080054 }
55
James Kuszmaul8e62b022022-03-22 09:33:25 -070056 /// Gets the indirect offset of the current stored object
57 /// (applicable only for object arrays)
58 /// - Parameter o: current offset
59 /// - Returns: offset of field within buffer
60 public func indirect(_ o: Int32) -> Int32 {
61 o + bb.read(def: Int32.self, position: Int(o))
62 }
Austin Schuh58b9b472020-11-25 19:12:44 -080063
64 /// String reads from the buffer with respect to position of the current table.
65 /// - Parameter offset: Offset of the string
66 public func string(at offset: Int32) -> String? {
67 directString(at: offset + postion)
68 }
69
70 /// Direct string reads from the buffer disregarding the position of the table.
James Kuszmaul8e62b022022-03-22 09:33:25 -070071 /// It would be preferable to use string unless the current position of the table
72 /// is not needed
Austin Schuh58b9b472020-11-25 19:12:44 -080073 /// - Parameter offset: Offset of the string
74 public func directString(at offset: Int32) -> String? {
75 var offset = offset
76 offset += bb.read(def: Int32.self, position: Int(offset))
77 let count = bb.read(def: Int32.self, position: Int(offset))
James Kuszmaul8e62b022022-03-22 09:33:25 -070078 let position = Int(offset) + MemoryLayout<Int32>.size
79 return bb.readString(at: position, count: Int(count))
Austin Schuh58b9b472020-11-25 19:12:44 -080080 }
81
82 /// Reads from the buffer with respect to the position in the table.
83 /// - Parameters:
James Kuszmaul8e62b022022-03-22 09:33:25 -070084 /// - type: Type of Element that needs to be read from the buffer
Austin Schuh58b9b472020-11-25 19:12:44 -080085 /// - o: Offset of the Element
James Kuszmaul8e62b022022-03-22 09:33:25 -070086 public func readBuffer<T>(of type: T.Type, at o: Int32) -> T {
Austin Schuh58b9b472020-11-25 19:12:44 -080087 directRead(of: T.self, offset: o + postion)
88 }
89
90 /// Reads from the buffer disregarding the position of the table.
91 /// It would be used when reading from an
92 /// ```
93 /// let offset = __t.offset(10)
94 /// //Only used when the we already know what is the
95 /// // position in the table since __t.vector(at:)
96 /// // returns the index with respect to the position
97 /// __t.directRead(of: Byte.self,
98 /// offset: __t.vector(at: offset) + index * 1)
99 /// ```
100 /// - Parameters:
James Kuszmaul8e62b022022-03-22 09:33:25 -0700101 /// - type: Type of Element that needs to be read from the buffer
Austin Schuh58b9b472020-11-25 19:12:44 -0800102 /// - o: Offset of the Element
James Kuszmaul8e62b022022-03-22 09:33:25 -0700103 public func directRead<T>(of type: T.Type, offset o: Int32) -> T {
Austin Schuh58b9b472020-11-25 19:12:44 -0800104 let r = bb.read(def: T.self, position: Int(o))
105 return r
106 }
107
James Kuszmaul8e62b022022-03-22 09:33:25 -0700108 /// Returns that current `Union` object at a specific offset
109 /// by adding offset to the current position of table
110 /// - Parameter o: offset
111 /// - Returns: A flatbuffers object
112 public func union<T: FlatbuffersInitializable>(_ o: Int32) -> T {
Austin Schuh58b9b472020-11-25 19:12:44 -0800113 let o = o + postion
114 return directUnion(o)
115 }
116
James Kuszmaul8e62b022022-03-22 09:33:25 -0700117 /// Returns a direct `Union` object at a specific offset
118 /// - Parameter o: offset
119 /// - Returns: A flatbuffers object
120 public func directUnion<T: FlatbuffersInitializable>(_ o: Int32) -> T {
Austin Schuh58b9b472020-11-25 19:12:44 -0800121 T.init(bb, o: o + bb.read(def: Int32.self, position: Int(o)))
122 }
123
James Kuszmaul8e62b022022-03-22 09:33:25 -0700124 /// Returns a vector of type T at a specific offset
125 /// This should only be used by `Scalars`
126 /// - Parameter off: Readable offset
127 /// - Returns: Returns a vector of type [T]
Austin Schuh58b9b472020-11-25 19:12:44 -0800128 public func getVector<T>(at off: Int32) -> [T]? {
129 let o = offset(off)
130 guard o != 0 else { return nil }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700131 return bb.readSlice(index: Int(vector(at: o)), count: Int(vector(count: o)))
Austin Schuh58b9b472020-11-25 19:12:44 -0800132 }
133
134 /// Vector count gets the count of Elements within the array
135 /// - Parameter o: start offset of the vector
136 /// - returns: Count of elements
137 public func vector(count o: Int32) -> Int32 {
138 var o = o
139 o += postion
140 o += bb.read(def: Int32.self, position: Int(o))
141 return bb.read(def: Int32.self, position: Int(o))
142 }
143
144 /// Vector start index in the buffer
145 /// - Parameter o:start offset of the vector
146 /// - returns: the start index of the vector
147 public func vector(at o: Int32) -> Int32 {
148 var o = o
149 o += postion
150 return o + bb.read(def: Int32.self, position: Int(o)) + 4
151 }
Austin Schuh272c6132020-11-14 16:37:52 -0800152
James Kuszmaul8e62b022022-03-22 09:33:25 -0700153 /// Reading an indirect offset of a table.
154 /// - Parameters:
155 /// - o: position within the buffer
156 /// - fbb: ByteBuffer
157 /// - Returns: table offset
158 static public func indirect(_ o: Int32, _ fbb: ByteBuffer) -> Int32 {
159 o + fbb.read(def: Int32.self, position: Int(o))
160 }
Austin Schuh58b9b472020-11-25 19:12:44 -0800161
James Kuszmaul8e62b022022-03-22 09:33:25 -0700162 /// Gets a vtable value according to an table Offset and a field offset
163 /// - Parameters:
164 /// - o: offset relative to entire buffer
165 /// - vOffset: Field offset within a vtable
166 /// - fbb: ByteBuffer
167 /// - Returns: an position of a field
168 static public func offset(
169 _ o: Int32,
170 vOffset: Int32,
171 fbb: ByteBuffer) -> Int32
172 {
Austin Schuh58b9b472020-11-25 19:12:44 -0800173 let vTable = Int32(fbb.capacity) - o
174 return vTable + Int32(fbb.read(
175 def: Int16.self,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700176 position: Int(vTable + vOffset - fbb.read(
177 def: Int32.self,
178 position: Int(vTable)))))
Austin Schuh58b9b472020-11-25 19:12:44 -0800179 }
180
James Kuszmaul8e62b022022-03-22 09:33:25 -0700181 /// Compares two objects at offset A and offset B within a ByteBuffer
182 /// - Parameters:
183 /// - off1: first offset to compare
184 /// - off2: second offset to compare
185 /// - fbb: Bytebuffer
186 /// - Returns: returns the difference between
187 static public func compare(
188 _ off1: Int32,
189 _ off2: Int32,
190 fbb: ByteBuffer) -> Int32
191 {
Austin Schuh58b9b472020-11-25 19:12:44 -0800192 let memorySize = Int32(MemoryLayout<Int32>.size)
193 let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1))
194 let _off2 = off2 + fbb.read(def: Int32.self, position: Int(off2))
195 let len1 = fbb.read(def: Int32.self, position: Int(_off1))
196 let len2 = fbb.read(def: Int32.self, position: Int(_off2))
197 let startPos1 = _off1 + memorySize
198 let startPos2 = _off2 + memorySize
199 let minValue = min(len1, len2)
200 for i in 0...minValue {
201 let b1 = fbb.read(def: Int8.self, position: Int(i + startPos1))
202 let b2 = fbb.read(def: Int8.self, position: Int(i + startPos2))
203 if b1 != b2 {
204 return Int32(b2 - b1)
205 }
Austin Schuh272c6132020-11-14 16:37:52 -0800206 }
Austin Schuh58b9b472020-11-25 19:12:44 -0800207 return len1 - len2
208 }
209
James Kuszmaul8e62b022022-03-22 09:33:25 -0700210 /// Compares two objects at offset A and array of `Bytes` within a ByteBuffer
211 /// - Parameters:
212 /// - off1: Offset to compare to
213 /// - key: bytes array to compare to
214 /// - fbb: Bytebuffer
215 /// - Returns: returns the difference between
216 static public func compare(
217 _ off1: Int32,
218 _ key: [Byte],
219 fbb: ByteBuffer) -> Int32
220 {
Austin Schuh58b9b472020-11-25 19:12:44 -0800221 let memorySize = Int32(MemoryLayout<Int32>.size)
222 let _off1 = off1 + fbb.read(def: Int32.self, position: Int(off1))
223 let len1 = fbb.read(def: Int32.self, position: Int(_off1))
224 let len2 = Int32(key.count)
225 let startPos1 = _off1 + memorySize
226 let minValue = min(len1, len2)
227 for i in 0..<minValue {
228 let b = fbb.read(def: Int8.self, position: Int(i + startPos1))
229 let byte = key[Int(i)]
230 if b != byte {
231 return Int32(b - Int8(byte))
232 }
Austin Schuh272c6132020-11-14 16:37:52 -0800233 }
Austin Schuh58b9b472020-11-25 19:12:44 -0800234 return len1 - len2
235 }
Austin Schuh272c6132020-11-14 16:37:52 -0800236}