Skip to content

Commit 2729aa0

Browse files
committed
refactor: change packFlagsToLong to accept BooleanArray instead of varargs
1 parent fbe2606 commit 2729aa0

2 files changed

Lines changed: 54 additions & 106 deletions

File tree

src/main/kotlin/com/eignex/kencode/PackedDecoder.kt

Lines changed: 29 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ class PackedDecoder(
2525

2626
private var booleanIndices: IntArray = intArrayOf()
2727
private lateinit var booleanValues: BooleanArray
28+
private var booleanLookup: IntArray = intArrayOf() // fieldIndex → bitmask position, or -1
2829
private var nullableIndices: IntArray = intArrayOf()
2930
private lateinit var nullValues: BooleanArray
31+
private var nullableLookup: IntArray = intArrayOf() // fieldIndex → bitmask position, or -1
3032

3133
private var collectionSize = -1
3234
private var collectionIndex = 0
@@ -40,19 +42,25 @@ class PackedDecoder(
4042

4143
if (isCollection) {
4244
booleanIndices = intArrayOf()
45+
booleanLookup = intArrayOf()
4346
nullableIndices = intArrayOf()
47+
nullableLookup = intArrayOf()
4448
return this
4549
}
4650

4751
val boolIdx = (0 until descriptor.elementsCount).filter {
4852
descriptor.getElementDescriptor(it).kind == PrimitiveKind.BOOLEAN
4953
}
5054
booleanIndices = boolIdx.toIntArray()
55+
booleanLookup = IntArray(descriptor.elementsCount) { -1 }
56+
booleanIndices.forEachIndexed { pos, fieldIdx -> booleanLookup[fieldIdx] = pos }
5157

5258
val nullableIdx = (0 until descriptor.elementsCount).filter {
5359
descriptor.getElementDescriptor(it).isNullable
5460
}
5561
nullableIndices = nullableIdx.toIntArray()
62+
nullableLookup = IntArray(descriptor.elementsCount) { -1 }
63+
nullableIndices.forEachIndexed { pos, fieldIdx -> nullableLookup[fieldIdx] = pos }
5664

5765
val totalFlags = booleanIndices.size + nullableIndices.size
5866

@@ -196,15 +204,11 @@ class PackedDecoder(
196204
currentIndex = -1
197205
}
198206

199-
private fun booleanPos(index: Int): Int {
200-
for (i in booleanIndices.indices) if (booleanIndices[i] == index) return i
201-
return -1
202-
}
207+
private fun booleanPos(index: Int): Int =
208+
if (index < booleanLookup.size) booleanLookup[index] else -1
203209

204-
private fun nullablePos(index: Int): Int {
205-
for (i in nullableIndices.indices) if (nullableIndices[i] == index) return i
206-
return -1
207-
}
210+
private fun nullablePos(index: Int): Int =
211+
if (index < nullableLookup.size) nullableLookup[index] else -1
208212

209213
override fun decodeBooleanElement(
210214
descriptor: SerialDescriptor,
@@ -231,61 +235,35 @@ class PackedDecoder(
231235
override fun decodeIntElement(
232236
descriptor: SerialDescriptor,
233237
index: Int
234-
): Int {
235-
val anns = descriptor.getElementAnnotations(index)
236-
val hasFixedInt = anns.hasFixedInt()
237-
val hasVarInt = anns.hasVarInt()
238-
val hasVarUInt = anns.hasVarUInt()
239-
240-
val isVar = when {
241-
hasFixedInt -> false
242-
hasVarInt || hasVarUInt -> true
243-
else -> config.defaultVarInt || config.defaultZigZag
244-
}
245-
246-
val zigZag = when {
247-
hasVarInt -> true
248-
hasVarUInt || hasFixedInt -> false
249-
else -> config.defaultZigZag
238+
): Int = when (resolveIntEncoding(descriptor.getElementAnnotations(index), config)) {
239+
IntEncoding.ZIGZAG -> {
240+
val (raw, bytesRead) = PackedUtils.decodeVarInt(input, position)
241+
position += bytesRead
242+
PackedUtils.zigZagDecodeInt(raw)
250243
}
251-
252-
return if (isVar) {
244+
IntEncoding.VARINT -> {
253245
val (raw, bytesRead) = PackedUtils.decodeVarInt(input, position)
254246
position += bytesRead
255-
if (zigZag) PackedUtils.zigZagDecodeInt(raw) else raw
256-
} else {
257-
readIntPos()
247+
raw
258248
}
249+
IntEncoding.FIXED -> readIntPos()
259250
}
260251

261252
override fun decodeLongElement(
262253
descriptor: SerialDescriptor,
263254
index: Int
264-
): Long {
265-
val anns = descriptor.getElementAnnotations(index)
266-
val hasFixedInt = anns.hasFixedInt()
267-
val hasVarInt = anns.hasVarInt()
268-
val hasVarUInt = anns.hasVarUInt()
269-
270-
val isVar = when {
271-
hasFixedInt -> false
272-
hasVarInt || hasVarUInt -> true
273-
else -> config.defaultVarInt || config.defaultZigZag
274-
}
275-
276-
val zigZag = when {
277-
hasVarInt -> true
278-
hasVarUInt || hasFixedInt -> false
279-
else -> config.defaultZigZag
255+
): Long = when (resolveIntEncoding(descriptor.getElementAnnotations(index), config)) {
256+
IntEncoding.ZIGZAG -> {
257+
val (raw, bytesRead) = PackedUtils.decodeVarLong(input, position)
258+
position += bytesRead
259+
PackedUtils.zigZagDecodeLong(raw)
280260
}
281-
282-
return if (isVar) {
261+
IntEncoding.VARINT -> {
283262
val (raw, bytesRead) = PackedUtils.decodeVarLong(input, position)
284263
position += bytesRead
285-
if (zigZag) PackedUtils.zigZagDecodeLong(raw) else raw
286-
} else {
287-
readLongPos()
264+
raw
288265
}
266+
IntEncoding.FIXED -> readLongPos()
289267
}
290268

291269
override fun decodeFloatElement(
@@ -330,7 +308,7 @@ class PackedDecoder(
330308
val kind = deserializer.descriptor.kind
331309
val isInline = deserializer.descriptor.isInline
332310

333-
if ((kind is StructureKind.CLASS || kind is StructureKind.OBJECT || kind is StructureKind.LIST || kind is StructureKind.MAP || kind is PolymorphicKind) && !isInline) {
311+
if (!isInline && (kind is StructureKind || kind is PolymorphicKind)) {
334312
val subDecoder = PackedDecoder(input, config, serializersModule)
335313
subDecoder.position = this.position
336314
val value = deserializer.deserialize(subDecoder)

src/main/kotlin/com/eignex/kencode/PackedEncoder.kt

Lines changed: 25 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ class PackedEncoder(
2424
// Bitmask arrays for CLASSES only
2525
private var booleanIndices: IntArray = intArrayOf()
2626
private lateinit var booleanValues: BooleanArray
27+
private var booleanLookup: IntArray = intArrayOf() // fieldIndex → bitmask position, or -1
2728
private var nullableIndices: IntArray = intArrayOf()
2829
private lateinit var nullValues: BooleanArray
30+
private var nullableLookup: IntArray = intArrayOf() // fieldIndex → bitmask position, or -1
2931

3032
// Buffer for field data
3133
private val dataBuffer = ByteArrayOutputStream()
@@ -69,18 +71,24 @@ class PackedEncoder(
6971
}
7072
booleanIndices = boolIdx.toIntArray()
7173
booleanValues = BooleanArray(booleanIndices.size)
74+
booleanLookup = IntArray(descriptor.elementsCount) { -1 }
75+
booleanIndices.forEachIndexed { pos, fieldIdx -> booleanLookup[fieldIdx] = pos }
7276

7377
val nullableIdx = (0 until descriptor.elementsCount).filter {
7478
descriptor.getElementDescriptor(it).isNullable
7579
}
7680
nullableIndices = nullableIdx.toIntArray()
7781
nullValues = BooleanArray(nullableIndices.size)
82+
nullableLookup = IntArray(descriptor.elementsCount) { -1 }
83+
nullableIndices.forEachIndexed { pos, fieldIdx -> nullableLookup[fieldIdx] = pos }
7884
} else {
7985
// Collections do not use bitmasks
8086
booleanIndices = intArrayOf()
8187
booleanValues = BooleanArray(0)
88+
booleanLookup = intArrayOf()
8289
nullableIndices = intArrayOf()
8390
nullValues = BooleanArray(0)
91+
nullableLookup = intArrayOf()
8492
}
8593

8694
dataBuffer.reset()
@@ -181,7 +189,7 @@ class PackedEncoder(
181189

182190
// 1. Collections: No header, just data
183191
if (isCollection) {
184-
output.write(dataBuffer.toByteArray())
192+
dataBuffer.writeTo(output)
185193
inStructure = false
186194
return
187195
}
@@ -201,28 +209,26 @@ class PackedEncoder(
201209
PackedUtils.writeVarInt(flagBytes.size, output)
202210
output.write(flagBytes)
203211
} else {
204-
val flagsLong = PackedUtils.packFlagsToLong(*combined)
212+
val flagsLong = PackedUtils.packFlagsToLong(combined)
205213
PackedUtils.writeVarLong(flagsLong, output)
206214
}
207215
}
208216

209-
output.write(dataBuffer.toByteArray())
217+
dataBuffer.writeTo(output)
210218

211219
inStructure = false
212220
currentIndex = -1
213221
booleanIndices = intArrayOf()
222+
booleanLookup = intArrayOf()
214223
nullableIndices = intArrayOf()
224+
nullableLookup = intArrayOf()
215225
}
216226

217-
private fun booleanPos(index: Int): Int {
218-
for (i in booleanIndices.indices) if (booleanIndices[i] == index) return i
219-
return -1
220-
}
227+
private fun booleanPos(index: Int): Int =
228+
if (index < booleanLookup.size) booleanLookup[index] else -1
221229

222-
private fun nullablePos(index: Int): Int {
223-
for (i in nullableIndices.indices) if (nullableIndices[i] == index) return i
224-
return -1
225-
}
230+
private fun nullablePos(index: Int): Int =
231+
if (index < nullableLookup.size) nullableLookup[index] else -1
226232

227233
override fun encodeBooleanElement(
228234
descriptor: SerialDescriptor,
@@ -239,28 +245,10 @@ class PackedEncoder(
239245
index: Int,
240246
value: Int
241247
) {
242-
val anns = descriptor.getElementAnnotations(index)
243-
val hasFixedInt = anns.hasFixedInt()
244-
val hasVarInt = anns.hasVarInt()
245-
val hasVarUInt = anns.hasVarUInt()
246-
247-
val isVar = when {
248-
hasFixedInt -> false
249-
hasVarInt || hasVarUInt -> true
250-
else -> config.defaultVarInt || config.defaultZigZag
251-
}
252-
253-
val zigZag = when {
254-
hasVarInt -> true
255-
hasVarUInt || hasFixedInt -> false
256-
else -> config.defaultZigZag
257-
}
258-
259-
if (isVar) {
260-
val v = if (zigZag) PackedUtils.zigZagEncodeInt(value) else value
261-
PackedUtils.writeVarInt(v, dataBuffer)
262-
} else {
263-
PackedUtils.writeInt(value, dataBuffer)
248+
when (resolveIntEncoding(descriptor.getElementAnnotations(index), config)) {
249+
IntEncoding.ZIGZAG -> PackedUtils.writeVarInt(PackedUtils.zigZagEncodeInt(value), dataBuffer)
250+
IntEncoding.VARINT -> PackedUtils.writeVarInt(value, dataBuffer)
251+
IntEncoding.FIXED -> PackedUtils.writeInt(value, dataBuffer)
264252
}
265253
}
266254

@@ -269,28 +257,10 @@ class PackedEncoder(
269257
index: Int,
270258
value: Long
271259
) {
272-
val anns = descriptor.getElementAnnotations(index)
273-
val hasFixedInt = anns.hasFixedInt()
274-
val hasVarInt = anns.hasVarInt()
275-
val hasVarUInt = anns.hasVarUInt()
276-
277-
val isVar = when {
278-
hasFixedInt -> false
279-
hasVarInt || hasVarUInt -> true
280-
else -> config.defaultVarInt || config.defaultZigZag
281-
}
282-
283-
val zigZag = when {
284-
hasVarInt -> true
285-
hasVarUInt || hasFixedInt -> false
286-
else -> config.defaultZigZag
287-
}
288-
289-
if (isVar) {
290-
val v = if (zigZag) PackedUtils.zigZagEncodeLong(value) else value
291-
PackedUtils.writeVarLong(v, dataBuffer)
292-
} else {
293-
PackedUtils.writeLong(value, dataBuffer)
260+
when (resolveIntEncoding(descriptor.getElementAnnotations(index), config)) {
261+
IntEncoding.ZIGZAG -> PackedUtils.writeVarLong(PackedUtils.zigZagEncodeLong(value), dataBuffer)
262+
IntEncoding.VARINT -> PackedUtils.writeVarLong(value, dataBuffer)
263+
IntEncoding.FIXED -> PackedUtils.writeLong(value, dataBuffer)
294264
}
295265
}
296266

0 commit comments

Comments
 (0)