xref: /aosp_15_r20/external/leakcanary2/shark-graph/src/main/java/shark/internal/ByteSubArray.kt (revision d9e8da70d8c9df9a41d7848ae506fb3115cae6e6)
1 package shark.internal
2 
3 /**
4  * Provides read access to a sub part of a larger array.
5  */
6 internal class ByteSubArray(
7   private val array: ByteArray,
8   private val rangeStart: Int,
9   size: Int,
10   private val longIdentifiers: Boolean
11 ) {
12 
13   private val endInclusive = size - 1
14 
15   private var currentIndex = 0
16 
readBytenull17   fun readByte(): Byte {
18     val index = currentIndex
19     currentIndex++
20     require(index in 0..endInclusive) {
21       "Index $index should be between 0 and $endInclusive"
22     }
23     return array[rangeStart + index]
24   }
25 
readIdnull26   fun readId(): Long {
27     return if (longIdentifiers) {
28       readLong()
29     } else {
30       readInt().toLong()
31     }
32   }
33 
readIntnull34   fun readInt(): Int {
35     val index = currentIndex
36     currentIndex += 4
37     require(index >= 0 && index <= endInclusive - 3) {
38       "Index $index should be between 0 and ${endInclusive - 3}"
39     }
40     return array.readInt(rangeStart + index)
41   }
42 
readTruncatedLongnull43   fun readTruncatedLong(byteCount: Int): Long {
44     val index = currentIndex
45     currentIndex += byteCount
46     require(index >= 0 && index <= endInclusive - (byteCount - 1)) {
47       "Index $index should be between 0 and ${endInclusive - (byteCount - 1)}"
48     }
49     var pos = rangeStart + index
50     val array = array
51 
52     var value = 0L
53 
54     var shift = (byteCount - 1) * 8
55     while (shift >= 8) {
56       value = value or (array[pos++] and 0xffL shl shift)
57       shift -= 8
58     }
59     value = value or (array[pos] and 0xffL)
60     return value
61   }
62 
readLongnull63   fun readLong(): Long {
64     val index = currentIndex
65     currentIndex += 8
66     require(index >= 0 && index <= endInclusive - 7) {
67       "Index $index should be between 0 and ${endInclusive - 7}"
68     }
69     return array.readLong(rangeStart + index)
70   }
71 }
72 
readShortnull73 internal fun ByteArray.readShort(index: Int): Short {
74   var pos = index
75   val array = this
76   val valueAsInt = array[pos++] and 0xff shl 8 or (array[pos] and 0xff)
77   return valueAsInt.toShort()
78 }
79 
readIntnull80 internal fun ByteArray.readInt(index: Int): Int {
81   var pos = index
82   val array = this
83   return (array[pos++] and 0xff shl 24
84     or (array[pos++] and 0xff shl 16)
85     or (array[pos++] and 0xff shl 8)
86     or (array[pos] and 0xff))
87 }
88 
readLongnull89 internal fun ByteArray.readLong(index: Int): Long {
90   var pos = index
91   val array = this
92   return (array[pos++] and 0xffL shl 56
93     or (array[pos++] and 0xffL shl 48)
94     or (array[pos++] and 0xffL shl 40)
95     or (array[pos++] and 0xffL shl 32)
96     or (array[pos++] and 0xffL shl 24)
97     or (array[pos++] and 0xffL shl 16)
98     or (array[pos++] and 0xffL shl 8)
99     or (array[pos] and 0xffL))
100 }
101 
102 @Suppress("NOTHING_TO_INLINE") // Syntactic sugar.
andnull103 private inline infix fun Byte.and(other: Long): Long = toLong() and other
104 
105 @Suppress("NOTHING_TO_INLINE") // Syntactic sugar.
106 private inline infix fun Byte.and(other: Int): Int = toInt() and other