From a28ceb251a433869e56110070cbc484295afff3a Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Fri, 9 Aug 2024 17:20:07 +0300 Subject: [PATCH] [#77] util/proto: Optimize int32 marshaling This is the approach used in easyproto https://github.com/VictoriaMetrics/easyproto/blob/52d3ac47440b52fd42bf4bbb5bacb358a85fccc3/writer.go#L203 It allows to occupy slightly less space for negative numbers. The format is still protobuf, although, technically, this is a breaking change for our stable marshaling format. However, we don't use int32 at all and all enums have positive values, so nothing is broken. Signed-off-by: Evgenii Stratonikov --- util/proto/marshal.go | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/util/proto/marshal.go b/util/proto/marshal.go index 26b3eb0..42c6a91 100644 --- a/util/proto/marshal.go +++ b/util/proto/marshal.go @@ -136,19 +136,19 @@ func UInt32Size(field int, v uint32) int { } func Int32Marshal(field int, buf []byte, v int32) int { - return UInt64Marshal(field, buf, uint64(v)) + return UInt64Marshal(field, buf, uint64(uint32(v))) } func Int32Size(field int, v int32) int { - return UInt64Size(field, uint64(v)) + return UInt64Size(field, uint64(uint32(v))) } func EnumMarshal(field int, buf []byte, v int32) int { - return UInt64Marshal(field, buf, uint64(v)) + return UInt64Marshal(field, buf, uint64(uint32(v))) } func EnumSize(field int, v int32) int { - return UInt64Size(field, uint64(v)) + return UInt64Size(field, uint64(uint32(v))) } func RepeatedBytesMarshal(field int, buf []byte, v [][]byte) int { @@ -243,11 +243,28 @@ func RepeatedUInt32Size(field int, v []uint32) (size, arraySize int) { } func RepeatedInt32Marshal(field int, buf []byte, v []int32) int { - return repeatedUIntMarshal(field, buf, v) + if len(v) == 0 { + return 0 + } + + prefix := protowire.EncodeTag(protowire.Number(field), protowire.BytesType) + offset := binary.PutUvarint(buf, uint64(prefix)) + _, arrSize := RepeatedInt32Size(field, v) + offset += binary.PutUvarint(buf[offset:], uint64(arrSize)) + for i := range v { + offset += binary.PutUvarint(buf[offset:], uint64(uint32(v[i]))) + } + return offset } func RepeatedInt32Size(field int, v []int32) (size, arraySize int) { - return repeatedUIntSize(field, v) + if len(v) == 0 { + return 0, 0 + } + for i := range v { + arraySize += protowire.SizeVarint(uint64(uint32(v[i]))) + } + return protowire.SizeGroup(protowire.Number(field), protowire.SizeBytes(arraySize)), arraySize } // VarUIntSize returns length of varint byte sequence for uint64 value 'x'.