123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- #pragma once
- #include <library/cpp/deprecated/accessors/accessors.h>
- #include <util/stream/output.h>
- #include <util/system/yassert.h>
- #include <util/generic/bitops.h>
- #include <util/generic/vector.h>
- #include <util/generic/yexception.h>
- namespace NBitIO {
- // Based on junk/solar/codecs/bitstream.h
- // Almost all code is hard tuned for sequential write performance.
- // Use tools/bursttrie/benchmarks/bitstreams_benchmark to check your changes.
- inline constexpr ui64 BytesUp(ui64 bits) {
- return (bits + 7ULL) >> 3ULL;
- }
- template <typename TStorage>
- class TBitOutputBase {
- protected:
- TStorage* Storage;
- ui64 FreeBits;
- ui64 Active;
- ui64 Offset;
- public:
- TBitOutputBase(TStorage* storage)
- : Storage(storage)
- , FreeBits(64)
- , Active()
- , Offset()
- {
- }
- ui64 GetOffset() const {
- return Offset + BytesUp(64ULL - FreeBits);
- }
- ui64 GetBitOffset() const {
- return (64ULL - FreeBits) & 7ULL;
- }
- ui64 GetByteReminder() const {
- return FreeBits & 7ULL;
- }
- public:
- // interface
- // Write "bits" lower bits.
- Y_FORCE_INLINE void Write(ui64 data, ui64 bits) {
- if (FreeBits < bits) {
- if (FreeBits) {
- bits -= FreeBits;
- Active |= (data & MaskLowerBits(FreeBits)) << (64ULL - FreeBits);
- data >>= FreeBits;
- FreeBits = 0ULL;
- }
- Flush();
- }
- Active |= bits ? ((data & MaskLowerBits(bits)) << (64ULL - FreeBits)) : 0;
- FreeBits -= bits;
- }
- // Write "bits" lower bits starting from "skipbits" bit.
- Y_FORCE_INLINE void Write(ui64 data, ui64 bits, ui64 skipbits) {
- Write(data >> skipbits, bits);
- }
- // Unsigned wordwise write. Underlying data is splitted in "words" of "bits(data) + 1(flag)" bits.
- // Like this: (unsigned char)0x2E<3> (0000 0010 1110) <=> 1110 0101
- // fddd fddd
- template <ui64 bits>
- Y_FORCE_INLINE void WriteWords(ui64 data) {
- do {
- ui64 part = data;
- data >>= bits;
- part |= FastZeroIfFalse(data, NthBit64(bits));
- Write(part, bits + 1ULL);
- } while (data);
- }
- Y_FORCE_INLINE ui64 /* padded bits */ Flush() {
- const ui64 ubytes = 8ULL - (FreeBits >> 3ULL);
- if (ubytes) {
- Active <<= FreeBits;
- Active >>= FreeBits;
- Storage->WriteData((const char*)&Active, (const char*)&Active + ubytes);
- Offset += ubytes;
- }
- const ui64 padded = FreeBits & 7;
- FreeBits = 64ULL;
- Active = 0ULL;
- return padded;
- }
- virtual ~TBitOutputBase() {
- Flush();
- }
- private:
- static Y_FORCE_INLINE ui64 FastZeroIfFalse(bool cond, ui64 iftrue) {
- return -i64(cond) & iftrue;
- }
- };
- template <typename TVec>
- class TBitOutputVectorImpl {
- TVec* Data;
- public:
- void WriteData(const char* begin, const char* end) {
- NAccessors::Append(*Data, begin, end);
- }
- TBitOutputVectorImpl(TVec* data)
- : Data(data)
- {
- }
- };
- template <typename TVec>
- struct TBitOutputVector: public TBitOutputVectorImpl<TVec>, public TBitOutputBase<TBitOutputVectorImpl<TVec>> {
- inline TBitOutputVector(TVec* data)
- : TBitOutputVectorImpl<TVec>(data)
- , TBitOutputBase<TBitOutputVectorImpl<TVec>>(this)
- {
- }
- };
- class TBitOutputArrayImpl {
- char* Data;
- size_t Left;
- public:
- void WriteData(const char* begin, const char* end) {
- size_t sz = end - begin;
- Y_ABORT_UNLESS(sz <= Left, " ");
- memcpy(Data, begin, sz);
- Data += sz;
- Left -= sz;
- }
- TBitOutputArrayImpl(char* begin, size_t len)
- : Data(begin)
- , Left(len)
- {
- }
- };
- struct TBitOutputArray: public TBitOutputArrayImpl, public TBitOutputBase<TBitOutputArrayImpl> {
- inline TBitOutputArray(char* begin, size_t len)
- : TBitOutputArrayImpl(begin, len)
- , TBitOutputBase<TBitOutputArrayImpl>(this)
- {
- }
- };
- using TBitOutputYVector = TBitOutputVector<TVector<char>>;
- class TBitOutputStreamImpl {
- IOutputStream* Out;
- public:
- void WriteData(const char* begin, const char* end) {
- Out->Write(begin, end - begin);
- }
- TBitOutputStreamImpl(IOutputStream* out)
- : Out(out)
- {
- }
- };
- struct TBitOutputStream: public TBitOutputStreamImpl, public TBitOutputBase<TBitOutputStreamImpl> {
- inline TBitOutputStream(IOutputStream* out)
- : TBitOutputStreamImpl(out)
- , TBitOutputBase<TBitOutputStreamImpl>(this)
- {
- }
- };
- }
|