ByteSubArray.kt
TLDR
The ByteSubArray
class in the provided file allows for read access to a sub part of a larger array. It provides methods for reading bytes, integers, longs, and truncated longs. The file also includes extension functions for reading shorts, integers, and longs from a ByteArray
.
Classes
ByteSubArray
The ByteSubArray
class provides read access to a sub part of a larger array. It takes the following parameters in its constructor:
-
array
: The larger array from which the sub-array is created. -
rangeStart
: The start index of the sub-array in the larger array. -
size
: The size of the sub-array. -
longIdentifiers
: Boolean value indicating whether the identifiers are of typeLong
.
The class contains the following methods:
-
readByte()
: Reads and returns aByte
value from the sub-array. -
readId()
: Reads and returns anInt
value orLong
value from the sub-array, depending on the value oflongIdentifiers
. -
readInt()
: Reads and returns anInt
value from the sub-array. -
readTruncatedLong(byteCount: Int)
: Reads and returns a truncatedLong
value from the sub-array, based on the specifiedbyteCount
. -
readLong()
: Reads and returns aLong
value from the sub-array.
Extension Functions
The provided file also includes the following extension functions for the ByteArray
class:
-
readShort(index: Int)
: Reads and returns aShort
value from the specifiedindex
in the array. -
readInt(index: Int)
: Reads and returns anInt
value from the specifiedindex
in the array. -
readLong(index: Int)
: Reads and returns aLong
value from the specifiedindex
in the array.
package shark.internal
/**
* Provides read access to a sub part of a larger array.
*/
internal class ByteSubArray(
private val array: ByteArray,
private val rangeStart: Int,
size: Int,
private val longIdentifiers: Boolean
) {
private val endInclusive = size - 1
private var currentIndex = 0
fun readByte(): Byte {
val index = currentIndex
currentIndex++
require(index in 0..endInclusive) {
"Index $index should be between 0 and $endInclusive"
}
return array[rangeStart + index]
}
fun readId(): Long {
return if (longIdentifiers) {
readLong()
} else {
readInt().toLong()
}
}
fun readInt(): Int {
val index = currentIndex
currentIndex += 4
require(index >= 0 && index <= endInclusive - 3) {
"Index $index should be between 0 and ${endInclusive - 3}"
}
return array.readInt(rangeStart + index)
}
fun readTruncatedLong(byteCount: Int): Long {
val index = currentIndex
currentIndex += byteCount
require(index >= 0 && index <= endInclusive - (byteCount - 1)) {
"Index $index should be between 0 and ${endInclusive - (byteCount - 1)}"
}
var pos = rangeStart + index
val array = array
var value = 0L
var shift = (byteCount - 1) * 8
while (shift >= 8) {
value = value or (array[pos++] and 0xffL shl shift)
shift -= 8
}
value = value or (array[pos] and 0xffL)
return value
}
fun readLong(): Long {
val index = currentIndex
currentIndex += 8
require(index >= 0 && index <= endInclusive - 7) {
"Index $index should be between 0 and ${endInclusive - 7}"
}
return array.readLong(rangeStart + index)
}
}
internal fun ByteArray.readShort(index: Int): Short {
var pos = index
val array = this
val valueAsInt = array[pos++] and 0xff shl 8 or (array[pos] and 0xff)
return valueAsInt.toShort()
}
internal fun ByteArray.readInt(index: Int): Int {
var pos = index
val array = this
return (array[pos++] and 0xff shl 24
or (array[pos++] and 0xff shl 16)
or (array[pos++] and 0xff shl 8)
or (array[pos] and 0xff))
}
internal fun ByteArray.readLong(index: Int): Long {
var pos = index
val array = this
return (array[pos++] and 0xffL shl 56
or (array[pos++] and 0xffL shl 48)
or (array[pos++] and 0xffL shl 40)
or (array[pos++] and 0xffL shl 32)
or (array[pos++] and 0xffL shl 24)
or (array[pos++] and 0xffL shl 16)
or (array[pos++] and 0xffL shl 8)
or (array[pos] and 0xffL))
}
@Suppress("NOTHING_TO_INLINE") // Syntactic sugar.
private inline infix fun Byte.and(other: Long): Long = toLong() and other
@Suppress("NOTHING_TO_INLINE") // Syntactic sugar.
private inline infix fun Byte.and(other: Int): Int = toInt() and other