#pragma once #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_add.hpp" #include #include /// This function writes, using optimal bytes count. /// Pass any integral type and it will write platform-independent. template void WriteVarUint(TSink & dst, T value) { static_assert(is_unsigned::value, ""); while (value > 127) { WriteToSink(dst, static_cast((value & 127) | 128)); value >>= 7; } WriteToSink(dst, static_cast(value)); } namespace impl { template uint32_t ReadVarUint(TSource & src, uint32_t const *) { uint32_t res = 0; { uint8_t next0; src.Read(&next0, 1); res |= (static_cast(next0) & 127); if (!(next0 & 128)) return res; } { uint8_t next1; src.Read(&next1, 1); res |= (static_cast(next1) & 127) << 7; if (!(next1 & 128)) return res; } { uint8_t next2; src.Read(&next2, 1); res |= (static_cast(next2) & 127) << 14; if (!(next2 & 128)) return res; } { uint8_t next3; src.Read(&next3, 1); res |= (static_cast(next3) & 127) << 21; if (!(next3 & 128)) return res; } { uint8_t next4; src.Read(&next4, 1); res |= (static_cast(next4) & 127) << 28; ASSERT(!(next4 & 128), (next4)); ASSERT_LESS(next4, 1 << (32 - 28), ()); return res; } } template uint64_t ReadVarUint(TSource & src, uint64_t const *) { uint32_t res0 = 0; { uint8_t next0; src.Read(&next0, 1); res0 |= (static_cast(next0) & 127); if (!(next0 & 128)) return res0; } { uint8_t next1; src.Read(&next1, 1); res0 |= (static_cast(next1) & 127) << 7; if (!(next1 & 128)) return res0; } { uint8_t next2; src.Read(&next2, 1); res0 |= (static_cast(next2) & 127) << 14; if (!(next2 & 128)) return res0; } { uint8_t next3; src.Read(&next3, 1); res0 |= (static_cast(next3) & 127) << 21; if (!(next3 & 128)) return res0; } uint32_t res1 = 0; { uint8_t next4; src.Read(&next4, 1); res1 |= (static_cast(next4) & 127); if (!(next4 & 128)) return (static_cast(res1) << 28) + res0; } { uint8_t next5; src.Read(&next5, 1); res1 |= (static_cast(next5) & 127) << 7; if (!(next5 & 128)) return (static_cast(res1) << 28) + res0; } { uint8_t next6; src.Read(&next6, 1); res1 |= (static_cast(next6) & 127) << 14; if (!(next6 & 128)) return (static_cast(res1) << 28) + res0; } { uint8_t next7; src.Read(&next7, 1); res1 |= (static_cast(next7) & 127) << 21; if (!(next7 & 128)) return (static_cast(res1) << 28) + res0; } uint32_t res2 = 0; { uint8_t next8; src.Read(&next8, 1); res2 |= (static_cast(next8) & 127); if (!(next8 & 128)) return (static_cast(res2) << 56) + (static_cast(res1) << 28) + res0; } { uint8_t next9; src.Read(&next9, 1); res2 |= (static_cast(next9) & 127) << 7; ASSERT(!(next9 & 128), (next9)); ASSERT_LESS_OR_EQUAL(next9, 1 << (64 - 63), ()); return (static_cast(res2) << 56) + (static_cast(res1) << 28) + res0; } } } template T ReadVarUint(TSource & src) { static_assert((is_same::value || is_same::value), ""); return ::impl::ReadVarUint(src, static_cast(NULL)); /* Generic code commented out. static_assert(is_unsigned::value, ""); T res = 0; unsigned int bits = 0; for (; bits < sizeof(T) * 8 - 7; bits += 7) { uint8_t next; src.Read(&next, 1); res |= (static_cast(next) & 127) << bits; if (!(next & 128)) return res; } uint8_t next; src.Read(&next, 1); ASSERT_LESS_OR_EQUAL(next, (255 >> (sizeof(T) * 8 - bits)), ()); ASSERT(!(next & 128), (next, bits)); res |= static_cast(next) << bits; return res */ } template void WriteVarInt(TSink & dst, T value) { static_assert(is_signed::value, ""); WriteVarUint(dst, bits::ZigZagEncode(value)); } template T ReadVarInt(TSource & src) { static_assert(is_signed::value, ""); return bits::ZigZagDecode(ReadVarUint>(src)); } DECLARE_EXCEPTION(ReadVarIntException, RootException); namespace impl { class ReadVarInt64ArrayUntilBufferEnd { public: explicit ReadVarInt64ArrayUntilBufferEnd(void const * pEnd) : m_pEnd(pEnd) {} bool Continue(void const * p) const { ASSERT_LESS_OR_EQUAL(reinterpret_cast(p), reinterpret_cast(m_pEnd), ()); return p < m_pEnd; } void NextVarInt() {} private: void const * m_pEnd; }; class ReadVarInt64ArrayGivenSize { public: explicit ReadVarInt64ArrayGivenSize(size_t const count) : m_Remaining(count) {} bool Continue(void const *) const { return m_Remaining > 0; } void NextVarInt() { --m_Remaining; } private: size_t m_Remaining; }; template inline void const * ReadVarInt64Array(void const * pBeg, WhileConditionT whileCondition, F f, ConverterT converter) { uint8_t const * const pBegChar = static_cast(pBeg); uint64_t res64 = 0; uint32_t res32 = 0; uint32_t count32 = 0; uint32_t count64 = 0; uint8_t const * p = pBegChar; while (whileCondition.Continue(p)) { uint8_t const t = *p++; res32 += (static_cast(t & 127) << count32); count32 += 7; if (!(t & 128)) { f(converter((static_cast(res32) << count64) + res64)); whileCondition.NextVarInt(); 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, ()); return p; } } template inline void const * ReadVarInt64Array(void const * pBeg, void const * pEnd, F f) { return impl::ReadVarInt64Array( pBeg, impl::ReadVarInt64ArrayUntilBufferEnd(pEnd), f, &bits::ZigZagDecode); } template inline void const * ReadVarUint64Array(void const * pBeg, void const * pEnd, F f) { return impl::ReadVarInt64Array(pBeg, impl::ReadVarInt64ArrayUntilBufferEnd(pEnd), f, IdFunctor()); } template inline void const * ReadVarInt64Array(void const * pBeg, size_t count, F f) { return impl::ReadVarInt64Array( pBeg, impl::ReadVarInt64ArrayGivenSize(count), f, &bits::ZigZagDecode); } template inline void const * ReadVarUint64Array(void const * pBeg, size_t count, F f) { return impl::ReadVarInt64Array(pBeg, impl::ReadVarInt64ArrayGivenSize(count), f, IdFunctor()); } template inline void WriteVarUintArray(Cont const & v, Sink & sink) { for (size_t i = 0; i != v.size(); ++i) WriteVarUint(sink, v[i]); }