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