damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

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 }