main

square/leakcanary

Last updated at: 29/12/2023 09:39

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 type Long.

The class contains the following methods:

  • readByte(): Reads and returns a Byte value from the sub-array.
  • readId(): Reads and returns an Int value or Long value from the sub-array, depending on the value of longIdentifiers.
  • readInt(): Reads and returns an Int value from the sub-array.
  • readTruncatedLong(byteCount: Int): Reads and returns a truncated Long value from the sub-array, based on the specified byteCount.
  • readLong(): Reads and returns a Long 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 a Short value from the specified index in the array.
  • readInt(index: Int): Reads and returns an Int value from the specified index in the array.
  • readLong(index: Int): Reads and returns a Long value from the specified index 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