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