ByteUtilities/src/dorkbox/bytes/ByteBufInput.kt

933 lines
32 KiB
Kotlin

/*
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.bytes
import com.esotericsoftware.kryo.KryoException
import com.esotericsoftware.kryo.io.Input
import com.esotericsoftware.kryo.util.Util
import io.netty.buffer.ByteBuf
import io.netty.buffer.Unpooled
import java.io.IOException
import java.io.InputStream
/**
* An [InputStream] which reads data from a [ByteBuf].
*
*
* A read operation against this stream will occur at the `readerIndex`
* of its underlying buffer and the `readerIndex` will increase during
* the read operation.
*
*
* This stream implements [DataInput] for your convenience.
* The endianness of the stream is not always big endian but depends on
* the endianness of the underlying buffer.
*
*
* Utility methods are provided for efficiently reading primitive types and strings.
*
*
* Modified from KRYO ByteBufferInput to use ByteBuf instead of ByteBuffer.
*/
@Suppress("NAME_SHADOWING")
class ByteBufInput : Input {
companion object {
/**
* Gets the version number.
*/
const val version = BytesInfo.version
}
lateinit var byteBuf: ByteBuf
private set
private var initialReaderIndex = 0
private var initialWriterIndex = 0
private var tempBuffer: ByteArray? = null
/**
* Creates a new Input for reading from a direct [ByteBuf].
*
* @param bufferSize The size of the buffer. An exception is thrown if more bytes than this are read and
* [.fill] does not supply more bytes.
*/
constructor(bufferSize: Int) {
capacity = bufferSize
byteBuf = Unpooled.buffer(bufferSize)
}
/**
* Creates a new Input for reading from a [ByteBuf] which is filled with the specified bytes.
*
* @see .setBuffer
*/
constructor(bytes: ByteArray, offset: Int = 0, count: Int = bytes.size) {
setBuffer(Unpooled.wrappedBuffer(bytes, offset, count))
}
/**
* Creates a new Input for reading from a ByteBuffer.
*/
constructor(buffer: ByteBuf) {
setBuffer(buffer)
}
/**
* @see Input.Input
*/
constructor(inputStream: InputStream) : this(4096) {
this.inputStream = inputStream
}
/**
* @see Input.Input
*/
constructor(inputStream: InputStream, bufferSize: Int) : this(bufferSize) {
this.inputStream = inputStream
}
/**
* Throws [UnsupportedOperationException] because this input uses a ByteBuffer, not a byte[].
*
* @see .getByteBuf
*/
@Deprecated("Use getByteBuf() instead",
ReplaceWith("getByteBuf()")
)
override fun getBuffer(): ByteArray {
throw UnsupportedOperationException("This input does not used a byte[], see #getByteBuf().")
}
/**
* Throws [UnsupportedOperationException] because this input uses a ByteBuffer, not a byte[].
*
* @see .setBuffer
*/
@Deprecated("Use setByteBuf() instead",
ReplaceWith("setBuffer(ByteBuf)")
)
override fun setBuffer(bytes: ByteArray) {
throw UnsupportedOperationException("This input does not used a byte[], see #setBuffer(ByteBuf).")
}
/**
* Throws [UnsupportedOperationException] because this input uses a ByteBuffer, not a byte[].
*
* @see .setBuffer
*/
@Deprecated("This input does not used a byte[], see #setByteBuf().",
ReplaceWith("setBuffer(ByteBuf)")
)
override fun setBuffer(bytes: ByteArray, offset: Int, count: Int) {
throw UnsupportedOperationException("This input does not used a byte[], see #setBuffer().")
}
/**
* Sets a new buffer to read from. The bytes are not copied, the old buffer is discarded and the new buffer used in its place.
*
* The position, limit, and capacity are set to match the specified buffer. The total is reset. The
* [InputStream][.setInputStream] is set to null.
*/
fun setBuffer(buffer: ByteBuf) {
byteBuf = buffer
initialReaderIndex = byteBuf.readerIndex() // where the object starts...
initialWriterIndex = byteBuf.writerIndex() // where the object ends...
position = initialReaderIndex
limit = initialWriterIndex
capacity = buffer.capacity()
total = 0
inputStream = null
}
override fun setInputStream(inputStream: InputStream) {
this.inputStream = inputStream
limit = 0
reset()
}
override fun reset() {
super.reset()
byteBuf.setIndex(initialReaderIndex, initialWriterIndex)
}
/** Fills the buffer with more bytes. The default implementation reads from the [InputStream][.getInputStream], if set.
* Can be overridden to fill the bytes from another source. */
@Throws(KryoException::class)
protected fun fill(buffer: ByteBuf?, offset: Int, count: Int): Int {
var count = count
return if (inputStream == null) -1 else try {
if (tempBuffer == null) tempBuffer = ByteArray(2048)
buffer!!.readerIndex(offset)
var total = 0
while (count > 0) {
val read = inputStream.read(tempBuffer, 0, Math.min(tempBuffer!!.size, count))
if (read == -1) {
if (total == 0) return -1
break
}
buffer.writeBytes(tempBuffer, 0, read)
count -= read
total += read
}
buffer.readerIndex(offset)
total
} catch (ex: IOException) {
throw KryoException(ex)
}
}
@Throws(KryoException::class)
override fun require(required: Int): Int {
var remaining = limit - position
if (remaining >= required) return remaining
if (required > capacity) throw KryoException("Buffer too small: capacity: $capacity, required: $required")
val count: Int
// Try to fill the buffer.
if (remaining > 0) {
count = fill(byteBuf, limit, capacity - limit)
if (count == -1) throw KryoException("Buffer underflow.")
remaining += count
if (remaining >= required) {
limit += count
return remaining
}
}
// Compact. Position after compaction can be non-zero.
// CANNOT COMPACT A BYTEBUF
// byteBuffer.position(position);
// byteBuffer.compact();
// total += position;
// position = 0;
//
// while (true) {
// count = fill(byteBuffer, remaining, capacity - remaining);
// if (count == -1) {
// if (remaining >= required) break;
// throw new KryoException("Buffer underflow.");
// }
// remaining += count;
// if (remaining >= required) break; // Enough has been read.
// }
// limit = remaining;
// byteBuffer.position(0);
return remaining
}
/** Fills the buffer with at least the number of bytes specified, if possible.
* @param optional Must be > 0.
* @return the number of bytes remaining, but not more than optional, or -1 if [.fill] is unable to
* provide more bytes.
*/
@Throws(KryoException::class)
override fun optional(optional: Int): Int {
var optional = optional
var remaining = limit - position
if (remaining >= optional) return optional
optional = Math.min(optional, capacity)
// Try to fill the buffer.
val count = fill(byteBuf, limit, capacity - limit)
if (count == -1) return if (remaining == 0) -1 else Math.min(remaining, optional)
remaining += count
if (remaining >= optional) {
limit += count
return optional
}
// Compact.
// CANNOT COMPACT A BYTEBUF
// byteBuffer.compact();
// total += position;
// position = 0;
//
// while (true) {
// count = fill(byteBuffer, remaining, capacity - remaining);
// if (count == -1) break;
// remaining += count;
// if (remaining >= optional) break; // Enough has been read.
// }
// limit = remaining;
// byteBuffer.position(position);
return if (remaining == 0) -1 else Math.min(remaining, optional)
}
// InputStream:
@Throws(KryoException::class)
override fun read(): Int {
if (optional(1) <= 0) return -1
position++
return byteBuf.readByte().toInt() and 0xFF
}
@Throws(KryoException::class)
override fun read(bytes: ByteArray): Int {
return read(bytes, 0, bytes.size)
}
@Throws(KryoException::class)
override fun read(bytes: ByteArray, offset: Int, count: Int): Int {
var offset = offset
var count = count
requireNotNull(bytes) { "bytes cannot be null." }
val startingCount = count
var copyCount = Math.min(limit - position, count)
while (true) {
byteBuf.getBytes(position, bytes, offset, copyCount)
position += copyCount
count -= copyCount
if (count == 0) break
offset += copyCount
copyCount = optional(count)
if (copyCount == -1) {
// End of data.
if (startingCount == count) return -1
break
}
if (position == limit) break
}
return startingCount - count
}
override fun setPosition(position: Int) {
this.position = position
byteBuf.readerIndex(position)
}
override fun setLimit(limit: Int) {
this.limit = limit
byteBuf.writerIndex(limit)
}
@Throws(KryoException::class)
override fun skip(count: Int) {
super.skip(count)
byteBuf.readerIndex(position)
}
@Throws(KryoException::class)
override fun skip(count: Long): Long {
var remaining = count
while (remaining > 0) {
val skip = Math.min(Util.maxArraySize.toLong(), remaining).toInt()
skip(skip)
remaining -= skip.toLong()
}
return count
}
@Throws(KryoException::class)
override fun close() {
if (inputStream != null) {
try {
inputStream.close()
} catch (ignored: IOException) {
}
}
}
// byte:
@Throws(KryoException::class)
override fun readByte(): Byte {
if (position == limit) require(1)
position++
return byteBuf.readByte()
}
@Throws(KryoException::class)
override fun readByteUnsigned(): Int {
if (position == limit) require(1)
position++
return byteBuf.readByte().toInt() and 0xFF
}
@Throws(KryoException::class)
override fun readBytes(length: Int): ByteArray {
val bytes = ByteArray(length)
readBytes(bytes, 0, length)
return bytes
}
@Throws(KryoException::class)
override fun readBytes(bytes: ByteArray, offset: Int, count: Int) {
var offset = offset
var count = count
requireNotNull(bytes) { "bytes cannot be null." }
var copyCount = Math.min(limit - position, count)
while (true) {
byteBuf.readBytes(bytes, offset, copyCount)
position += copyCount
count -= copyCount
if (count == 0) break
offset += copyCount
copyCount = Math.min(count, capacity)
require(copyCount)
}
}
// int:
@Throws(KryoException::class)
override fun readInt(): Int {
require(4)
position += 4
return byteBuf.readInt()
}
@Throws(KryoException::class)
override fun readVarInt(optimizePositive: Boolean): Int {
if (require(1) < 5) return readVarInt_slow(optimizePositive)
val byteBuf = byteBuf
var b = byteBuf.readByte().toInt()
var result = b and 0x7F
if (b and 0x80 != 0) {
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 7)
if (b and 0x80 != 0) {
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 14)
if (b and 0x80 != 0) {
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 21)
if (b and 0x80 != 0) {
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 28)
}
}
}
}
position = byteBuf.readerIndex()
return if (optimizePositive) result else result ushr 1 xor -(result and 1)
}
private fun readVarInt_slow(optimizePositive: Boolean): Int {
// The buffer is guaranteed to have at least 1 byte.
position++
val byteBuf = byteBuf
var b = byteBuf.readByte().toInt()
var result = b and 0x7F
if (b and 0x80 != 0) {
if (position == limit) require(1)
position++
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 7)
if (b and 0x80 != 0) {
if (position == limit) require(1)
position++
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 14)
if (b and 0x80 != 0) {
if (position == limit) require(1)
position++
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 21)
if (b and 0x80 != 0) {
if (position == limit) require(1)
position++
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 28)
}
}
}
}
return if (optimizePositive) result else result ushr 1 xor -(result and 1)
}
@Throws(KryoException::class)
override fun canReadVarInt(): Boolean {
if (limit - position >= 5) return true
if (optional(5) <= 0) return false
var p = position
val limit = limit
val byteBuf = byteBuf
if (byteBuf.getByte(p++).toInt() and 0x80 == 0) return true
if (p == limit) return false
if (byteBuf.getByte(p++).toInt() and 0x80 == 0) return true
if (p == limit) return false
if (byteBuf.getByte(p++).toInt() and 0x80 == 0) return true
if (p == limit) return false
if (byteBuf.getByte(p++).toInt() and 0x80 == 0) return true
return if (p == limit) false else true
}
/** Reads the boolean part of a varint flag. The position is not advanced, [.readVarIntFlag] should be used to
* advance the position. */
override fun readVarIntFlag(): Boolean {
if (position == limit) require(1)
return byteBuf.getByte(position).toInt() and 0x80 != 0
}
/** Reads the 1-5 byte int part of a varint flag. The position is advanced so if the boolean part is needed it should be read
* first with [.readVarIntFlag]. */
override fun readVarIntFlag(optimizePositive: Boolean): Int {
if (require(1) < 5) return readVarIntFlag_slow(optimizePositive)
val byteBuf = byteBuf
var b = byteBuf.readByte().toInt()
var result = b and 0x3F // Mask first 6 bits.
if (b and 0x40 != 0) { // Bit 7 means another byte, bit 8 means UTF8.
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 6)
if (b and 0x80 != 0) {
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 13)
if (b and 0x80 != 0) {
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 20)
if (b and 0x80 != 0) {
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 27)
}
}
}
}
position = byteBuf.readerIndex()
return if (optimizePositive) result else result ushr 1 xor -(result and 1)
}
private fun readVarIntFlag_slow(optimizePositive: Boolean): Int {
// The buffer is guaranteed to have at least 1 byte.
position++
var b = byteBuf.readByte().toInt()
var result = b and 0x3F
if (b and 0x40 != 0) {
if (position == limit) require(1)
position++
val byteBuf = byteBuf
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 6)
if (b and 0x80 != 0) {
if (position == limit) require(1)
position++
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 13)
if (b and 0x80 != 0) {
if (position == limit) require(1)
position++
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 20)
if (b and 0x80 != 0) {
if (position == limit) require(1)
position++
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 27)
}
}
}
}
return if (optimizePositive) result else result ushr 1 xor -(result and 1)
}
// long:
@Throws(KryoException::class)
override fun readLong(): Long {
require(8)
position += 8
return byteBuf.readLong()
}
@Throws(KryoException::class)
override fun readVarLong(optimizePositive: Boolean): Long {
if (require(1) < 9) return readVarLong_slow(optimizePositive)
val byteBuf = byteBuf
var b = byteBuf.readByte().toInt()
var result = (b and 0x7F).toLong()
if (b and 0x80 != 0) {
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 7).toLong()
if (b and 0x80 != 0) {
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 14).toLong()
if (b and 0x80 != 0) {
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 21).toLong()
if (b and 0x80 != 0) {
b = byteBuf.readByte().toInt()
result = result or ((b and 0x7F).toLong() shl 28)
if (b and 0x80 != 0) {
b = byteBuf.readByte().toInt()
result = result or ((b and 0x7F).toLong() shl 35)
if (b and 0x80 != 0) {
b = byteBuf.readByte().toInt()
result = result or ((b and 0x7F).toLong() shl 42)
if (b and 0x80 != 0) {
b = byteBuf.readByte().toInt()
result = result or ((b and 0x7F).toLong() shl 49)
if (b and 0x80 != 0) {
b = byteBuf.readByte().toInt()
result = result or (b.toLong() shl 56)
}
}
}
}
}
}
}
}
position = byteBuf.readerIndex()
return if (optimizePositive) result else result ushr 1 xor -(result and 1)
}
private fun readVarLong_slow(optimizePositive: Boolean): Long {
// The buffer is guaranteed to have at least 1 byte.
position++
val byteBuf = byteBuf
var b = byteBuf.readByte().toInt()
var result = (b and 0x7F).toLong()
if (b and 0x80 != 0) {
if (position == limit) require(1)
position++
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 7).toLong()
if (b and 0x80 != 0) {
if (position == limit) require(1)
position++
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 14).toLong()
if (b and 0x80 != 0) {
if (position == limit) require(1)
position++
b = byteBuf.readByte().toInt()
result = result or (b and 0x7F shl 21).toLong()
if (b and 0x80 != 0) {
if (position == limit) require(1)
position++
b = byteBuf.readByte().toInt()
result = result or ((b and 0x7F).toLong() shl 28)
if (b and 0x80 != 0) {
if (position == limit) require(1)
position++
b = byteBuf.readByte().toInt()
result = result or ((b and 0x7F).toLong() shl 35)
if (b and 0x80 != 0) {
if (position == limit) require(1)
position++
b = byteBuf.readByte().toInt()
result = result or ((b and 0x7F).toLong() shl 42)
if (b and 0x80 != 0) {
if (position == limit) require(1)
position++
b = byteBuf.readByte().toInt()
result = result or ((b and 0x7F).toLong() shl 49)
if (b and 0x80 != 0) {
if (position == limit) require(1)
position++
b = byteBuf.readByte().toInt()
result = result or (b.toLong() shl 56)
}
}
}
}
}
}
}
}
return if (optimizePositive) result else result ushr 1 xor -(result and 1)
}
@Throws(KryoException::class)
override fun canReadVarLong(): Boolean {
if (limit - position >= 9) return true
if (optional(5) <= 0) return false
var p = position
val limit = limit
val byteBuf = byteBuf
if (byteBuf.getByte(p++).toInt() and 0x80 == 0) return true
if (p == limit) return false
if (byteBuf.getByte(p++).toInt() and 0x80 == 0) return true
if (p == limit) return false
if (byteBuf.getByte(p++).toInt() and 0x80 == 0) return true
if (p == limit) return false
if (byteBuf.getByte(p++).toInt() and 0x80 == 0) return true
if (p == limit) return false
if (byteBuf.getByte(p++).toInt() and 0x80 == 0) return true
if (p == limit) return false
if (byteBuf.getByte(p++).toInt() and 0x80 == 0) return true
if (p == limit) return false
if (byteBuf.getByte(p++).toInt() and 0x80 == 0) return true
if (p == limit) return false
if (byteBuf.getByte(p++).toInt() and 0x80 == 0) return true
return if (p == limit) false else true
}
// float:
@Throws(KryoException::class)
override fun readFloat(): Float {
require(4)
val p = position
position = p + 4
return byteBuf.readFloat()
}
// double:
@Throws(KryoException::class)
override fun readDouble(): Double {
require(8)
val p = position
position = p + 8
return byteBuf.readDouble()
}
// boolean:
@Throws(KryoException::class)
override fun readBoolean(): Boolean {
if (position == limit) require(1)
position++
return if (byteBuf.readByte().toInt() == 1) true else false
}
// short:
@Throws(KryoException::class)
override fun readShort(): Short {
require(2)
position += 2
return byteBuf.readShort()
}
@Throws(KryoException::class)
override fun readShortUnsigned(): Int {
require(2)
position += 2
return byteBuf.readUnsignedShort()
}
// char:
@Throws(KryoException::class)
override fun readChar(): Char {
require(2)
position += 2
return byteBuf.readChar()
}
// String:
override fun readString(): String? {
if (!readVarIntFlag()) return readAsciiString() // ASCII.
// Null, empty, or UTF8.
var charCount = readVarIntFlag(true)
when (charCount) {
0 -> return null
1 -> return ""
}
charCount-- // make count adjustment
readUtf8Chars(charCount)
return String(chars, 0, charCount)
}
override fun readStringBuilder(): StringBuilder? {
if (!readVarIntFlag()) return StringBuilder(readAsciiString()) // ASCII.
// Null, empty, or UTF8.
var charCount = readVarIntFlag(true)
when (charCount) {
0 -> return null
1 -> return StringBuilder("")
}
charCount--
readUtf8Chars(charCount)
val builder = StringBuilder(charCount)
builder.append(chars, 0, charCount)
return builder
}
private fun readUtf8Chars(charCount: Int) {
if (chars.size < charCount) chars = CharArray(charCount)
val chars = chars
// Try to read 7 bit ASCII chars.
val byteBuf = byteBuf
var charIndex = 0
val count = require(1).coerceAtMost(charCount)
while (charIndex < count) {
val b = byteBuf.readByte().toInt()
if (b < 0) break
chars[charIndex++] = b.toChar()
}
position += charIndex
// If buffer didn't hold all chars or any were not ASCII, use slow path for remainder.
if (charIndex < charCount) {
byteBuf.readerIndex(position)
readUtf8Chars_slow(charCount, charIndex)
}
}
private fun readUtf8Chars_slow(charCount: Int, charIndex: Int) {
var index = charIndex
val byteBuf = byteBuf
val chars = chars
while (index < charCount) {
if (position == limit) require(1)
position++
val b: Int = byteBuf.readByte().toInt() and 0xFF
when (b shr 4) {
0, 1, 2, 3, 4, 5, 6, 7 -> chars[index] = b.toChar()
12, 13 -> {
if (position == limit) require(1)
position++
chars[index] = (b and 0x1F shl 6 or (byteBuf.readByte().toInt() and 0x3F)).toChar()
}
14 -> {
require(2)
position += 2
val b2 = byteBuf.readByte().toInt()
val b3 = byteBuf.readByte().toInt()
chars[index] = (b and 0x0F shl 12 or (b2 and 0x3F shl 6) or (b3 and 0x3F)).toChar()
}
}
index++
}
}
private fun readAsciiString(): String {
val chars = chars
val byteBuf = byteBuf
var charCount = 0
val n = Math.min(chars.size, limit - position)
while (charCount < n) {
val b = byteBuf.readByte().toInt()
if (b and 0x80 == 0x80) {
position = byteBuf.readerIndex()
chars[charCount] = (b and 0x7F).toChar()
return String(chars, 0, charCount + 1)
}
chars[charCount] = b.toChar()
charCount++
}
position = byteBuf.readerIndex()
return readAscii_slow(charCount)
}
private fun readAscii_slow(charCount: Int): String {
var charCount = charCount
var chars = chars
val byteBuf = byteBuf
while (true) {
if (position == limit) require(1)
position++
val b = byteBuf.readByte().toInt()
if (charCount == chars.size) {
val newChars = CharArray(charCount * 2)
System.arraycopy(chars, 0, newChars, 0, charCount)
chars = newChars
this.chars = newChars
}
if (b and 0x80 == 0x80) {
chars[charCount] = (b and 0x7F).toChar()
return String(chars, 0, charCount + 1)
}
chars[charCount++] = b.toChar()
}
}
// Primitive arrays:
@Throws(KryoException::class)
override fun readInts(length: Int): IntArray {
val array = IntArray(length)
if (optional(length shl 2) == length shl 2) {
val byteBuf = byteBuf
for (i in 0 until length) {
array[i] = byteBuf.readInt()
}
position = byteBuf.readerIndex()
} else {
for (i in 0 until length) array[i] = readInt()
}
return array
}
@Throws(KryoException::class)
override fun readLongs(length: Int): LongArray {
val array = LongArray(length)
if (optional(length shl 3) == length shl 3) {
val byteBuf = byteBuf
for (i in 0 until length) {
array[i] = byteBuf.readLong()
}
position = byteBuf.readerIndex()
} else {
for (i in 0 until length) array[i] = readLong()
}
return array
}
@Throws(KryoException::class)
override fun readFloats(length: Int): FloatArray {
val array = FloatArray(length)
if (optional(length shl 2) == length shl 2) {
val byteBuf = byteBuf
for (i in 0 until length) {
array[i] = byteBuf.readFloat()
}
position = byteBuf.readerIndex()
} else {
for (i in 0 until length) array[i] = readFloat()
}
return array
}
@Throws(KryoException::class)
override fun readDoubles(length: Int): DoubleArray {
val array = DoubleArray(length)
if (optional(length shl 3) == length shl 3) {
val byteBuf = byteBuf
for (i in 0 until length) {
array[i] = byteBuf.readDouble()
}
position = byteBuf.readerIndex()
} else {
for (i in 0 until length) array[i] = readDouble()
}
return array
}
@Throws(KryoException::class)
override fun readShorts(length: Int): ShortArray {
val array = ShortArray(length)
if (optional(length shl 1) == length shl 1) {
val byteBuf = byteBuf
for (i in 0 until length) array[i] = (byteBuf.readByte().toInt() and 0xFF or (byteBuf.readByte().toInt() and 0xFF shl 8)).toShort()
position = byteBuf.readerIndex()
} else {
for (i in 0 until length) array[i] = readShort()
}
return array
}
@Throws(KryoException::class)
override fun readChars(length: Int): CharArray {
val array = CharArray(length)
if (optional(length shl 1) == length shl 1) {
val byteBuf = byteBuf
for (i in 0 until length) array[i] = (byteBuf.readByte().toInt() and 0xFF or (byteBuf.readByte().toInt() and 0xFF shl 8)).toChar()
position = byteBuf.readerIndex()
} else {
for (i in 0 until length) array[i] = readChar()
}
return array
}
@Throws(KryoException::class)
override fun readBooleans(length: Int): BooleanArray {
val array = BooleanArray(length)
if (optional(length) == length) {
val byteBuf = byteBuf
for (i in 0 until length) array[i] = byteBuf.readByte().toInt() != 0
position = byteBuf.readerIndex()
} else {
for (i in 0 until length) array[i] = readBoolean()
}
return array
}
}