From 25a4a3b76f6b53114aab2150cf9a60094608f6aa Mon Sep 17 00:00:00 2001 From: Viktor Govako Date: Sat, 5 Jul 2025 11:19:30 -0300 Subject: [PATCH] [coding] Added varint short arrays ser/des. Signed-off-by: Viktor Govako # Conflicts: # libs/coding/coding_tests/varint_test.cpp --- libs/coding/coding_tests/varint_test.cpp | 29 ++++++++++++- libs/coding/varint.hpp | 54 +++++++++++++++++++++--- 2 files changed, 77 insertions(+), 6 deletions(-) diff --git a/libs/coding/coding_tests/varint_test.cpp b/libs/coding/coding_tests/varint_test.cpp index f18278347..4f28e18ac 100644 --- a/libs/coding/coding_tests/varint_test.cpp +++ b/libs/coding/coding_tests/varint_test.cpp @@ -1,7 +1,8 @@ -#include "coding/varint.hpp" #include "testing/testing.hpp" #include "coding/byte_stream.hpp" +#include "coding/reader.hpp" +#include "coding/varint.hpp" #include "base/macros.hpp" #include "base/stl_helpers.hpp" @@ -185,3 +186,29 @@ UNIT_TEST(ReadVarInt64Array) } } } + +UNIT_TEST(VarInt_ShortSortedArray) +{ + uint32_t constexpr maxVal = (uint32_t(1) << 30) - 1; + std::vector samples[] = { + {0}, + {10, 10000}, + {maxVal - 2, maxVal - 1, maxVal}, + }; + + for (auto const & s : samples) + { + std::vector buffer; + PushBackByteSink sink(buffer); + + WriteVarUInt32SortedShortArray(s, sink); + + MemReader reader(buffer.data(), buffer.size()); + ReaderSource src(reader); + + std::vector actual; + ReadVarUInt32SortedShortArray(src, actual); + + TEST_EQUAL(s, actual, ()); + } +} diff --git a/libs/coding/varint.hpp b/libs/coding/varint.hpp index b34430118..e401f7494 100644 --- a/libs/coding/varint.hpp +++ b/libs/coding/varint.hpp @@ -3,13 +3,10 @@ #include "coding/write_to_sink.hpp" #include "base/assert.hpp" -#include "base/base.hpp" #include "base/bits.hpp" #include "base/exception.hpp" #include "base/stl_helpers.hpp" -#include -#include #include // Writes any unsigned integer type using optimal bytes count, platform-independent. @@ -296,6 +293,53 @@ void const * ReadVarUint64Array(void const * pBeg, size_t count, F f) template void WriteVarUintArray(Cont const & v, Sink & sink) { - for (size_t i = 0; i != v.size(); ++i) - WriteVarUint(sink, v[i]); + for (auto e : v) + WriteVarUint(sink, e); } + +/// @name Special functions to read/write varint array when each value stores a control bit "has next". +/// Useful for short (>90% have 1 value) arrays. +/// @{ +template +void WriteVarUInt32SortedShortArray(std::vector const & cont, Sink & sink) +{ + CHECK(!cont.empty(), ()); + CHECK(base::IsSortedAndUnique(cont), ()); + + uint32_t prev = 0; + size_t const sz = cont.size(); + for (size_t i = 0; i < sz; ++i) + { + uint32_t v = cont[i] - prev; + prev = cont[i]; + + CHECK((v & (uint32_t(3) << 30)) == 0, ()); // leading 2 bits are zeros + v <<= 1; + // set 1-bit if have a next value + if (i + 1 < sz) + v |= 0x1; + + WriteVarUint(sink, v); + } +} + +/// @todo Refactor on raw pointers (same as ReadXXX functions above). +/// ArrayByteSource isn't as fast as pointers :) +template +void ReadVarUInt32SortedShortArray(Source & src, ContT & cont) +{ + cont.clear(); + + bool hasNext = false; + uint32_t prev = 0; + do + { + uint32_t const v = ReadVarUint(src); + hasNext = (v & 0x1) != 0; + + prev += (v >> 1); + cont.push_back(prev); + } + while (hasNext); +} +/// @}