xref: /aosp_15_r20/external/leakcanary2/shark/src/main/java/shark/internal/FieldIdReader.kt (revision d9e8da70d8c9df9a41d7848ae506fb3115cae6e6)
1 package shark.internal
2 
3 import shark.HprofRecord.HeapDumpRecord.ObjectRecord.InstanceDumpRecord
4 
5 /**
6  * Simplified version of [FieldValuesReader] class that can only read an ID or skip a certain
7  * amount of bytes.
8  */
9 internal class FieldIdReader(
10   private val record: InstanceDumpRecord,
11   private val identifierByteSize: Int
12 ) {
13 
14   private var position = 0
15 
readIdnull16   fun readId(): Long {
17     // As long as we don't interpret IDs, reading signed values here is fine.
18     val value = when (identifierByteSize) {
19       1 -> readByteId(position, record.fieldValues)
20       2 -> readShortId(position, record.fieldValues)
21       4 -> readIntId(position, record.fieldValues)
22       8 -> readLongId(position, record.fieldValues)
23       else -> error("ID Length must be 1, 2, 4, or 8")
24     }
25     position += identifierByteSize
26     return value
27   }
28 
skipBytesnull29   fun skipBytes(count: Int) {
30     position += count
31   }
32 
readByteIdnull33   private fun readByteId(
34     index: Int,
35     array: ByteArray
36   ) =
37     array[index].toLong()
38 
39   private fun readShortId(
40     index: Int,
41     array: ByteArray
42   ): Long {
43     var pos = index
44     return (array[pos++] and 0xff shl 8
45       or (array[pos] and 0xff)).toLong()
46   }
47 
readIntIdnull48   private fun readIntId(
49     index: Int,
50     array: ByteArray
51   ): Long {
52     var pos = index
53     return (array[pos++] and 0xff shl 24
54       or (array[pos++] and 0xff shl 16)
55       or (array[pos++] and 0xff shl 8)
56       or (array[pos] and 0xff)).toLong()
57   }
58 
readLongIdnull59   private fun readLongId(
60     index: Int,
61     array: ByteArray
62   ): Long {
63     var pos = index
64     return (array[pos++] and 0xffL shl 56
65       or (array[pos++] and 0xffL shl 48)
66       or (array[pos++] and 0xffL shl 40)
67       or (array[pos++] and 0xffL shl 32)
68       or (array[pos++] and 0xffL shl 24)
69       or (array[pos++] and 0xffL shl 16)
70       or (array[pos++] and 0xffL shl 8)
71       or (array[pos] and 0xffL))
72   }
73 
74   @Suppress("NOTHING_TO_INLINE") // Syntactic sugar.
andnull75   private inline infix fun Byte.and(other: Long): Long = toLong() and other
76 
77   @Suppress("NOTHING_TO_INLINE") // Syntactic sugar.
78   private inline infix fun Byte.and(other: Int): Int = toInt() and other
79 }