Skip to content

Commit 4ead384

Browse files
austnwilpopematt
andauthored
Add starting point for ByteArray-backed bytecode generator (#1134)
* Begin implementation of ByteArrayBytecodeGenerator - Implement readTextReference - Implement readBytesReference - Implement readBigIntegerReference - Implement readShortTimestampReference - Implement basic refill --------- Co-authored-by: Matthew Pope <81593196+popematt@users.noreply.github.com>
1 parent 6493fc4 commit 4ead384

10 files changed

Lines changed: 661 additions & 43 deletions

File tree

src/main/java/com/amazon/ion/bytecode/BytecodeEmitter.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ internal object BytecodeEmitter {
8484
}
8585

8686
@JvmStatic
87-
fun emitShortTimestampReference(destination: BytecodeBuffer, precisionAndOffsetMode: Int, dataPosition: Int) {
88-
destination.add2(Instructions.I_SHORT_TIMESTAMP_REF.packInstructionData(precisionAndOffsetMode), dataPosition)
87+
fun emitShortTimestampReference(destination: BytecodeBuffer, opcode: Int, dataPosition: Int) {
88+
destination.add2(Instructions.I_SHORT_TIMESTAMP_REF.packInstructionData(opcode), dataPosition)
8989
}
9090
}

src/main/java/com/amazon/ion/bytecode/bin11/ByteArrayBytecodeGenerator11.kt

Lines changed: 87 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,95 @@
22
// SPDX-License-Identifier: Apache-2.0
33
package com.amazon.ion.bytecode.bin11
44

5+
import com.amazon.ion.Decimal
6+
import com.amazon.ion.IonException
7+
import com.amazon.ion.Timestamp
8+
import com.amazon.ion.bytecode.BytecodeGenerator
9+
import com.amazon.ion.bytecode.bin11.bytearray.OpcodeHandlerTable
10+
import com.amazon.ion.bytecode.bin11.bytearray.PrimitiveDecoder.readFixedIntAsBigInteger
11+
import com.amazon.ion.bytecode.bin11.bytearray.TimestampDecoder
12+
import com.amazon.ion.bytecode.ir.Instructions
13+
import com.amazon.ion.bytecode.util.AppendableConstantPoolView
14+
import com.amazon.ion.bytecode.util.ByteSlice
15+
import com.amazon.ion.bytecode.util.BytecodeBuffer
16+
import com.amazon.ion.bytecode.util.unsignedToInt
17+
import com.amazon.ion.impl.bin.utf8.Utf8StringDecoder
18+
import com.amazon.ion.impl.bin.utf8.Utf8StringDecoderPool
519
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
20+
import java.math.BigInteger
21+
import java.nio.ByteBuffer
622

723
@SuppressFBWarnings("EI_EXPOSE_REP2", justification = "constructor does not make a defensive copy of source as a performance optimization")
8-
internal class ByteArrayBytecodeGenerator11
9-
@SuppressFBWarnings("URF_UNREAD_FIELD", justification = "field will be read once this class is implemented")
10-
constructor(
24+
internal class ByteArrayBytecodeGenerator11(
1125
private val source: ByteArray,
12-
private var i: Int,
13-
) {
14-
// TODO: This should implement BytecodeGenerator
26+
private var currentPosition: Int,
27+
) : BytecodeGenerator {
28+
private val utf8Decoder: Utf8StringDecoder = Utf8StringDecoderPool.getInstance().orCreate
29+
30+
override fun refill(
31+
destination: BytecodeBuffer,
32+
constantPool: AppendableConstantPoolView,
33+
macroSrc: IntArray,
34+
macroIndices: IntArray,
35+
symTab: Array<String?>
36+
) {
37+
var opcode = -1
38+
while (currentPosition < source.size && !isSystemValue(opcode)) {
39+
opcode = source[currentPosition++].unsignedToInt()
40+
val handler = OpcodeHandlerTable.handler(opcode)
41+
currentPosition += handler.convertOpcodeToBytecode(
42+
opcode,
43+
source,
44+
currentPosition,
45+
destination,
46+
constantPool,
47+
macroSrc,
48+
macroIndices,
49+
symTab
50+
)
51+
}
52+
53+
if (currentPosition >= source.size) {
54+
destination.add(Instructions.I_END_OF_INPUT)
55+
}
56+
}
57+
58+
override fun readBigIntegerReference(position: Int, length: Int): BigInteger {
59+
return readFixedIntAsBigInteger(source, position, length)
60+
}
61+
62+
override fun readDecimalReference(position: Int, length: Int): Decimal {
63+
TODO("Not yet implemented")
64+
}
65+
66+
override fun readShortTimestampReference(position: Int, opcode: Int): Timestamp {
67+
return TimestampDecoder.readShortTimestamp(source, position, opcode)
68+
}
69+
70+
override fun readTimestampReference(position: Int, length: Int): Timestamp {
71+
TODO("Not yet implemented")
72+
}
73+
74+
override fun readTextReference(position: Int, length: Int): String {
75+
val buffer = ByteBuffer.wrap(source, position, length)
76+
return utf8Decoder.decode(buffer, length)
77+
}
78+
79+
override fun readBytesReference(position: Int, length: Int): ByteSlice {
80+
return ByteSlice(source, position, position + length)
81+
}
82+
83+
override fun ionMinorVersion(): Int = 1
84+
85+
override fun getGeneratorForMinorVersion(minorVersion: Int): BytecodeGenerator {
86+
return when (minorVersion) {
87+
1 -> ByteArrayBytecodeGenerator11(source, currentPosition)
88+
// TODO: update with ByteArrayBytecodeGenerator10 once it implements BytecodeGenerator
89+
else -> throw IonException("Minor version $minorVersion not yet implemented for ByteArray-backed data sources.")
90+
}
91+
}
92+
93+
private fun isSystemValue(opcode: Int): Boolean {
94+
return opcode in 0xE0..0xE8
95+
}
1596
}

src/main/java/com/amazon/ion/bytecode/bin11/bytearray/PrimitiveDecoder.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,17 @@ internal object PrimitiveDecoder {
7373
}
7474
}
7575

76+
@JvmStatic
77+
fun readFixedIntAsBigInteger(source: ByteArray, start: Int, length: Int): BigInteger {
78+
// TODO: ion-java#1114
79+
if (source.size < start + length) throw IonException("Incomplete data: start=$start, length=$length, limit=${source.size}")
80+
val bytes = ByteArray(length)
81+
for (i in 0 until length) {
82+
bytes[i] = source[start + length - i - 1]
83+
}
84+
return BigInteger(bytes)
85+
}
86+
7687
@JvmStatic
7788
fun readFixedUInt16(source: ByteArray, position: Int): UShort {
7889
// TODO: ion-java#1114

src/main/java/com/amazon/ion/bytecode/bin11/bytearray/ShortTimestampOpcodeHandler.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ internal object ShortTimestampOpcodeHandler : OpcodeToBytecodeHandler {
4040
macroIndices: IntArray,
4141
symbolTable: Array<String?>
4242
): Int {
43-
val precisionAndOffsetMode = opcode and 0xF
4443
BytecodeEmitter.emitShortTimestampReference(
4544
destination,
46-
precisionAndOffsetMode,
45+
opcode,
4746
position
4847
)
48+
val precisionAndOffsetMode = opcode and 0xF
4949
return serializedSizeByOpcodeTable[precisionAndOffsetMode]
5050
}
5151
}
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
package com.amazon.ion.bytecode.bin11.bytearray
4+
5+
import com.amazon.ion.IonException
6+
import com.amazon.ion.Timestamp
7+
import com.amazon.ion.bytecode.bin11.bytearray.PrimitiveDecoder.readFixedInt16
8+
import com.amazon.ion.bytecode.bin11.bytearray.PrimitiveDecoder.readFixedInt32
9+
import com.amazon.ion.bytecode.bin11.bytearray.PrimitiveDecoder.readFixedInt8AsShort
10+
import com.amazon.ion.bytecode.bin11.bytearray.PrimitiveDecoder.readFixedIntAsLong
11+
import com.amazon.ion.impl.bin.Ion_1_1_Constants.S_O_TIMESTAMP_FRACTION_BIT_OFFSET
12+
import com.amazon.ion.impl.bin.Ion_1_1_Constants.S_O_TIMESTAMP_OFFSET_BIT_OFFSET
13+
import com.amazon.ion.impl.bin.Ion_1_1_Constants.S_O_TIMESTAMP_SECOND_BIT_OFFSET
14+
import com.amazon.ion.impl.bin.Ion_1_1_Constants.S_TIMESTAMP_DAY_BIT_OFFSET
15+
import com.amazon.ion.impl.bin.Ion_1_1_Constants.S_TIMESTAMP_HOUR_BIT_OFFSET
16+
import com.amazon.ion.impl.bin.Ion_1_1_Constants.S_TIMESTAMP_MINUTE_BIT_OFFSET
17+
import com.amazon.ion.impl.bin.Ion_1_1_Constants.S_TIMESTAMP_MONTH_BIT_OFFSET
18+
import com.amazon.ion.impl.bin.Ion_1_1_Constants.S_U_TIMESTAMP_FRACTION_BIT_OFFSET
19+
import com.amazon.ion.impl.bin.Ion_1_1_Constants.S_U_TIMESTAMP_SECOND_BIT_OFFSET
20+
import com.amazon.ion.impl.bin.Ion_1_1_Constants.S_U_TIMESTAMP_UTC_FLAG
21+
import com.amazon.ion.impl.bin.Ion_1_1_Constants.S_U_TIMESTAMP_UTC_FLAG_L
22+
import java.math.BigDecimal
23+
24+
/**
25+
* Helper class for decoding the various timestamp encoding variants from a [ByteArray].
26+
*
27+
* TODO(perf): avoid auto-boxing the `0` integer for the offset when constructing the Timestamp instance.
28+
*/
29+
internal object TimestampDecoder {
30+
private const val MASK_4 = 0b1111
31+
private const val MASK_5 = 0b11111
32+
private const val MASK_6 = 0b111111
33+
private const val MASK_7 = 0b1111111
34+
private const val MASK_4L = 0b1111L
35+
private const val MASK_5L = 0b11111L
36+
private const val MASK_6L = 0b111111L
37+
private const val MASK_7L = 0b1111111L
38+
private const val MASK_10L = 0b1111111111L
39+
private const val MASK_20L = 0b11111111111111111111L
40+
private const val MASK_30L = 0b111111111111111111111111111111L
41+
42+
fun readTimestampToYear(source: ByteArray, position: Int): Timestamp {
43+
val year = readFixedInt8AsShort(source, position).toInt()
44+
return Timestamp.forYear(year + 1970)
45+
}
46+
47+
fun readTimestampToMonth(source: ByteArray, position: Int): Timestamp {
48+
val yearAndMonth = readFixedInt16(source, position).toInt()
49+
val year = yearAndMonth.and(MASK_7)
50+
val month = yearAndMonth.shr(S_TIMESTAMP_MONTH_BIT_OFFSET)
51+
52+
return Timestamp.forMonth(year + 1970, month)
53+
}
54+
55+
fun readTimestampToDay(source: ByteArray, position: Int): Timestamp {
56+
val yearMonthAndDay = readFixedInt16(source, position).toInt()
57+
val year = yearMonthAndDay.and(MASK_7)
58+
val month = yearMonthAndDay.shr(S_TIMESTAMP_MONTH_BIT_OFFSET).and(MASK_4)
59+
val day = yearMonthAndDay.shr(S_TIMESTAMP_DAY_BIT_OFFSET).and(MASK_5)
60+
61+
return Timestamp.forDay(year + 1970, month, day)
62+
}
63+
64+
fun readTimestampToMinuteUTCOrUnknown(source: ByteArray, position: Int): Timestamp {
65+
val data = readFixedInt32(source, position)
66+
val year = data.and(MASK_7)
67+
val month = data.shr(S_TIMESTAMP_MONTH_BIT_OFFSET).and(MASK_4)
68+
val day = data.shr(S_TIMESTAMP_DAY_BIT_OFFSET).and(MASK_5)
69+
val hour = data.shr(S_TIMESTAMP_HOUR_BIT_OFFSET).and(MASK_5)
70+
val minute = data.shr(S_TIMESTAMP_MINUTE_BIT_OFFSET).and(MASK_6)
71+
val isUTC = data.and(S_U_TIMESTAMP_UTC_FLAG) != 0
72+
73+
return Timestamp.forMinute(year + 1970, month, day, hour, minute, if (isUTC) 0 else null)
74+
}
75+
76+
fun readTimestampToSecondUTCOrUnknown(source: ByteArray, position: Int): Timestamp {
77+
val data = readFixedIntAsLong(source, position, 5)
78+
val year = data.and(MASK_7L).toInt()
79+
val month = data.shr(S_TIMESTAMP_MONTH_BIT_OFFSET).and(MASK_4L).toInt()
80+
val day = data.shr(S_TIMESTAMP_DAY_BIT_OFFSET).and(MASK_5L).toInt()
81+
val hour = data.shr(S_TIMESTAMP_HOUR_BIT_OFFSET).and(MASK_5L).toInt()
82+
val minute = data.shr(S_TIMESTAMP_MINUTE_BIT_OFFSET).and(MASK_6L).toInt()
83+
val second = data.shr(S_U_TIMESTAMP_SECOND_BIT_OFFSET).and(MASK_6L).toInt()
84+
val isUTC = data.and(S_U_TIMESTAMP_UTC_FLAG_L) != 0L
85+
86+
return Timestamp.forSecond(year + 1970, month, day, hour, minute, second, if (isUTC) 0 else null)
87+
}
88+
89+
fun readTimestampToMillisecondUTCOrUnknown(source: ByteArray, position: Int): Timestamp {
90+
val data = readFixedIntAsLong(source, position, 6)
91+
val year = data.and(MASK_7L).toInt()
92+
val month = data.shr(S_TIMESTAMP_MONTH_BIT_OFFSET).and(MASK_4L).toInt()
93+
val day = data.shr(S_TIMESTAMP_DAY_BIT_OFFSET).and(MASK_5L).toInt()
94+
val hour = data.shr(S_TIMESTAMP_HOUR_BIT_OFFSET).and(MASK_5L).toInt()
95+
val minute = data.shr(S_TIMESTAMP_MINUTE_BIT_OFFSET).and(MASK_6L).toInt()
96+
val second = data.shr(S_U_TIMESTAMP_SECOND_BIT_OFFSET).and(MASK_6L)
97+
val fractionalSecond = data.shr(S_U_TIMESTAMP_FRACTION_BIT_OFFSET).and(MASK_10L)
98+
val isUTC = data.and(S_U_TIMESTAMP_UTC_FLAG_L) != 0L
99+
100+
val secondBigDecimal = BigDecimal.valueOf(second)
101+
val fractionalSecondBigDecimal = BigDecimal.valueOf(fractionalSecond, 3)
102+
return Timestamp.forSecond(year + 1970, month, day, hour, minute, secondBigDecimal.add(fractionalSecondBigDecimal), if (isUTC) 0 else null)
103+
}
104+
105+
fun readTimestampToMicrosecondUTCOrUnknown(source: ByteArray, position: Int): Timestamp {
106+
val data = readFixedIntAsLong(source, position, 7)
107+
val year = data.and(MASK_7L).toInt()
108+
val month = data.shr(S_TIMESTAMP_MONTH_BIT_OFFSET).and(MASK_4L).toInt()
109+
val day = data.shr(S_TIMESTAMP_DAY_BIT_OFFSET).and(MASK_5L).toInt()
110+
val hour = data.shr(S_TIMESTAMP_HOUR_BIT_OFFSET).and(MASK_5L).toInt()
111+
val minute = data.shr(S_TIMESTAMP_MINUTE_BIT_OFFSET).and(MASK_6L).toInt()
112+
val second = data.shr(S_U_TIMESTAMP_SECOND_BIT_OFFSET).and(MASK_6L)
113+
val fractionalSecond = data.shr(S_U_TIMESTAMP_FRACTION_BIT_OFFSET).and(MASK_20L)
114+
val isUTC = data.and(S_U_TIMESTAMP_UTC_FLAG_L) != 0L
115+
116+
val secondBigDecimal = BigDecimal.valueOf(second)
117+
val fractionalSecondBigDecimal = BigDecimal.valueOf(fractionalSecond, 6)
118+
return Timestamp.forSecond(year + 1970, month, day, hour, minute, secondBigDecimal.add(fractionalSecondBigDecimal), if (isUTC) 0 else null)
119+
}
120+
121+
fun readTimestampToNanosecondUTCOrUnknown(source: ByteArray, position: Int): Timestamp {
122+
val data = readFixedIntAsLong(source, position, 8)
123+
val year = data.and(MASK_7L).toInt()
124+
val month = data.shr(S_TIMESTAMP_MONTH_BIT_OFFSET).and(MASK_4L).toInt()
125+
val day = data.shr(S_TIMESTAMP_DAY_BIT_OFFSET).and(MASK_5L).toInt()
126+
val hour = data.shr(S_TIMESTAMP_HOUR_BIT_OFFSET).and(MASK_5L).toInt()
127+
val minute = data.shr(S_TIMESTAMP_MINUTE_BIT_OFFSET).and(MASK_6L).toInt()
128+
val second = data.shr(S_U_TIMESTAMP_SECOND_BIT_OFFSET).and(MASK_6L)
129+
val fractionalSecond = data.ushr(S_U_TIMESTAMP_FRACTION_BIT_OFFSET).and(MASK_30L)
130+
val isUTC = data.and(S_U_TIMESTAMP_UTC_FLAG_L) != 0L
131+
132+
val secondBigDecimal = BigDecimal.valueOf(second)
133+
val fractionalSecondBigDecimal = BigDecimal.valueOf(fractionalSecond, 9)
134+
return Timestamp.forSecond(year + 1970, month, day, hour, minute, secondBigDecimal.add(fractionalSecondBigDecimal), if (isUTC) 0 else null)
135+
}
136+
137+
fun readTimestampToMinuteWithOffset(source: ByteArray, position: Int): Timestamp {
138+
val data = readFixedIntAsLong(source, position, 5)
139+
val year = data.and(MASK_7L).toInt()
140+
val month = data.shr(S_TIMESTAMP_MONTH_BIT_OFFSET).and(MASK_4L).toInt()
141+
val day = data.shr(S_TIMESTAMP_DAY_BIT_OFFSET).and(MASK_5L).toInt()
142+
val hour = data.shr(S_TIMESTAMP_HOUR_BIT_OFFSET).and(MASK_5L).toInt()
143+
val minute = data.shr(S_TIMESTAMP_MINUTE_BIT_OFFSET).and(MASK_6L).toInt()
144+
val offset = data.shr(S_O_TIMESTAMP_OFFSET_BIT_OFFSET).and(MASK_7L).toInt()
145+
146+
return Timestamp.forMinute(year + 1970, month, day, hour, minute, (offset - 56) * 15)
147+
}
148+
149+
fun readTimestampToSecondWithOffset(source: ByteArray, position: Int): Timestamp {
150+
val data = readFixedIntAsLong(source, position, 5)
151+
val year = data.and(MASK_7L).toInt()
152+
val month = data.shr(S_TIMESTAMP_MONTH_BIT_OFFSET).and(MASK_4L).toInt()
153+
val day = data.shr(S_TIMESTAMP_DAY_BIT_OFFSET).and(MASK_5L).toInt()
154+
val hour = data.shr(S_TIMESTAMP_HOUR_BIT_OFFSET).and(MASK_5L).toInt()
155+
val minute = data.shr(S_TIMESTAMP_MINUTE_BIT_OFFSET).and(MASK_6L).toInt()
156+
val offset = data.shr(S_O_TIMESTAMP_OFFSET_BIT_OFFSET).and(MASK_7L).toInt()
157+
val second = data.shr(S_O_TIMESTAMP_SECOND_BIT_OFFSET).and(MASK_6L).toInt()
158+
159+
return Timestamp.forSecond(year + 1970, month, day, hour, minute, second, (offset - 56) * 15)
160+
}
161+
162+
fun readTimestampToMillisecondWithOffset(source: ByteArray, position: Int): Timestamp {
163+
val data = readFixedIntAsLong(source, position, 7)
164+
val year = data.and(MASK_7L).toInt()
165+
val month = data.shr(S_TIMESTAMP_MONTH_BIT_OFFSET).and(MASK_4L).toInt()
166+
val day = data.shr(S_TIMESTAMP_DAY_BIT_OFFSET).and(MASK_5L).toInt()
167+
val hour = data.shr(S_TIMESTAMP_HOUR_BIT_OFFSET).and(MASK_5L).toInt()
168+
val minute = data.shr(S_TIMESTAMP_MINUTE_BIT_OFFSET).and(MASK_6L).toInt()
169+
val offset = data.shr(S_O_TIMESTAMP_OFFSET_BIT_OFFSET).and(MASK_7L).toInt()
170+
val second = data.shr(S_O_TIMESTAMP_SECOND_BIT_OFFSET).and(MASK_6L)
171+
val fractionalSecond = data.shr(S_O_TIMESTAMP_FRACTION_BIT_OFFSET).and(MASK_10L)
172+
173+
val secondBigDecimal = BigDecimal.valueOf(second)
174+
val fractionalSecondBigDecimal = BigDecimal.valueOf(fractionalSecond, 3)
175+
return Timestamp.forSecond(year + 1970, month, day, hour, minute, secondBigDecimal.add(fractionalSecondBigDecimal), (offset - 56) * 15)
176+
}
177+
178+
fun readTimestampToMicrosecondWithOffset(source: ByteArray, position: Int): Timestamp {
179+
val data = readFixedIntAsLong(source, position, 8)
180+
val year = data.and(MASK_7L).toInt()
181+
val month = data.shr(S_TIMESTAMP_MONTH_BIT_OFFSET).and(MASK_4L).toInt()
182+
val day = data.shr(S_TIMESTAMP_DAY_BIT_OFFSET).and(MASK_5L).toInt()
183+
val hour = data.shr(S_TIMESTAMP_HOUR_BIT_OFFSET).and(MASK_5L).toInt()
184+
val minute = data.shr(S_TIMESTAMP_MINUTE_BIT_OFFSET).and(MASK_6L).toInt()
185+
val offset = data.shr(S_O_TIMESTAMP_OFFSET_BIT_OFFSET).and(MASK_7L).toInt()
186+
val second = data.shr(S_O_TIMESTAMP_SECOND_BIT_OFFSET).and(MASK_6L)
187+
val fractionalSecond = data.shr(S_O_TIMESTAMP_FRACTION_BIT_OFFSET).and(MASK_20L)
188+
189+
val secondBigDecimal = BigDecimal.valueOf(second)
190+
val fractionalSecondBigDecimal = BigDecimal.valueOf(fractionalSecond, 6)
191+
return Timestamp.forSecond(year + 1970, month, day, hour, minute, secondBigDecimal.add(fractionalSecondBigDecimal), (offset - 56) * 15)
192+
}
193+
194+
fun readTimestampToNanosecondWithOffset(source: ByteArray, position: Int): Timestamp {
195+
val data = readFixedIntAsLong(source, position, 8)
196+
val highFractionalSecondByte = readFixedInt8AsShort(source, position + 8).toLong().and(MASK_6L)
197+
val year = data.and(MASK_7L).toInt()
198+
val month = data.shr(S_TIMESTAMP_MONTH_BIT_OFFSET).and(MASK_4L).toInt()
199+
val day = data.shr(S_TIMESTAMP_DAY_BIT_OFFSET).and(MASK_5L).toInt()
200+
val hour = data.shr(S_TIMESTAMP_HOUR_BIT_OFFSET).and(MASK_5L).toInt()
201+
val minute = data.shr(S_TIMESTAMP_MINUTE_BIT_OFFSET).and(MASK_6L).toInt()
202+
val offset = data.shr(S_O_TIMESTAMP_OFFSET_BIT_OFFSET).and(MASK_7L).toInt()
203+
val second = data.shr(S_O_TIMESTAMP_SECOND_BIT_OFFSET).and(MASK_6L)
204+
val fractionalSecond = data.ushr(S_O_TIMESTAMP_FRACTION_BIT_OFFSET).or(highFractionalSecondByte.shl(24))
205+
206+
val secondBigDecimal = BigDecimal.valueOf(second)
207+
val fractionalSecondBigDecimal = BigDecimal.valueOf(fractionalSecond, 9)
208+
return Timestamp.forSecond(year + 1970, month, day, hour, minute, secondBigDecimal.add(fractionalSecondBigDecimal), (offset - 56) * 15)
209+
}
210+
211+
@OptIn(ExperimentalStdlibApi::class) // for Byte.toHexString()
212+
fun readShortTimestamp(source: ByteArray, position: Int, opcode: Int): Timestamp {
213+
return when (opcode) {
214+
0x80 -> readTimestampToYear(source, position)
215+
0x81 -> readTimestampToMonth(source, position)
216+
0x82 -> readTimestampToDay(source, position)
217+
0x83 -> readTimestampToMinuteUTCOrUnknown(source, position)
218+
0x84 -> readTimestampToSecondUTCOrUnknown(source, position)
219+
0x85 -> readTimestampToMillisecondUTCOrUnknown(source, position)
220+
0x86 -> readTimestampToMicrosecondUTCOrUnknown(source, position)
221+
0x87 -> readTimestampToNanosecondUTCOrUnknown(source, position)
222+
0x88 -> readTimestampToMinuteWithOffset(source, position)
223+
0x89 -> readTimestampToSecondWithOffset(source, position)
224+
0x8a -> readTimestampToMillisecondWithOffset(source, position)
225+
0x8b -> readTimestampToMicrosecondWithOffset(source, position)
226+
0x8c -> readTimestampToNanosecondWithOffset(source, position)
227+
else -> throw IonException("Unrecognized short timestamp opcode ${opcode.toByte().toHexString()}")
228+
}
229+
}
230+
}

0 commit comments

Comments
 (0)