Coverage Report

Created: 2024-04-30 09:35

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
                value.push_back(readByte());
252
40
            return value;
253
40
        }
254
45
        else
255
45
        {
256
            // we are aligned to byte
257
45
            setBitPosition(beginBitPosition + len * 8);
258
45
            Span<const uint8_t>::iterator beginIt = m_context.buffer.begin() + beginBitPosition / 8;
259
45
            return vector<uint8_t, ALLOC>(beginIt, beginIt + len, alloc);
260
45
        }
261
85
    }
262
263
    /**
264
     * Reads an UTF-8 string.
265
     *
266
     * \param alloc Allocator to use.
267
     *
268
     * \return Read string.
269
     */
270
    template <typename ALLOC = std::allocator<char>>
271
    string<ALLOC> readString(const ALLOC& alloc = ALLOC())
272
139
    {
273
139
        const size_t len = static_cast<size_t>(readVarSize());
274
139
        const BitPosType beginBitPosition = getBitPosition();
275
139
        if ((beginBitPosition & 0x07U) != 0)
276
60
        {
277
            // we are not aligned to byte
278
60
            string<ALLOC> value{alloc};
279
60
            value.reserve(len);
280
942
            for (size_t i = 0; i < len; 
++i882
)
281
882
                value.push_back(static_cast<char>(readByte()));
282
60
            return value;
283
60
        }
284
79
        else
285
79
        {
286
            // we are aligned to byte
287
79
            setBitPosition(beginBitPosition + len * 8);
288
79
            Span<const uint8_t>::iterator beginIt = m_context.buffer.begin() + beginBitPosition / 8;
289
79
            return string<ALLOC>(beginIt, beginIt + len, alloc);
290
79
        }
291
139
    }
292
293
    /**
294
     * Reads bool as a single bit.
295
     *
296
     * \return Read bool value.
297
     */
298
    bool readBool();
299
300
    /**
301
     * Reads a bit buffer.
302
     *
303
     * \param alloc Allocator to use.
304
     *
305
     * \return Read bit buffer.
306
     */
307
    template <typename ALLOC = std::allocator<uint8_t>>
308
    BasicBitBuffer<RebindAlloc<ALLOC, uint8_t>> readBitBuffer(const ALLOC& allocator = ALLOC())
309
117
    {
310
117
        const size_t bitSize = static_cast<size_t>(readVarSize());
311
117
        const size_t numBytesToRead = bitSize / 8;
312
117
        const uint8_t numRestBits = static_cast<uint8_t>(bitSize - numBytesToRead * 8);
313
117
        BasicBitBuffer<RebindAlloc<ALLOC, uint8_t>> bitBuffer(bitSize, allocator);
314
117
        Span<uint8_t> buffer = bitBuffer.getData();
315
117
        const BitPosType beginBitPosition = getBitPosition();
316
117
        const Span<uint8_t>::iterator itEnd = buffer.begin() + numBytesToRead;
317
117
        if ((beginBitPosition & 0x07U) != 0)
318
54
        {
319
            // we are not aligned to byte
320
114
            for (Span<uint8_t>::iterator it = buffer.begin(); it != itEnd; 
++it60
)
321
60
                *it = static_cast<uint8_t>(readBits(8));
322
54
        }
323
63
        else
324
63
        {
325
            // we are aligned to byte
326
63
            setBitPosition(beginBitPosition + numBytesToRead * 8);
327
63
            Span<const uint8_t>::const_iterator sourceIt = m_context.buffer.begin() + beginBitPosition / 8;
328
63
            std::copy(sourceIt, sourceIt + numBytesToRead, buffer.begin());
329
63
        }
330
331
117
        if (numRestBits > 0)
332
114
            *itEnd = static_cast<uint8_t>(readBits(numRestBits) << (8U - numRestBits));
333
334
117
        return bitBuffer;
335
117
    }
336
337
    /**
338
     * Gets current bit position.
339
     *
340
     * \return Current bit position.
341
     */
342
    BitPosType getBitPosition() const
343
10.2k
    {
344
10.2k
        return m_context.bitIndex;
345
10.2k
    }
346
347
    /**
348
     * Sets current bit position. Use with caution!
349
     *
350
     * \param position New bit position.
351
     */
352
    void setBitPosition(BitPosType position);
353
354
    /**
355
     * Moves current bit position to perform the requested bit alignment.
356
     *
357
     * \param alignment Size of the alignment in bits.
358
     */
359
    void alignTo(size_t alignment);
360
361
    /**
362
     * Gets size of the underlying buffer in bits.
363
     *
364
     * \return Buffer bit size.
365
     */
366
    size_t getBufferBitSize() const
367
149
    {
368
149
        return m_context.bufferBitSize;
369
149
    }
370
371
private:
372
    uint8_t readByte();
373
374
    ReaderContext m_context;
375
};
376
377
} // namespace zserio
378
379
#endif // ifndef ZSERIO_BIT_STREAM_READER_H_INC