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 class FlexBuffersBuilder(
21   public val buffer: ReadWriteBuffer,
22   private val shareFlag: Int = SHARE_KEYS
23 ) {
24 
25   public constructor(initialCapacity: Int = 1024, shareFlag: Int = SHARE_KEYS) :
26     this(ArrayReadWriteBuffer(initialCapacity), shareFlag)
27 
28   private val stringValuePool: HashMap<String, Value> = HashMap()
29   private val stringKeyPool: HashMap<String, Int> = HashMap()
30   private val stack: MutableList<Value> = mutableListOf()
31   private var finished: Boolean = false
32 
33   /**
34    * Reset the FlexBuffersBuilder by purging all data that it holds. Buffer might
35    * keep its capacity after a reset.
36    */
clearnull37   public fun clear() {
38     buffer.clear()
39     stringValuePool.clear()
40     stringKeyPool.clear()
41     stack.clear()
42     finished = false
43   }
44 
45   /**
46    * Finish writing the message into the buffer. After that no other element must
47    * be inserted into the buffer. Also, you must call this function before start using the
48    * FlexBuffer message
49    * @return [ReadBuffer] containing the FlexBuffer message
50    */
finishnull51   public fun finish(): ReadBuffer {
52     // If you hit this assert, you likely have objects that were never included
53     // in a parent. You need to have exactly one root to finish a buffer.
54     // Check your Start/End calls are matched, and all objects are inside
55     // some other object.
56     if (stack.size != 1) error("There is must be only on object as root. Current ${stack.size}.")
57     // Write root value.
58     val byteWidth = align(stack[0].elemWidth(buffer.writePosition, 0))
59     writeAny(stack[0], byteWidth)
60     // Write root type.
61     buffer.put(stack[0].storedPackedType())
62     // Write root size. Normally determined by parent, but root has no parent :)
63     buffer.put(byteWidth.value.toByte())
64     this.finished = true
65     return buffer // TODO: make a read-only shallow copy
66   }
67 
68   /**
69    * Insert a single [Boolean] into the buffer
70    * @param value true or false
71    */
<lambda>null72   public fun put(value: Boolean): Unit = run { this[null] = value }
73 
74   /**
75    * Insert a null reference into the buffer. A key must be present if element is inserted into a map.
76    */
putNullnull77   public fun putNull(key: String? = null): Unit =
78     run { stack.add(Value(T_NULL, putKey(key), W_8, 0UL)) }
79 
80   /**
81    * Insert a single [Boolean] into the buffer. A key must be present if element is inserted into a map.
82    */
setnull83   public operator fun set(key: String? = null, value: Boolean): Unit =
84     run { stack.add(Value(T_BOOL, putKey(key), W_8, if (value) 1UL else 0UL)) }
85 
86   /**
87    * Insert a single [Byte] into the buffer
88    */
putnull89   public fun put(value: Byte): Unit = set(null, value.toLong())
90 
91   /**
92    * Insert a single [Byte] into the buffer. A key must be present if element is inserted into a map.
93    */
94   public operator fun set(key: String? = null, value: Byte): Unit = set(key, value.toLong())
95 
96   /**
97    * Insert a single [Short] into the buffer.
98    */
99   public fun put(value: Short): Unit = set(null, value.toLong())
100 
101   /**
102    * Insert a single [Short] into the buffer. A key must be present if element is inserted into a map.
103    */
104   public inline operator fun set(key: String? = null, value: Short): Unit = set(key, value.toLong())
105 
106   /**
107    * Insert a single [Int] into the buffer.
108    */
109   public fun put(value: Int): Unit = set(null, value.toLong())
110 
111   /**
112    * Insert a single [Int] into the buffer. A key must be present if element is inserted into a map.
113    */
114   public inline operator fun set(key: String? = null, value: Int): Unit = set(key, value.toLong())
115 
116   /**
117    * Insert a single [Long] into the buffer.
118    */
119   public fun put(value: Long): Unit = set(null, value)
120 
121   /**
122    * Insert a single [Long] into the buffer. A key must be present if element is inserted into a map.
123    */
124   public operator fun set(key: String? = null, value: Long): Unit =
125     run { stack.add(Value(T_INT, putKey(key), value.toULong().widthInUBits(), value.toULong())) }
126 
127   /**
128    * Insert a single [UByte] into the buffer
129    */
putnull130   public fun put(value: UByte): Unit = set(null, value.toULong())
131 
132   /**
133    * Insert a single [UByte] into the buffer. A key must be present if element is inserted into a map.
134    */
135   public inline operator fun set(key: String? = null, value: UByte): Unit = set(key, value.toULong())
136 
137   /**
138    * Insert a single [UShort] into the buffer.
139    */
140   public fun put(value: UShort): Unit = set(null, value.toULong())
141 
142   /**
143    * Insert a single [UShort] into the buffer. A key must be present if element is inserted into a map.
144    */
145   private inline operator fun set(key: String? = null, value: UShort): Unit = set(key, value.toULong())
146 
147   /**
148    * Insert a single [UInt] into the buffer.
149    */
150   public fun put(value: UInt): Unit = set(null, value.toULong())
151 
152   /**
153    * Insert a single [UInt] into the buffer. A key must be present if element is inserted into a map.
154    */
155   private inline operator fun set(key: String? = null, value: UInt): Unit = set(key, value.toULong())
156 
157   /**
158    * Insert a single [ULong] into the buffer.
159    */
160   public fun put(value: ULong): Unit = set(null, value)
161 
162   /**
163    * Insert a single [ULong] into the buffer. A key must be present if element is inserted into a map.
164    */
165   public operator fun set(key: String? = null, value: ULong): Unit =
166     run { stack.add(Value(T_UINT, putKey(key), value.widthInUBits(), value)) }
167 
168   /**
169    * Insert a single [Float] into the buffer.
170    */
<lambda>null171   public fun put(value: Float): Unit = run { this[null] = value }
172 
173   /**
174    * Insert a single [Float] into the buffer. A key must be present if element is inserted into a map.
175    */
setnull176   public operator fun set(key: String? = null, value: Float): Unit =
177     run { stack.add(Value(T_FLOAT, putKey(key), W_32, dValue = value.toDouble())) }
178 
179   /**
180    * Insert a single [Double] into the buffer.
181    */
<lambda>null182   public fun put(value: Double): Unit = run { this[null] = value }
183 
184   /**
185    * Insert a single [Double] into the buffer. A key must be present if element is inserted into a map.
186    */
setnull187   public operator fun set(key: String? = null, value: Double): Unit =
188     run { stack.add(Value(T_FLOAT, putKey(key), W_64, dValue = value)) }
189 
190   /**
191    * Insert a single [String] into the buffer.
192    */
putnull193   public fun put(value: String): Int = set(null, value)
194 
195   /**
196    * Insert a single [String] into the buffer. A key must be present if element is inserted into a map.
197    */
198   public operator fun set(key: String? = null, value: String): Int {
199     val iKey = putKey(key)
200     val holder = if (shareFlag and SHARE_STRINGS != 0) {
201       stringValuePool.getOrPut(value) { writeString(iKey, value).also { stringValuePool[value] = it } }.copy(key = iKey)
202     } else {
203       writeString(iKey, value)
204     }
205     stack.add(holder)
206     return holder.iValue.toInt()
207   }
208 
209   /**
210    * Adds a [ByteArray] into the message as a [Blob].
211    * @param value byte array
212    * @return position in buffer as the start of byte array
213    */
putnull214   public fun put(value: ByteArray): Int = set(null, value)
215 
216   /**
217    * Adds a [ByteArray] into the message as a [Blob]. A key must be present if element is inserted into a map.
218    * @param value byte array
219    * @return position in buffer as the start of byte array
220    */
221   public operator fun set(key: String? = null, value: ByteArray): Int {
222     val element = writeBlob(putKey(key), value, T_BLOB, false)
223     stack.add(element)
224     return element.iValue.toInt()
225   }
226 
227   /**
228    * Adds a [IntArray] into the message as a typed vector of fixed size.
229    * @param value [IntArray]
230    * @return position in buffer as the start of byte array
231    */
putnull232   public fun put(value: IntArray): Int = set(null, value)
233 
234   /**
235    * Adds a [IntArray] into the message as a typed vector of fixed size.
236    * A key must be present if element is inserted into a map.
237    * @param value [IntArray]
238    * @return position in buffer as the start of byte array
239    */
240   public operator fun set(key: String? = null, value: IntArray): Int =
241     setTypedVector(key, value.size, T_VECTOR_INT, value.widthInUBits()) { writeIntArray(value, it) }
242 
243   /**
244    * Adds a [ShortArray] into the message as a typed vector of fixed size.
245    * @param value [ShortArray]
246    * @return position in buffer as the start of byte array
247    */
putnull248   public fun put(value: ShortArray): Int = set(null, value)
249 
250   /**
251    * Adds a [ShortArray] into the message as a typed vector of fixed size.
252    * A key must be present if element is inserted into a map.
253    * @param value [ShortArray]
254    * @return position in buffer as the start of byte array
255    */
256   public operator fun set(key: String? = null, value: ShortArray): Int =
257     setTypedVector(key, value.size, T_VECTOR_INT, value.widthInUBits()) { writeIntArray(value, it) }
258 
259   /**
260    * Adds a [LongArray] into the message as a typed vector of fixed size.
261    * @param value [LongArray]
262    * @return position in buffer as the start of byte array
263    */
putnull264   public fun put(value: LongArray): Int = set(null, value)
265 
266   /**
267    * Adds a [LongArray] into the message as a typed vector of fixed size.
268    * A key must be present if element is inserted into a map.
269    * @param value [LongArray]
270    * @return position in buffer as the start of byte array
271    */
272   public operator fun set(key: String? = null, value: LongArray): Int =
273     setTypedVector(key, value.size, T_VECTOR_INT, value.widthInUBits()) { writeIntArray(value, it) }
274 
275   /**
276    * Adds a [FloatArray] into the message as a typed vector of fixed size.
277    * @param value [FloatArray]
278    * @return position in buffer as the start of byte array
279    */
putnull280   public fun put(value: FloatArray): Int = set(null, value)
281 
282   /**
283    * Adds a [FloatArray] into the message as a typed vector of fixed size.
284    * A key must be present if element is inserted into a map.
285    * @param value [FloatArray]
286    * @return position in buffer as the start of byte array
287    */
288   public operator fun set(key: String? = null, value: FloatArray): Int =
289     setTypedVector(key, value.size, T_VECTOR_FLOAT, W_32) { writeFloatArray(value) }
290 
291   /**
292    * Adds a [DoubleArray] into the message as a typed vector of fixed size.
293    * @param value [DoubleArray]
294    * @return position in buffer as the start of byte array
295    */
putnull296   public fun put(value: DoubleArray): Int = set(null, value)
297 
298   /**
299    * Adds a [DoubleArray] into the message as a typed vector of fixed size.
300    * A key must be present if element is inserted into a map.
301    * @param value [DoubleArray]
302    * @return position in buffer as the start of byte array
303    */
304   public operator fun set(key: String? = null, value: DoubleArray): Int =
305     setTypedVector(key, value.size, T_VECTOR_FLOAT, W_64) { writeFloatArray(value) }
306 
307   /**
308    * Adds a [UByteArray] into the message as a typed vector of fixed size.
309    * @param value [UByteArray]
310    * @return position in buffer as the start of byte array
311    */
putnull312   public fun put(value: UByteArray): Int = set(null, value)
313 
314   /**
315    * Adds a [UByteArray] into the message as a typed vector of fixed size.
316    * A key must be present if element is inserted into a map.
317    * @param value [UByteArray]
318    * @return position in buffer as the start of byte array
319    */
320   public operator fun set(key: String? = null, value: UByteArray): Int =
321     setTypedVec(key) { value.forEach { put(it) } }
322 
323   /**
324    * Adds a [UShortArray] into the message as a typed vector of fixed size.
325    * @param value [UShortArray]
326    * @return position in buffer as the start of byte array
327    */
putnull328   public fun put(value: UShortArray): Int = set(null, value)
329 
330   /**
331    * Adds a [UShortArray] into the message as a typed vector of fixed size.
332    * A key must be present if element is inserted into a map.
333    * @param value [UShortArray]
334    * @return position in buffer as the start of byte array
335    */
336   public operator fun set(key: String? = null, value: UShortArray): Int =
337     setTypedVec(key) { value.forEach { put(it) } }
338 
339   /**
340    * Adds a [UIntArray] into the message as a typed vector of fixed size.
341    * @param value [UIntArray]
342    * @return position in buffer as the start of byte array
343    */
putnull344   public fun put(value: UIntArray): Int = set(null, value)
345 
346   /**
347    * Adds a [UIntArray] into the message as a typed vector of fixed size.
348    * A key must be present if element is inserted into a map.
349    * @param value [UIntArray]
350    * @return position in buffer as the start of byte array
351    */
352   public fun set(key: String? = null, value: UIntArray): Int =
353     setTypedVec(key) { value.forEach { put(it) } }
354 
355   /**
356    * Adds a [ULongArray] into the message as a typed vector of fixed size.
357    * @param value [ULongArray]
358    * @return position in buffer as the start of byte array
359    */
putnull360   public fun put(value: ULongArray): Int = set(null, value)
361 
362   /**
363    * Adds a [ULongArray] into the message as a typed vector of fixed size.
364    * A key must be present if element is inserted into a map.
365    * @param value [ULongArray]
366    * @return position in buffer as the start of byte array
367    */
368   public operator fun set(key: String? = null, value: ULongArray): Int =
369     setTypedVec(key) { value.forEach { put(it) } }
370 
371   /**
372    * Creates a new vector will all elements inserted in [block].
373    * @param block where elements will be inserted
374    * @return position in buffer as the start of byte array
375    */
putVectornull376   public inline fun putVector(crossinline block: FlexBuffersBuilder.() -> Unit): Int {
377     val pos = startVector()
378     this.block()
379     return endVector(pos)
380   }
381 
382   /**
383    * Creates a new typed vector will all elements inserted in [block].
384    * @param block where elements will be inserted
385    * @return position in buffer as the start of byte array
386    */
putTypedVectornull387   public inline fun putTypedVector(crossinline block: FlexBuffersBuilder.() -> Unit): Int {
388     val pos = startVector()
389     this.block()
390     return endTypedVector(pos)
391   }
392 
393   /**
394    * Helper function to return position for starting a new vector.
395    */
startVectornull396   public fun startVector(): Int = stack.size
397 
398   /**
399    * Finishes a vector element. The initial position of the vector must be passed
400    * @param position position at the start of the vector
401    */
402   public fun endVector(position: Int): Int = endVector(null, position)
403 
404   /**
405    * Finishes a vector element. The initial position of the vector must be passed
406    * @param position position at the start of the vector
407    */
408   public fun endVector(key: String? = null, position: Int): Int =
409     endAnyVector(position) { createVector(putKey(key), position, stack.size - position) }
410   /**
411    * Finishes a typed vector element. The initial position of the vector must be passed
412    * @param position position at the start of the vector
413    */
endTypedVectornull414   public fun endTypedVector(position: Int): Int = endTypedVector(position, null)
415 
416   /**
417    * Helper function to return position for starting a new vector.
418    */
419   public fun startMap(): Int = stack.size
420 
421   /**
422    * Creates a new map will all elements inserted in [block].
423    * @param block where elements will be inserted
424    * @return position in buffer as the start of byte array
425    */
426   public inline fun putMap(key: String? = null, crossinline block: FlexBuffersBuilder.() -> Unit): Int {
427     val pos = startMap()
428     this.block()
429     return endMap(pos, key)
430   }
431 
432   /**
433    * Finishes a map, but writing the information in the buffer
434    * @param key   key used to store element in map
435    * @return Reference to the map
436    */
endMapnull437   public fun endMap(start: Int, key: String? = null): Int {
438     stack.subList(start, stack.size).sortWith(keyComparator)
439     val length = stack.size - start
440     val keys = createKeyVector(start, length)
441     val vec = putMap(putKey(key), start, length, keys)
442     // Remove temp elements and return map.
443     while (stack.size > start) {
444       stack.removeAt(stack.size - 1)
445     }
446     stack.add(vec)
447     return vec.iValue.toInt()
448   }
449 
setTypedVectornull450   private inline fun setTypedVector(
451     key: String? = null,
452     length: Int,
453     vecType: FlexBufferType,
454     bitWidth: BitWidth,
455     crossinline writeBlock: (ByteWidth) -> Unit
456   ): Int {
457     val keyPos = putKey(key)
458     val byteWidth = align(bitWidth)
459     // Write vector. First the keys width/offset if available, and size.
460     // write the size
461     writeInt(length, byteWidth)
462 
463     // Then the actual data.
464     val vloc: Int = buffer.writePosition
465     writeBlock(byteWidth)
466     stack.add(Value(vecType, keyPos, bitWidth, vloc.toULong()))
467     return vloc
468   }
469 
setTypedVecnull470   private inline fun setTypedVec(key: String? = null, crossinline block: FlexBuffersBuilder.() -> Unit): Int {
471     val pos = startVector()
472     this.block()
473     return endTypedVector(pos, key)
474   }
475 
endTypedVectornull476   public fun endTypedVector(position: Int, key: String? = null): Int =
477     endAnyVector(position) { createTypedVector(putKey(key), position, stack.size - position) }
478 
endAnyVectornull479   private inline fun endAnyVector(start: Int, crossinline creationBlock: () -> Value): Int {
480     val vec = creationBlock()
481     // Remove temp elements and return vector.
482     while (stack.size > start) {
483       stack.removeLast()
484     }
485     stack.add(vec)
486     return vec.iValue.toInt()
487   }
488 
putKeynull489   private inline fun putKey(key: String? = null): Int {
490     if (key == null) return -1
491     return if ((shareFlag and SHARE_KEYS) != 0) {
492       stringKeyPool.getOrPut(key) {
493         val pos: Int = buffer.writePosition
494         buffer.put(key)
495         buffer.put(ZeroByte)
496         pos
497       }
498     } else {
499       val pos: Int = buffer.writePosition
500       buffer.put(key)
501       buffer.put(ZeroByte)
502       pos
503     }
504   }
505 
writeAnynull506   private fun writeAny(toWrite: Value, byteWidth: ByteWidth) = when (toWrite.type) {
507     T_NULL, T_BOOL, T_INT, T_UINT -> writeInt(toWrite.iValue, byteWidth)
508     T_FLOAT -> writeDouble(toWrite.dValue, byteWidth)
509     else -> writeOffset(toWrite.iValue.toInt(), byteWidth)
510   }
511 
writeStringnull512   private fun writeString(key: Int, s: String): Value {
513     val size = Utf8.encodedLength(s)
514     val bitWidth = size.toULong().widthInUBits()
515     val byteWidth = align(bitWidth)
516 
517     writeInt(size, byteWidth)
518 
519     val sloc: Int = buffer.writePosition
520     if (size > 0)
521       buffer.put(s, size)
522     buffer.put(ZeroByte)
523     return Value(T_STRING, key, bitWidth, sloc.toULong())
524   }
525 
writeDoublenull526   private fun writeDouble(toWrite: Double, byteWidth: ByteWidth): Unit = when (byteWidth.value) {
527     4 -> buffer.put(toWrite.toFloat())
528     8 -> buffer.put(toWrite)
529     else -> Unit
530   }
531 
writeOffsetnull532   private fun writeOffset(toWrite: Int, byteWidth: ByteWidth) {
533     val relativeOffset = (buffer.writePosition - toWrite)
534     if (byteWidth.value != 8 && relativeOffset >= 1L shl byteWidth.value * 8) error("invalid offset $relativeOffset, writer pos ${buffer.writePosition}")
535     writeInt(relativeOffset, byteWidth)
536   }
537 
writeBlobnull538   private inline fun writeBlob(key: Int, blob: ByteArray, type: FlexBufferType, trailing: Boolean): Value {
539     val bitWidth = blob.size.toULong().widthInUBits()
540     val byteWidth = align(bitWidth)
541 
542     writeInt(blob.size, byteWidth)
543 
544     val sloc: Int = buffer.writePosition
545     buffer.put(blob, 0, blob.size)
546     if (trailing) {
547       buffer.put(ZeroByte)
548     }
549     return Value(type, key, bitWidth, sloc.toULong())
550   }
551 
writeIntArraynull552   private fun writeIntArray(value: IntArray, byteWidth: ByteWidth) =
553     writeIntegerArray(0, value.size, byteWidth) { value[it].toULong() }
554 
writeIntArraynull555   private fun writeIntArray(value: ShortArray, byteWidth: ByteWidth) =
556     writeIntegerArray(0, value.size, byteWidth) { value[it].toULong() }
557 
writeIntArraynull558   private fun writeIntArray(value: LongArray, byteWidth: ByteWidth) =
559     writeIntegerArray(0, value.size, byteWidth) { value[it].toULong() }
560 
writeFloatArraynull561   private fun writeFloatArray(value: FloatArray) {
562     val byteWidth = Float.SIZE_BYTES
563     // since we know we are writing an array, we can avoid multiple copy/growth of the buffer by requesting
564     // the right size on the spot
565     buffer.requestCapacity(buffer.writePosition + (value.size * byteWidth))
566     value.forEach { buffer.put(it) }
567   }
568 
writeFloatArraynull569   private fun writeFloatArray(value: DoubleArray) {
570     val byteWidth = Double.SIZE_BYTES
571     // since we know we are writing an array, we can avoid multiple copy/growth of the buffer by requesting
572     // the right size on the spot
573     buffer.requestCapacity(buffer.writePosition + (value.size * byteWidth))
574     value.forEach { buffer.put(it) }
575   }
576 
writeIntegerArraynull577   private inline fun writeIntegerArray(
578     start: Int,
579     size: Int,
580     byteWidth: ByteWidth,
581     crossinline valueBlock: (Int) -> ULong
582   ) {
583     // since we know we are writing an array, we can avoid multiple copy/growth of the buffer by requesting
584     // the right size on the spot
585     buffer.requestCapacity(buffer.writePosition + (size * byteWidth))
586     return when (byteWidth.value) {
587       1 -> for (i in start until start + size) {
588         buffer.put(valueBlock(i).toUByte())
589       }
590       2 -> for (i in start until start + size) {
591         buffer.put(valueBlock(i).toUShort())
592       }
593       4 -> for (i in start until start + size) {
594         buffer.put(valueBlock(i).toUInt())
595       }
596       8 -> for (i in start until start + size) {
597         buffer.put(valueBlock(i))
598       }
599       else -> Unit
600     }
601   }
602 
writeIntnull603   private fun writeInt(value: Int, byteWidth: ByteWidth) = when (byteWidth.value) {
604     1 -> buffer.put(value.toUByte())
605     2 -> buffer.put(value.toUShort())
606     4 -> buffer.put(value.toUInt())
607     8 -> buffer.put(value.toULong())
608     else -> Unit
609   }
610 
writeIntnull611   private fun writeInt(value: ULong, byteWidth: ByteWidth) = when (byteWidth.value) {
612     1 -> buffer.put(value.toUByte())
613     2 -> buffer.put(value.toUShort())
614     4 -> buffer.put(value.toUInt())
615     8 -> buffer.put(value)
616     else -> Unit
617   }
618 
619   // Align to prepare for writing a scalar with a certain size.
620   // returns the amounts of bytes needed to be written.
alignnull621   private fun align(alignment: BitWidth): ByteWidth {
622     val byteWidth = 1 shl alignment.value
623     var padBytes = paddingBytes(buffer.writePosition, byteWidth)
624     while (padBytes-- != 0) {
625       buffer.put(ZeroByte)
626     }
627     return ByteWidth(byteWidth)
628   }
629 
calculateKeyVectorBitWidthnull630   private fun calculateKeyVectorBitWidth(start: Int, length: Int): BitWidth {
631     val bitWidth = length.toULong().widthInUBits()
632     var width = bitWidth
633     val prefixElems = 1
634     // Check bit widths and types for all elements.
635     for (i in start until stack.size) {
636       val elemWidth = elemWidth(T_KEY, W_8, stack[i].key.toLong(), buffer.writePosition, i + prefixElems)
637       width = width.max(elemWidth)
638     }
639     return width
640   }
641 
createKeyVectornull642   private fun createKeyVector(start: Int, length: Int): Value {
643     // Figure out smallest bit width we can store this vector with.
644     val bitWidth = calculateKeyVectorBitWidth(start, length)
645     val byteWidth = align(bitWidth)
646     // Write vector. First the keys width/offset if available, and size.
647     writeInt(length, byteWidth)
648     // Then the actual data.
649     val vloc = buffer.writePosition.toULong()
650     for (i in start until stack.size) {
651       val pos = stack[i].key
652       if (pos == -1) error("invalid position $pos for key")
653       writeOffset(stack[i].key, byteWidth)
654     }
655     // Then the types.
656     return Value(T_VECTOR_KEY, -1, bitWidth, vloc)
657   }
658 
createVectornull659   private inline fun createVector(key: Int, start: Int, length: Int, keys: Value? = null): Value {
660     return createAnyVector(key, start, length, T_VECTOR, keys) {
661       // add types since we are not creating a typed vector.
662       for (i in start until stack.size) {
663         buffer.put(stack[i].storedPackedType(it))
664       }
665     }
666   }
667 
putMapnull668   private fun putMap(key: Int, start: Int, length: Int, keys: Value? = null): Value {
669     return createAnyVector(key, start, length, T_MAP, keys) {
670       // add types since we are not creating a typed vector.
671       for (i in start until stack.size) {
672         buffer.put(stack[i].storedPackedType(it))
673       }
674     }
675   }
676 
createTypedVectornull677   private inline fun createTypedVector(key: Int, start: Int, length: Int, keys: Value? = null): Value {
678     // We assume the callers of this method guarantees all elements are of the same type.
679     val elementType: FlexBufferType = stack[start].type
680     for (i in start + 1 until length) {
681       if (elementType != stack[i].type) error("TypedVector does not support array of different element types")
682     }
683     if (!elementType.isTypedVectorElementType()) error("TypedVector does not support this element type")
684     return createAnyVector(key, start, length, elementType.toTypedVector(), keys)
685   }
686 
createAnyVectornull687   private inline fun createAnyVector(
688     key: Int,
689     start: Int,
690     length: Int,
691     type: FlexBufferType,
692     keys: Value? = null,
693     crossinline typeBlock: (BitWidth) -> Unit = {}
694   ): Value {
695     // Figure out smallest bit width we can store this vector with.
696     var bitWidth = W_8.max(length.toULong().widthInUBits())
697     var prefixElems = 1
698     if (keys != null) {
699       // If this vector is part of a map, we will pre-fix an offset to the keys
700       // to this vector.
701       bitWidth = bitWidth.max(keys.elemWidth(buffer.writePosition, 0))
702       prefixElems += 2
703     }
704     // Check bit widths and types for all elements.
705     for (i in start until stack.size) {
706       val elemWidth = stack[i].elemWidth(buffer.writePosition, i + prefixElems)
707       bitWidth = bitWidth.max(elemWidth)
708     }
709     val byteWidth = align(bitWidth)
710     // Write vector. First the keys width/offset if available, and size.
711     if (keys != null) {
712       writeOffset(keys.iValue.toInt(), byteWidth)
713       writeInt(1 shl keys.minBitWidth.value, byteWidth)
714     }
715     // write the size
716     writeInt(length, byteWidth)
717 
718     // Then the actual data.
719     val vloc: Int = buffer.writePosition
720     for (i in start until stack.size) {
721       writeAny(stack[i], byteWidth)
722     }
723 
724     // Optionally you can introduce the types for non-typed vector
725     typeBlock(bitWidth)
726     return Value(type, key, bitWidth, vloc.toULong())
727   }
728 
729   // A lambda to sort map keys
730   internal val keyComparator = object : Comparator<Value> {
comparenull731     override fun compare(a: Value, b: Value): Int {
732       var ia: Int = a.key
733       var io: Int = b.key
734       var c1: Byte
735       var c2: Byte
736       do {
737         c1 = buffer[ia]
738         c2 = buffer[io]
739         if (c1.toInt() == 0) return c1 - c2
740         ia++
741         io++
742       } while (c1 == c2)
743       return c1 - c2
744     }
745   }
746 
747   public companion object {
748     /**
749      * No keys or strings will be shared
750      */
751     public const val SHARE_NONE: Int = 0
752 
753     /**
754      * Keys will be shared between elements. Identical keys will only be serialized once, thus possibly saving space.
755      * But serialization performance might be slower and consumes more memory.
756      */
757     public const val SHARE_KEYS: Int = 1
758 
759     /**
760      * Strings will be shared between elements. Identical strings will only be serialized once, thus possibly saving space.
761      * But serialization performance might be slower and consumes more memory. This is ideal if you expect many repeated
762      * strings on the message.
763      */
764     public const val SHARE_STRINGS: Int = 2
765 
766     /**
767      * Strings and keys will be shared between elements.
768      */
769     public const val SHARE_KEYS_AND_STRINGS: Int = 3
770   }
771 }
772