#pragma once #include "codecs.h" #include #include #include #include namespace NCodecs { template class TDeltaCodec: public ICodec { static_assert(std::is_integral::value, "expect std::is_integral::value"); public: using TUnsigned = std::make_unsigned_t; using TSigned = std::make_signed_t; using TDelta = std::conditional_t; private: const TDelta MinDelta{Min()}; const TDelta MaxDelta{Max() - 1}; const TDelta InvalidDelta{MaxDelta + 1}; Y_FORCE_INLINE static TDelta AddSafe(TUnsigned a, TUnsigned b) { return a + b; } Y_FORCE_INLINE static TDelta SubSafe(TUnsigned a, TUnsigned b) { return a - b; } public: struct TDecoder { const TDelta InvalidDelta{Max()}; T Last = 0; T Result = 0; bool First = true; bool Invalid = false; Y_FORCE_INLINE bool Decode(TDelta t) { if (Y_UNLIKELY(First)) { First = false; Result = Last = t; return true; } if (Y_UNLIKELY(Invalid)) { Invalid = false; Last = 0; Result = t; return true; } Result = (Last += t); Invalid = t == InvalidDelta; return !Invalid; } }; public: static TStringBuf MyName(); TDeltaCodec() { MyTraits.SizeOfInputElement = sizeof(T); MyTraits.AssumesStructuredInput = true; } TString GetName() const override { return ToString(MyName()); } template static void AppendTo(TBuffer& b, TItem t) { b.Append((char*)&t, sizeof(t)); } ui8 Encode(TStringBuf s, TBuffer& b) const override { b.Clear(); if (s.empty()) { return 0; } b.Reserve(s.size()); TArrayRef tin{(const T*)s.data(), s.size() / sizeof(T)}; const T* it = tin.begin(); TDelta last = *(it++); AppendTo(b, last); TDelta maxt = SubSafe(MaxDelta, last); TDelta mint = AddSafe(MinDelta, last); for (; it != tin.end(); ++it) { TDelta t = *it; if (Y_LIKELY((t >= mint) & (t <= maxt))) { AppendTo(b, t - last); last = t; maxt = SubSafe(MaxDelta, last); mint = AddSafe(MinDelta, last); } else { // delta overflow AppendTo(b, InvalidDelta); AppendTo(b, t); last = 0; maxt = MaxDelta; mint = MinDelta; } } return 0; } void Decode(TStringBuf s, TBuffer& b) const override { b.Clear(); if (s.empty()) { return; } b.Reserve(s.size()); TArrayRef tin{(const T*)s.data(), s.size() / sizeof(T)}; TDecoder dec; for (const T* it = tin.begin(); it != tin.end(); ++it) { T tmp; memcpy(&tmp, it, sizeof(tmp)); if (dec.Decode(tmp)) { AppendTo(b, dec.Result); } } } protected: void DoLearn(ISequenceReader&) override { } }; }