From 149a0e1850dbebcb9126f505504aead8c7a01c88 Mon Sep 17 00:00:00 2001 From: sergeych Date: Wed, 15 Mar 2023 09:51:42 +0100 Subject: [PATCH] optimization: ise varint on field counter for extendable format (it's rare for a struct to have so many fields so smartint will be better). --- src/commonMain/kotlin/net.sergeych.bintools/DataSink.kt | 5 +++++ src/commonMain/kotlin/net.sergeych.bintools/DataSource.kt | 8 ++++++++ .../kotlin/net.sergeych.bipack/BipackDecoder.kt | 4 ++-- .../kotlin/net.sergeych.bipack/BipackEncoder.kt | 4 ++-- src/commonMain/kotlin/net.sergeych.bipack/annotations.kt | 4 ++-- src/commonTest/kotlin/bipack/BipackEncoderTest.kt | 8 ++++---- 6 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/commonMain/kotlin/net.sergeych.bintools/DataSink.kt b/src/commonMain/kotlin/net.sergeych.bintools/DataSink.kt index 0ed3dea..4816af2 100644 --- a/src/commonMain/kotlin/net.sergeych.bintools/DataSink.kt +++ b/src/commonMain/kotlin/net.sergeych.bintools/DataSink.kt @@ -22,6 +22,11 @@ interface DataSink { fun writeBytes(data: ByteArray) { for(d in data) writeByte(d) } + + fun writeVarUInt(value: UInt) { Varint.encodeUnsigned(value.toULong())} + fun writeVarInt(value: UInt) { Varint.encodeSigned(value.toLong())} + fun writeSmartUInt(value: UInt) { Smartint.encodeUnsigned(value.toULong())} + fun writeSmartInt(value: UInt) { Smartint.encodeSigned(value.toLong())} } inline fun DataSink.writeNumber(value: T) { diff --git a/src/commonMain/kotlin/net.sergeych.bintools/DataSource.kt b/src/commonMain/kotlin/net.sergeych.bintools/DataSource.kt index af9af64..408accc 100644 --- a/src/commonMain/kotlin/net.sergeych.bintools/DataSource.kt +++ b/src/commonMain/kotlin/net.sergeych.bintools/DataSource.kt @@ -34,6 +34,14 @@ interface DataSource { fun readFloat() = Float.fromBits(readI32()).toFloat() + fun readSmartUInt(): UInt = Smartint.decodeUnsigned(this).toUInt() + fun readSmartInt(): Int = Smartint.decodeSigned(this).toInt() + + fun readVarUInt(): UInt = Varint.decodeUnsigned(this).toUInt() + fun readVarInt(): Int = Varint.decodeSigned(this).toInt() + + + } fun ByteArray.toDataSource(): DataSource = diff --git a/src/commonMain/kotlin/net.sergeych.bipack/BipackDecoder.kt b/src/commonMain/kotlin/net.sergeych.bipack/BipackDecoder.kt index b11ffff..fddc8db 100644 --- a/src/commonMain/kotlin/net.sergeych.bipack/BipackDecoder.kt +++ b/src/commonMain/kotlin/net.sergeych.bipack/BipackDecoder.kt @@ -59,8 +59,8 @@ class BipackDecoder(val input: DataSource, var elementsCount: Int = 0,val isColl // CRC-calculating one, and the fields below are CRC protected too: var count = descriptor.elementsCount for (a in descriptor.annotations) { - if (a is ExtendableFormat) - count = source.readNumber().toInt() + if (a is Extendable) + count = source.readSmartUInt().toInt() else if (a is Framed) { val code = CRC.crc32(descriptor.serialName.encodeToByteArray()) // if we fail to read CRC, it is IO error, so DataSource.EndOfData will be diff --git a/src/commonMain/kotlin/net.sergeych.bipack/BipackEncoder.kt b/src/commonMain/kotlin/net.sergeych.bipack/BipackEncoder.kt index 158c361..4fd33b2 100644 --- a/src/commonMain/kotlin/net.sergeych.bipack/BipackEncoder.kt +++ b/src/commonMain/kotlin/net.sergeych.bipack/BipackEncoder.kt @@ -72,8 +72,8 @@ class BipackEncoder(val output: DataSink) : AbstractEncoder() { sink.writeU32( CRC.crc32(descriptor.serialName.encodeToByteArray()) ) - } else if (a is ExtendableFormat) { - sink.writeNumber(descriptor.elementsCount.toUInt()) + } else if (a is Extendable) { + sink.writeSmartUInt(descriptor.elementsCount.toUInt()) } } return BipackEncoder(sink) diff --git a/src/commonMain/kotlin/net.sergeych.bipack/annotations.kt b/src/commonMain/kotlin/net.sergeych.bipack/annotations.kt index aa872be..4fe7ed1 100644 --- a/src/commonMain/kotlin/net.sergeych.bipack/annotations.kt +++ b/src/commonMain/kotlin/net.sergeych.bipack/annotations.kt @@ -15,7 +15,7 @@ import kotlinx.serialization.SerialInfo */ @Target(AnnotationTarget.CLASS) @SerialInfo -annotation class ExtendableFormat +annotation class Extendable /** @@ -29,7 +29,7 @@ annotation class Framed /** * Allow to CRC-protect structures (we suppose to use it with classes only). After the * data block its CRC32 will be written and checked. It is memory-wise: it calculates CRC - * on the fly without buffering the data. If used with [Framed] and [ExtendableFormat] the extra + * on the fly without buffering the data. If used with [Framed] and [Extendable] the extra * data is protected too. * * __Common pitfalls__. When unpacking corrupted data protected this way, the not only [InvalidFrameCRCException] diff --git a/src/commonTest/kotlin/bipack/BipackEncoderTest.kt b/src/commonTest/kotlin/bipack/BipackEncoderTest.kt index ed747f2..0ac2da3 100644 --- a/src/commonTest/kotlin/bipack/BipackEncoderTest.kt +++ b/src/commonTest/kotlin/bipack/BipackEncoderTest.kt @@ -11,11 +11,11 @@ import kotlin.test.* data class Foobar1N(val bar: Int, val foo: Int = 117) @Serializable -@ExtendableFormat +@Extendable data class Foobar1(val bar: Int, val foo: Int = 117) @Serializable -@ExtendableFormat +@Extendable @SerialName("bipack.Foobar1") data class Foobar2(val bar: Int, val foo: Int, val other: Int = -1) @@ -30,12 +30,12 @@ data class FoobarF2(val bar: Int, val foo: Int, val other: Int = -1) @Serializable @Framed -@ExtendableFormat +@Extendable data class FoobarF3(val bar: Int, val foo: Int, val other: Int = -1) @Serializable @Framed -@ExtendableFormat +@Extendable @CrcProtected() data class FoobarFP1(val bar: Int, val foo: Int, val other: Int = -1)