Coverage Report

Created: 2024-07-18 11:41

src/zserio/BitStreamReader.h
Line
Count
Source
1
#ifndef ZSERIO_BIT_STREAM_READER_H_INC
2
#define ZSERIO_BIT_STREAM_READER_H_INC
3
4
#include <algorithm>
5
#include <cstddef>
6
#include <cstring>
7
8
#include "zserio/BitBuffer.h"
9
#include "zserio/RebindAlloc.h"
10
#include "zserio/Span.h"
11
#include "zserio/String.h"
12
#include "zserio/Types.h"
13
#include "zserio/Vector.h"
14
15
namespace zserio
16
{
17
18
/**
19
 * Reader class which allows to read various data from the bit stream.
20
 */
21
class BitStreamReader
22
{
23
public:
24
    /** Type for bit position. */
25
    using BitPosType = size_t;
26
27
    /**
28
     * Context of the reader defining its state.
29
     */
30
    struct ReaderContext
31
    {
32
        /**
33
         * Constructor.
34
         *
35
         * \param readBuffer Span to the buffer to read.
36
         * \param readBufferBitSize Size of the buffer in bits.
37
         */
38
        explicit ReaderContext(Span<const uint8_t> readBuffer, size_t readBufferBitSize);
39
40
        /**
41
         * Destructor.
42
         */
43
        ~ReaderContext() = default;
44
45
        /**
46
         * Copying and moving is disallowed!
47
         * \{
48
         */
49
        ReaderContext(const ReaderContext&) = delete;
50
        ReaderContext& operator=(const ReaderContext&) = delete;
51
52
        ReaderContext(const ReaderContext&&) = delete;
53
        ReaderContext& operator=(const ReaderContext&&) = delete;
54
        /**
55
         * \}
56
         */
57
58
        Span<const uint8_t> buffer; /**< Buffer to read from. */
59
        const BitPosType bufferBitSize; /**< Size of the buffer in bits. */
60
61
        uintptr_t cache; /**< Bit cache to optimize bit reading. */
62
        uint8_t cacheNumBits; /**< Num bits available in the bit cache. */
63
64
        BitPosType bitIndex; /**< Current bit index. */
65
    };
66
67
    /**
68
     * Constructor from raw buffer.
69
     *
70
     * \param buffer Pointer to the buffer to read.
71
     * \param bufferByteSize Size of the buffer in bytes.
72
     */
73
    explicit BitStreamReader(const uint8_t* buffer, size_t bufferByteSize);
74
75
    /**
76
     * Constructor from buffer passed as a Span.
77
     *
78
     * \param buffer Buffer to read.
79
     */
80
    explicit BitStreamReader(Span<const uint8_t> buffer);
81
82
    /**
83
     * Constructor from buffer passed as a Span with exact bit size.
84
     *
85
     * \param buffer Buffer to read.
86
     * \param bufferBitSize Size of the buffer in bits.
87
     */
88
    explicit BitStreamReader(Span<const uint8_t> buffer, size_t bufferBitSize);
89
90
    /**
91
     * Constructor from raw buffer with exact bit size.
92
     *
93
     * \param buffer Pointer to buffer to read.
94
     * \param bufferBitSize Size of the buffer in bits.
95
     */
96
    explicit BitStreamReader(const uint8_t* buffer, size_t bufferBitSize, BitsTag);
97
98
    /**
99
     * Constructor from bit buffer.
100
     *
101
     * \param bitBuffer Bit buffer to read from.
102
     */
103
    template <typename ALLOC>
104
    explicit BitStreamReader(const BasicBitBuffer<ALLOC>& bitBuffer) :
105
            BitStreamReader(bitBuffer.getData(), bitBuffer.getBitSize())
106
390
    {}
107
108
    /**
109
     * Destructor.
110
     */
111
    ~BitStreamReader() = default;
112
113
    /**
114
     * Reads unsigned bits up to 32-bits.
115
     *
116
     * \param numBits Number of bits to read.
117
     *
118
     * \return Read bits.
119
     */
120
    uint32_t readBits(uint8_t numBits = 32);
121
122
    /**
123
     * Reads unsigned bits up to 64-bits.
124
     *
125
     * \param numBits Number of bits to read.
126
     *
127
     * \return Read bits.
128
     */
129
    uint64_t readBits64(uint8_t numBits = 64);
130
131
    /**
132
     * Reads signed bits up to 32-bits.
133
     *
134
     * \param numBits Number of bits to read.
135
     *
136
     * \return Read bits.
137
     */
138
    int32_t readSignedBits(uint8_t numBits = 32);
139
140
    /**
141
     * Reads signed bits up to 64-bits.
142
     *
143
     * \param numBits Number of bits to read.
144
     *
145
     * \return Read bits.
146
     */
147
    int64_t readSignedBits64(uint8_t numBits = 64);
148
149
    /**
150
     * Reads signed variable integer up to 64 bits.
151
     *
152
     * \return Read varint64.
153
     */
154
    int64_t readVarInt64();
155
156
    /**
157
     * Reads signed variable integer up to 32 bits.
158
     *
159
     * \return Read varint32.
160
     */
161
    int32_t readVarInt32();
162
163
    /**
164
     * Reads signed variable integer up to 16 bits.
165
     *
166
     * \return Read varint16.
167
     */
168
    int16_t readVarInt16();
169
170
    /**
171
     * Read unsigned variable integer up to 64 bits.
172
     *
173
     * \return Read varuint64.
174
     */
175
    uint64_t readVarUInt64();
176
177
    /**
178
     * Read unsigned variable integer up to 32 bits.
179
     *
180
     * \return Read varuint32.
181
     */
182
    uint32_t readVarUInt32();
183
184
    /**
185
     * Read unsigned variable integer up to 16 bits.
186
     *
187
     * \return Read varuint16.
188
     */
189
    uint16_t readVarUInt16();
190
191
    /**
192
     * Reads signed variable integer up to 72 bits.
193
     *
194
     * \return Read varint.
195
     */
196
    int64_t readVarInt();
197
198
    /**
199
     * Read unsigned variable integer up to 72 bits.
200
     *
201
     * \return Read varuint.
202
     */
203
    uint64_t readVarUInt();
204
205
    /**
206
     * Read variable size integer up to 40 bits.
207
     *
208
     * \return Read varsize.
209
     */
210
    uint32_t readVarSize();
211
212
    /**
213
     * Reads 16-bit float.
214
     *
215
     * \return Read float16.
216
     */
217
    float readFloat16();
218
219
    /**
220
     * Reads 32-bit float.
221
     *
222
     * \return Read float32.
223
     */
224
    float readFloat32();
225
226
    /**
227
     * Reads 64-bit float double.
228
     *
229
     * \return Read float64.
230
     */
231
    double readFloat64();
232
233
    /**
234
     * Reads bytes.
235
     *
236
     * \param alloc Allocator to use.
237
     *
238
     * \return Read bytes as a vector.
239
     */
240
    template <typename ALLOC = std::allocator<uint8_t>>
241
    vector<uint8_t, ALLOC> readBytes(const ALLOC& alloc = ALLOC())
242
85
    {
243
85
        const size_t len = static_cast<size_t>(readVarSize());
244
85
        const BitPosType beginBitPosition = getBitPosition();
245
85
        if ((beginBitPosition & 0x07U) != 0)
246
40
        {
247
            // we are not aligned to byte
248
40
            vector<uint8_t, ALLOC> value{alloc};
249
40
            value.reserve(len);
250
132
            for (size_t i = 0; i < len; 
++i92
)
251
92
            {
252
92
                value.push_back(readByte());
253
92
            }
254
40
            return value;
255
40
        }
256
45
        else
257
45
        {
258
            // we are aligned to byte
259
45
            setBitPosition(beginBitPosition + len * 8);
260
45
            Span<const uint8_t>::iterator beginIt = m_context.buffer.begin() + beginBitPosition / 8;
261
45
            return vector<uint8_t, ALLOC>(beginIt, beginIt + len, alloc);
262
45
        }
263
85
    }
264
265
    /**
266
     * Reads an UTF-8 string.
267
     *
268
     * \param alloc Allocator to use.
269
     *
270
     * \return Read string.
271
     */
272
    template <typename ALLOC = std::allocator<char>>
273
    string<ALLOC> readString(const ALLOC& alloc = ALLOC())
274
139
    {
275
139
        const size_t len = static_cast<size_t>(readVarSize());
276
139
        const BitPosType beginBitPosition = getBitPosition();
277
139
        if ((beginBitPosition & 0x07U) != 0)
278
60
        {
279
            // we are not aligned to byte
280
60
            string<ALLOC> value{alloc};
281
60
            value.reserve(len);
282
942
            for (size_t i = 0; i < len; 
++i882
)
283
882
            {
284
882
                value.push_back(static_cast<char>(readByte()));
285
882
            }
286
60
            return value;
287
60
        }
288
79
        else
289
79
        {
290
            // we are aligned to byte
291
79
            setBitPosition(beginBitPosition + len * 8);
292
79
            Span<const uint8_t>::iterator beginIt = m_context.buffer.begin() + beginBitPosition / 8;
293
79
            return string<ALLOC>(beginIt, beginIt + len, alloc);
294
79
        }
295
139
    }
296
297
    /**
298
     * Reads bool as a single bit.
299
     *
300
     * \return Read bool value.
301
     */
302
    bool readBool();
303
304
    /**
305
     * Reads a bit buffer.
306
     *
307
     * \param alloc Allocator to use.
308
     *
309
     * \return Read bit buffer.
310
     */
311
    template <typename ALLOC = std::allocator<uint8_t>>
312
    BasicBitBuffer<RebindAlloc<ALLOC, uint8_t>> readBitBuffer(const ALLOC& allocator = ALLOC())
313
117
    {
314
117
        const size_t bitSize = static_cast<size_t>(readVarSize());
315
117
        const size_t numBytesToRead = bitSize / 8;
316
117
        const uint8_t numRestBits = static_cast<uint8_t>(bitSize - numBytesToRead * 8);
317
117
        BasicBitBuffer<RebindAlloc<ALLOC, uint8_t>> bitBuffer(bitSize, allocator);
318
117
        Span<uint8_t> buffer = bitBuffer.getData();
319
117
        const BitPosType beginBitPosition = getBitPosition();
320
117
        const Span<uint8_t>::iterator itEnd = buffer.begin() + numBytesToRead;
321
117
        if ((beginBitPosition & 0x07U) != 0)
322
54
        {
323
            // we are not aligned to byte
324
114
            for (Span<uint8_t>::iterator it = buffer.begin(); it != itEnd; 
++it60
)
325
60
            {
326
60
                *it = static_cast<uint8_t>(readBits(8));
327
60
            }
328
54
        }
329
63
        else
330
63
        {
331
            // we are aligned to byte
332
63
            setBitPosition(beginBitPosition + numBytesToRead * 8);
333
63
            Span<const uint8_t>::const_iterator sourceIt = m_context.buffer.begin() + beginBitPosition / 8;
334
63
            std::copy(sourceIt, sourceIt + numBytesToRead, buffer.begin());
335
63
        }
336
337
117
        if (numRestBits > 0)
338
114
        {
339
114
            *itEnd = static_cast<uint8_t>(readBits(numRestBits) << (8U - numRestBits));
340
114
        }
341
342
117
        return bitBuffer;
343
117
    }
344
345
    /**
346
     * Gets current bit position.
347
     *
348
     * \return Current bit position.
349
     */
350
    BitPosType getBitPosition() const
351
10.2k
    {
352
10.2k
        return m_context.bitIndex;
353
10.2k
    }
354
355
    /**
356
     * Sets current bit position. Use with caution!
357
     *
358
     * \param position New bit position.
359
     */
360
    void setBitPosition(BitPosType position);
361
362
    /**
363
     * Moves current bit position to perform the requested bit alignment.
364
     *
365
     * \param alignment Size of the alignment in bits.
366
     */
367
    void alignTo(size_t alignment);
368
369
    /**
370
     * Gets size of the underlying buffer in bits.
371
     *
372
     * \return Buffer bit size.
373
     */
374
    size_t getBufferBitSize() const
375
149
    {
376
149
        return m_context.bufferBitSize;
377
149
    }
378
379
private:
380
    uint8_t readByte();
381
382
    ReaderContext m_context;
383
};
384
385
} // namespace zserio
386
387
#endif // ifndef ZSERIO_BIT_STREAM_READER_H_INC