aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/bit_io/bitinput.h
blob: 288f04c96f92f8ff7744c890682a3ae34427651b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#pragma once

#include "bitinput_impl.h"

#include <util/system/yassert.h>
#include <util/generic/vector.h>
#include <util/generic/yexception.h>

#include <iterator>

namespace NBitIO {
    // Based on junk/solar/codecs/bitstream.h

    class TBitInput: protected  TBitInputImpl {
    public:
        template <typename TVec>
        explicit TBitInput(const TVec& vec)
            : TBitInputImpl(std::begin(vec), std::end(vec))
        {
        }

        TBitInput(const char* start, const char* end)
            : TBitInputImpl(start, end)
        {
        }

        bool Eof() const {
            return EofImpl();
        }

        ui64 GetOffset() const {
            ui64 bo = BitOffset();
            return bo / 8 + !!(bo % 8);
        }

        using TBitInputImpl::GetBitLength;

        ui64 GetBitOffset() const {
            return BitOffset() % 8;
        }

    public:
        // Read with static number of bits.
        // Preserves what's in result.
        template <ui64 bits, typename T>
        Y_FORCE_INLINE bool ReadK(T& result, ui64 skipbits) { 
            ui64 r64 = 0;
            bool ret = bits <= 56 ? ReadKImpl<bits>(r64) : ReadSafe(r64, bits);
            CopyToResultK<bits>(result, r64, skipbits);
            return ret;
        }

        // Read with static number of bits.
        // Zeroes other bits in result.
        template <ui64 bits, typename T>
        Y_FORCE_INLINE bool ReadK(T& result) { 
            ui64 r = 0;
            bool res = ReadK<bits>(r);
            result = r;
            return res;
        }

        // Shortcut to impl.
        template <ui64 bits>
        Y_FORCE_INLINE bool ReadK(ui64& result) { 
            if (bits <= 56)
                return ReadKImpl<bits>(result);

            ui64 r1 = 0ULL;
            ui64 r2 = 0ULL;

            bool ret1 = ReadKImpl<56ULL>(r1);
            bool ret2 = ReadKImpl<(bits > 56ULL ? bits - 56ULL : 0) /*or else we get negative param in template*/>(r2);

            result = (r2 << 56ULL) | r1;

            return ret1 & ret2;
        }

        // It's safe to read up to 64 bits.
        // Zeroes other bits in result.
        template <typename T>
        Y_FORCE_INLINE bool ReadSafe(T& result, ui64 bits) { 
            if (bits <= 56ULL)
                return Read(result, bits);

            ui64 r1 = 0ULL;
            ui64 r2 = 0ULL;

            bool ret1 = ReadKImpl<56ULL>(r1);
            bool ret2 = ReadImpl(r2, bits - 56ULL);

            result = (r2 << 56ULL) | r1;

            return ret1 & ret2;
        }

        // It's safe to read up to 64 bits.
        // Preserves what's in result.
        template <typename T>
        Y_FORCE_INLINE bool ReadSafe(T& result, ui64 bits, ui64 skipbits) { 
            ui64 r64 = 0;
            bool ret = ReadSafe(r64, bits);
            CopyToResult(result, r64, bits, skipbits);
            return ret;
        }

        // Do not try to read more than 56 bits at once. Split in two reads or use ReadSafe.
        // Zeroes other bits in result.
        template <typename T>
        Y_FORCE_INLINE bool Read(T& result, ui64 bits) { 
            ui64 r64 = 0;
            bool ret = ReadImpl(r64, bits);
            result = r64;
            return ret;
        }

        // Shortcut to impl.
        Y_FORCE_INLINE bool Read(ui64& result, ui64 bits) { 
            return ReadImpl(result, bits);
        }

        // Do not try to read more than 56 bits at once. Split in two reads or use ReadSafe.
        // Preserves what's in result.
        template <typename T>
        Y_FORCE_INLINE bool Read(T& result, ui64 bits, ui64 skipbits) { 
            ui64 r64 = 0;
            bool ret = ReadImpl(r64, bits);
            CopyToResult(result, r64, bits, skipbits);
            return ret;
        }

        // Unsigned wordwise read. Underlying data is splitted in "words" of "bits(data) + 1(flag)" bits.
        // Like this: (unsigned char)0x2E<3> (0010 1110) <=> 1110 0101
        //                                                   fddd fddd
        template <ui64 bits, typename T>
        Y_FORCE_INLINE bool ReadWords(T& result) { 
            ui64 r64 = 0;

            bool retCode = ReadWordsImpl<bits>(r64);
            result = r64;

            return retCode;
        }

        // Shortcut to impl.
        template <ui64 bits>
        Y_FORCE_INLINE bool ReadWords(ui64& result) { 
            return ReadWordsImpl<bits>(result);
        }

        Y_FORCE_INLINE bool Back(int bits) { 
            return Seek(BitOffset() - bits);
        }

        Y_FORCE_INLINE bool Seek(int bitoffset) { 
            return TBitInputImpl::Seek(bitoffset);
        }

        // A way to read a portion of bits at random location.
        // Didn't want to complicate sequential read, neither to copypaste.
        template <typename T>
        Y_FORCE_INLINE bool ReadRandom(ui64 bitoffset, T& result, ui64 bits, ui64 skipbits) { 
            const ui64 curr = BitOffset();
            Seek(bitoffset);
            bool ret = ReadSafe<T>(result, bits, skipbits);
            Seek(curr);
            return ret;
        }
    };
}