diff --git a/coding/coding_tests/varint_test.cpp b/coding/coding_tests/varint_test.cpp index 4a97039e4a..0889688e67 100644 --- a/coding/coding_tests/varint_test.cpp +++ b/coding/coding_tests/varint_test.cpp @@ -1,8 +1,9 @@ -#include "../../base/SRC_FIRST.hpp" +#include "../varint.hpp" #include "../../testing/testing.hpp" #include "../byte_stream.hpp" -#include "../varint.hpp" +#include "../../base/macros.hpp" +#include "../../base/stl_add.hpp" namespace { @@ -95,3 +96,53 @@ UNIT_TEST(VarIntMax) TestVarInt(int64_t(9223372036854775807LL)); // TestVarInt(int64_t(-9223372036854775808LL)); } + +UNIT_TEST(ReadVarInt64Array_EmptyArray) +{ + vector result; + ReadVarInt64Array(NULL, NULL, MakeBackInsertFunctor(result)); + TEST_EQUAL(result, vector(), ()); +} + +UNIT_TEST(ReadVarInt64Array) +{ + vector values; + + // Fill in values. + { + int64_t const baseValues [] = + { + 0, 127, 128, (2 << 28) - 1, (2 << 28), (2 << 31), (2 << 31) - 1, + 0xFFFFFFFF - 1, 0xFFFFFFFF, 0xFFFFFFFFFFULL + }; + for (size_t i = 0; i < ARRAY_SIZE(baseValues); ++i) + { + values.push_back(baseValues[i]); + values.push_back(-baseValues[i]); + } + sort(values.begin(), values.end()); + values.erase(unique(values.begin(), values.end()), values.end()); + } + + // Test all subsets. + for (size_t i = 1; i < 1 << values.size(); ++i) + { + vector testValues; + for (size_t j = 0; j < values.size(); ++j) + if (i & (1 << j)) + testValues.push_back(values[j]); + + vector data; + { + PushBackByteSink > dst(data); + for (size_t j = 0; j < testValues.size(); ++j) + WriteVarInt(dst, testValues[j]); + } + + vector result; + ASSERT_GREATER(data.size(), 0, ()); + ReadVarInt64Array(&data[0], &data[0] + data.size(), MakeBackInsertFunctor(result)); + TEST_EQUAL(result, testValues, ()); + } +} + diff --git a/coding/varint.hpp b/coding/varint.hpp index 00fe7999f5..d43f699102 100644 --- a/coding/varint.hpp +++ b/coding/varint.hpp @@ -3,7 +3,7 @@ #include "../base/assert.hpp" #include "../base/base.hpp" - +#include "../base/exception.hpp" #include "../std/type_traits.hpp" @@ -185,3 +185,39 @@ template T ReadVarInt(TSource & src) STATIC_ASSERT(is_signed::value); return ZigZagDecode(ReadVarUint::type>(src)); } + +DECLARE_EXCEPTION(ReadVarIntException, RootException); + +template void ReadVarInt64Array(void const * pBeg, void const * pEnd, F f) +{ + uint8_t const * const pBegChar = static_cast(pBeg); + uint8_t const * const pEndChar = static_cast(pEnd); + uint64_t res64 = 0; + uint32_t res32 = 0; + uint32_t count32 = 0; + uint32_t count64 = 0; + for (uint8_t const * p = pBegChar; p < pEndChar; ++p) + { + uint8_t const t = *p; + res32 += (static_cast(t & 127) << count32); + count32 += 7; + if (!(t & 128)) + { + f(ZigZagDecode((static_cast(res32) << count64) + res64)); + res64 = 0; + res32 = 0; + count32 = 0; + count64 = 0; + } + else if (count32 == 28) + { + res64 += (static_cast(res32) << count64); + res32 = 0; + count32 = 0; + count64 += 28; + } + } + ASSERT(count32 == 0 && res32 == 0 && res64 == 0, (res64, res32, count32)); + if (count32 != 0) + MYTHROW(ReadVarIntException, ()); +}