• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 @file:Suppress("NOTHING_TO_INLINE")
17 
18 package com.google.flatbuffers.kotlin
19 
20 import kotlin.jvm.JvmInline
21 
22 @JvmInline
23 public value class BitWidth(public val value: Int) {
maxnull24   public inline fun max(other: BitWidth): BitWidth = if (this.value >= other.value) this else other
25 }
26 
27 @JvmInline
28 public value class ByteWidth(public val value: Int)
29 
30 @JvmInline
31 public value class FlexBufferType(public val value: Int) {
32   public operator fun minus(other: FlexBufferType): FlexBufferType = FlexBufferType(this.value - other.value)
33   public operator fun plus(other: FlexBufferType): FlexBufferType = FlexBufferType(this.value + other.value)
34   public operator fun compareTo(other: FlexBufferType): Int = this.value - other.value
35 }
36 
timesnull37 internal operator fun Int.times(width: ByteWidth): Int = this * width.value
38 internal operator fun Int.minus(width: ByteWidth): Int = this - width.value
39 internal operator fun Int.plus(width: ByteWidth): Int = this + width.value
40 internal operator fun Int.minus(type: FlexBufferType): Int = this - type.value
41 
42 // Returns a Key string from the buffer starting at index [start]. Key Strings are stored as
43 // C-Strings, ending with '\0'. If zero byte not found returns empty string.
44 internal inline fun ReadBuffer.getKeyString(start: Int): String {
45   val i = findFirst(0.toByte(), start)
46   return if (i >= 0) getString(start, i - start) else ""
47 }
48 
49 // read unsigned int with size byteWidth and return as a 64-bit integer
readULongnull50 internal inline fun ReadBuffer.readULong(end: Int, byteWidth: ByteWidth): ULong {
51   return when (byteWidth.value) {
52     1 -> this.getUByte(end).toULong()
53     2 -> this.getUShort(end).toULong()
54     4 -> this.getUInt(end).toULong()
55     8 -> this.getULong(end)
56     else -> error("invalid byte width $byteWidth for scalar unsigned integer")
57   }
58 }
59 
readFloatnull60 internal inline fun ReadBuffer.readFloat(end: Int, byteWidth: ByteWidth): Double {
61   return when (byteWidth.value) {
62     4 -> this.getFloat(end).toDouble()
63     8 -> this.getDouble(end)
64     else -> error("invalid byte width $byteWidth for floating point scalar") // we should never reach here
65   }
66 }
67 // return position on the [ReadBuffer] of the element that the offset is pointing to
68 // we assume all offset fits on a int, since ReadBuffer operates with that assumption
indirectnull69 internal inline fun ReadBuffer.indirect(offset: Int, byteWidth: ByteWidth): Int = offset - readInt(offset, byteWidth)
70 // returns the size of an array-like element from [ReadBuffer].
71 internal inline fun ReadBuffer.readSize(end: Int, byteWidth: ByteWidth) = readInt(end - byteWidth, byteWidth)
72 internal inline fun ReadBuffer.readUInt(end: Int, byteWidth: ByteWidth): UInt = readULong(end, byteWidth).toUInt()
73 internal inline fun ReadBuffer.readInt(end: Int, byteWidth: ByteWidth): Int = readULong(end, byteWidth).toInt()
74 internal inline fun ReadBuffer.readLong(end: Int, byteWidth: ByteWidth): Long = readULong(end, byteWidth).toLong()
75 
76 internal fun IntArray.widthInUBits(): BitWidth = arrayWidthInUBits(this.size) { this[it].toULong().widthInUBits() }
<lambda>null77 internal fun ShortArray.widthInUBits(): BitWidth = arrayWidthInUBits(this.size) { this[it].toULong().widthInUBits() }
<lambda>null78 internal fun LongArray.widthInUBits(): BitWidth = arrayWidthInUBits(this.size) { this[it].toULong().widthInUBits() }
79 
arrayWidthInUBitsnull80 private inline fun arrayWidthInUBits(size: Int, crossinline elemWidthBlock: (Int) -> BitWidth): BitWidth {
81   // Figure out smallest bit width we can store this vector with.
82   var bitWidth = W_8.max(size.toULong().widthInUBits())
83   // Check bit widths and types for all elements.
84   for (i in 0 until size) {
85     // since we know its inline types we can just assume elmentWidth to be the value width in bits.
86     bitWidth = bitWidth.max(elemWidthBlock(i))
87   }
88   return bitWidth
89 }
90 
widthInUBitsnull91 internal fun ULong.widthInUBits(): BitWidth = when {
92   this <= MAX_UBYTE_ULONG -> W_8
93   this <= UShort.MAX_VALUE -> W_16
94   this <= UInt.MAX_VALUE -> W_32
95   else -> W_64
96 }
97 
98 // returns the number of bytes needed for padding the scalar of size scalarSize.
paddingBytesnull99 internal inline fun paddingBytes(bufSize: Int, scalarSize: Int): Int = bufSize.inv() + 1 and scalarSize - 1
100 
101 internal inline fun FlexBufferType.isInline(): Boolean = this.value <= T_FLOAT.value || this == T_BOOL
102 
103 internal fun FlexBufferType.isScalar(): Boolean = when (this) {
104   T_INT, T_UINT, T_FLOAT, T_BOOL -> true
105   else -> false
106 }
107 
isIndirectScalarnull108 internal fun FlexBufferType.isIndirectScalar(): Boolean = when (this) {
109   T_INDIRECT_INT, T_INDIRECT_UINT, T_INDIRECT_FLOAT -> true
110   else -> false
111 }
112 
isTypedVectornull113 internal fun FlexBufferType.isTypedVector(): Boolean =
114   this >= T_VECTOR_INT && this <= T_VECTOR_STRING_DEPRECATED || this == T_VECTOR_BOOL
115 
116 internal fun FlexBufferType.isTypedVectorElementType(): Boolean =
117   (this.value in T_INT.value..T_KEY.value) || this == T_BOOL
118 
119 // returns the typed vector of a given scalar type.
120 internal fun FlexBufferType.toTypedVector(): FlexBufferType = (this - T_INT) + T_VECTOR_INT
121 // returns the element type of given typed vector.
122 internal fun FlexBufferType.toElementTypedVector(): FlexBufferType = this - T_VECTOR_INT + T_INT
123 
124 // Holds information about the elements inserted on the buffer.
125 internal data class Value(
126   var type: FlexBufferType = T_INT,
127   var key: Int = -1,
128   var minBitWidth: BitWidth = W_8,
129   var iValue: ULong = 0UL, // integer value
130   var dValue: Double = 0.0 // TODO(paulovap): maybe we can keep floating type on iValue as well.
131 ) { // float value
132 
133   inline fun storedPackedType(parentBitWidth: BitWidth = W_8): Byte = packedType(storedWidth(parentBitWidth), type)
134 
135   private inline fun packedType(bitWidth: BitWidth, type: FlexBufferType): Byte =
136     (bitWidth.value or (type.value shl 2)).toByte()
137 
138   private inline fun storedWidth(parentBitWidth: BitWidth): BitWidth =
139     if (type.isInline()) minBitWidth.max(parentBitWidth) else minBitWidth
140 
141   fun elemWidth(bufSize: Int, elemIndex: Int): BitWidth =
142     elemWidth(type, minBitWidth, iValue.toLong(), bufSize, elemIndex)
143 }
144 
elemWidthnull145 internal fun elemWidth(
146   type: FlexBufferType,
147   minBitWidth: BitWidth,
148   iValue: Long,
149   bufSize: Int,
150   elemIndex: Int
151 ): BitWidth {
152   if (type.isInline()) return minBitWidth
153 
154   // We have an absolute offset, but want to store a relative offset
155   // elem_index elements beyond the current buffer end. Since whether
156   // the relative offset fits in a certain byte_width depends on
157   // the size of the elements before it (and their alignment), we have
158   // to test for each size in turn.
159   // Original implementation checks for largest scalar
160   // which is long unsigned int
161   var byteWidth = 1
162   while (byteWidth <= 32) {
163     // Where are we going to write this offset?
164     val offsetLoc: Int = bufSize + paddingBytes(bufSize, byteWidth) + elemIndex * byteWidth
165     // Compute relative offset.
166     val offset: Int = offsetLoc - iValue.toInt()
167     // Does it fit?
168     val bitWidth = offset.toULong().widthInUBits()
169     if (1 shl bitWidth.value == byteWidth) return bitWidth
170     byteWidth *= 2
171   }
172   return W_64
173 }
174 
175 // For debugging purposes, convert type to a human-readable string.
typeToStringnull176 internal fun FlexBufferType.typeToString(): String = when (this) {
177   T_NULL -> "Null"
178   T_INT -> "Int"
179   T_UINT -> "UInt"
180   T_FLOAT -> "Float"
181   T_KEY -> "Key"
182   T_STRING -> "String"
183   T_INDIRECT_INT -> "IndirectInt"
184   T_INDIRECT_UINT -> "IndirectUInt"
185   T_INDIRECT_FLOAT -> "IndirectFloat"
186   T_MAP -> "Map"
187   T_VECTOR -> "Vector"
188   T_VECTOR_INT -> "IntVector"
189   T_VECTOR_UINT -> "UIntVector"
190   T_VECTOR_FLOAT -> "FloatVector"
191   T_VECTOR_KEY -> "KeyVector"
192   T_VECTOR_STRING_DEPRECATED -> "StringVectorDeprecated"
193   T_VECTOR_INT2 -> "Int2Vector"
194   T_VECTOR_UINT2 -> "UInt2Vector"
195   T_VECTOR_FLOAT2 -> "Float2Vector"
196   T_VECTOR_INT3 -> "Int3Vector"
197   T_VECTOR_UINT3 -> "UInt3Vector"
198   T_VECTOR_FLOAT3 -> "Float3Vector"
199   T_VECTOR_INT4 -> "Int4Vector"
200   T_VECTOR_UINT4 -> "UInt4Vector"
201   T_VECTOR_FLOAT4 -> "Float4Vector"
202   T_BLOB -> "BlobVector"
203   T_BOOL -> "BoolVector"
204   T_VECTOR_BOOL -> "BoolVector"
205   else -> "UnknownType"
206 }
207 
208 // Few repeated values used in hot path is cached here
emptyBlobnull209 internal fun emptyBlob() = Blob(emptyBuffer, 1, ByteWidth(1))
210 internal fun emptyVector() = Vector(emptyBuffer, 1, ByteWidth(1))
211 internal fun emptyMap() = Map(ArrayReadWriteBuffer(3), 3, ByteWidth(1))
212 internal fun nullReference() = Reference(emptyBuffer, 1, ByteWidth(0), T_NULL.value)
213 internal fun nullKey() = Key(emptyBuffer, 1)
214 
215 internal const val ZeroByte = 0.toByte()
216 internal const val MAX_UBYTE_ULONG = 255UL
217 internal const val MAX_UBYTE = 255
218 internal const val MAX_USHORT = 65535
219 
220 // value bit width possible sizes
221 internal val W_8 = BitWidth(0)
222 internal val W_16 = BitWidth(1)
223 internal val W_32 = BitWidth(2)
224 internal val W_64 = BitWidth(3)
225 
226 // These are used as the upper 6 bits of a type field to indicate the actual type.
227 internal val T_INVALID = FlexBufferType(-1)
228 internal val T_NULL = FlexBufferType(0)
229 internal val T_INT = FlexBufferType(1)
230 internal val T_UINT = FlexBufferType(2)
231 internal val T_FLOAT = FlexBufferType(3) // Types above stored inline, types below are stored in an offset.
232 internal val T_KEY = FlexBufferType(4)
233 internal val T_STRING = FlexBufferType(5)
234 internal val T_INDIRECT_INT = FlexBufferType(6)
235 internal val T_INDIRECT_UINT = FlexBufferType(7)
236 internal val T_INDIRECT_FLOAT = FlexBufferType(8)
237 internal val T_MAP = FlexBufferType(9)
238 internal val T_VECTOR = FlexBufferType(10) // Untyped.
239 internal val T_VECTOR_INT = FlexBufferType(11) // Typed any size  = stores no type table).
240 internal val T_VECTOR_UINT = FlexBufferType(12)
241 internal val T_VECTOR_FLOAT = FlexBufferType(13)
242 internal val T_VECTOR_KEY = FlexBufferType(14)
243 // DEPRECATED, use FBT_VECTOR or FBT_VECTOR_KEY instead.
244 // more info on https://github.com/google/flatbuffers/issues/5627.
245 internal val T_VECTOR_STRING_DEPRECATED = FlexBufferType(15)
246 internal val T_VECTOR_INT2 = FlexBufferType(16) // Typed tuple  = no type table; no size field).
247 internal val T_VECTOR_UINT2 = FlexBufferType(17)
248 internal val T_VECTOR_FLOAT2 = FlexBufferType(18)
249 internal val T_VECTOR_INT3 = FlexBufferType(19) // Typed triple  = no type table; no size field).
250 internal val T_VECTOR_UINT3 = FlexBufferType(20)
251 internal val T_VECTOR_FLOAT3 = FlexBufferType(21)
252 internal val T_VECTOR_INT4 = FlexBufferType(22) // Typed quad  = no type table; no size field).
253 internal val T_VECTOR_UINT4 = FlexBufferType(23)
254 internal val T_VECTOR_FLOAT4 = FlexBufferType(24)
255 internal val T_BLOB = FlexBufferType(25)
256 internal val T_BOOL = FlexBufferType(26)
257 internal val T_VECTOR_BOOL = FlexBufferType(36) // To Allow the same type of conversion of type to vector type
258