Coverage Report

Created: 2024-07-18 11:41

src/zserio/BitStreamWriter.h
Line
Count
Source
1
#ifndef ZSERIO_BIT_STREAM_WRITER_H_INC
2
#define ZSERIO_BIT_STREAM_WRITER_H_INC
3
4
#include <algorithm>
5
#include <cstddef>
6
#include <cstring>
7
8
#include "zserio/BitBuffer.h"
9
#include "zserio/CppRuntimeException.h"
10
#include "zserio/SizeConvertUtil.h"
11
#include "zserio/Span.h"
12
#include "zserio/StringView.h"
13
#include "zserio/Types.h"
14
15
namespace zserio
16
{
17
18
/**
19
 * Writer class which allows to write various data to the bit stream.
20
 */
21
class BitStreamWriter
22
{
23
public:
24
    /** Exception throw in case of insufficient capacity of the given buffer. */
25
    class InsufficientCapacityException : public CppRuntimeException
26
    {
27
    public:
28
        using CppRuntimeException::CppRuntimeException;
29
    };
30
31
    /** Type for bit position. */
32
    using BitPosType = size_t;
33
34
    /**
35
     * Constructor from externally allocated byte buffer.
36
     *
37
     * \param buffer External byte buffer to create from.
38
     * \param bufferBitSize Size of the buffer in bits.
39
     */
40
    explicit BitStreamWriter(uint8_t* buffer, size_t bufferBitSize, BitsTag);
41
42
    /**
43
     * Constructor from externally allocated byte buffer.
44
     *
45
     * \param buffer External byte buffer to create from.
46
     * \param bufferByteSize Size of the buffer in bytes.
47
     */
48
    explicit BitStreamWriter(uint8_t* buffer, size_t bufferByteSize);
49
50
    /**
51
     * Constructor from externally allocated byte buffer.
52
     *
53
     * \param buffer External buffer to create from as a Span.
54
     */
55
    explicit BitStreamWriter(Span<uint8_t> buffer);
56
57
    /**
58
     * Constructor from externally allocated byte buffer with exact bit size.
59
     *
60
     * \param buffer External buffer to create from as a Span.
61
     * \param bufferBitSize Size of the buffer in bits.
62
     */
63
    explicit BitStreamWriter(Span<uint8_t> buffer, size_t bufferBitSize);
64
65
    /**
66
     * Constructor from externally allocated bit buffer.
67
     *
68
     * \param bitBuffer External bit buffer to create from.
69
     */
70
    template <typename ALLOC>
71
    explicit BitStreamWriter(BasicBitBuffer<ALLOC>& bitBuffer) :
72
            BitStreamWriter(bitBuffer.getData(), bitBuffer.getBitSize())
73
469
    {}
74
75
    /**
76
     * Destructor.
77
     */
78
    ~BitStreamWriter() = default;
79
80
    /**
81
     * Copying and moving is disallowed!
82
     * \{
83
     */
84
    BitStreamWriter(const BitStreamWriter&) = delete;
85
    BitStreamWriter& operator=(const BitStreamWriter&) = delete;
86
87
    BitStreamWriter(const BitStreamWriter&&) = delete;
88
    BitStreamWriter& operator=(BitStreamWriter&&) = delete;
89
    /**
90
     * \}
91
     */
92
93
    /**
94
     * Writes unsigned bits up to 32 bits.
95
     *
96
     * \param data Data to write.
97
     * \param numBits Number of bits to write.
98
     */
99
    void writeBits(uint32_t data, uint8_t numBits = 32);
100
101
    /**
102
     * Writes unsigned bits up to 64 bits.
103
     *
104
     * \param data Data to write.
105
     * \param numBits Number of bits to write.
106
     */
107
    void writeBits64(uint64_t data, uint8_t numBits = 64);
108
109
    /**
110
     * Writes signed bits up to 32 bits.
111
     *
112
     * \param data Data to write.
113
     * \param numBits Number of bits to write.
114
     */
115
    void writeSignedBits(int32_t data, uint8_t numBits = 32);
116
117
    /**
118
     * Writes signed bits up to 64 bits.
119
     *
120
     * \param data Data to write.
121
     * \param numBits Number of bits to write.
122
     */
123
    void writeSignedBits64(int64_t data, uint8_t numBits = 64);
124
125
    /**
126
     * Writes signed variable integer up to 64 bits.
127
     *
128
     * \param data Varint64 to write.
129
     */
130
    void writeVarInt64(int64_t data);
131
132
    /**
133
     * Writes signed variable integer up to 32 bits.
134
     *
135
     * \param data Varint32 to write.
136
     */
137
    void writeVarInt32(int32_t data);
138
139
    /**
140
     * Writes signed variable integer up to 16 bits.
141
     *
142
     * \param data Varint16 to write.
143
     */
144
    void writeVarInt16(int16_t data);
145
146
    /**
147
     * Writes unsigned variable integer up to 64 bits.
148
     *
149
     * \param data Varuint64 to write.
150
     */
151
    void writeVarUInt64(uint64_t data);
152
153
    /**
154
     * Writes unsigned variable integer up to 32 bits.
155
     *
156
     * \param data Varuint32 to write.
157
     */
158
    void writeVarUInt32(uint32_t data);
159
160
    /**
161
     * Writes unsigned variable integer up to 16 bits.
162
     *
163
     * \param data Varuint16 to write.
164
     */
165
    void writeVarUInt16(uint16_t data);
166
167
    /**
168
     * Writes signed variable integer up to 72 bits.
169
     *
170
     * \param data Varuint64 to write.
171
     */
172
    void writeVarInt(int64_t data);
173
174
    /**
175
     * Writes signed variable integer up to 72 bits.
176
     *
177
     * \param data Varuint64 to write.
178
     */
179
    void writeVarUInt(uint64_t data);
180
181
    /**
182
     * Writes variable size integer up to 40 bits.
183
     *
184
     * \param data Varsize to write.
185
     */
186
    void writeVarSize(uint32_t data);
187
188
    /**
189
     * Writes 16-bit float.
190
     *
191
     * \param data Float16 to write.
192
     */
193
    void writeFloat16(float data);
194
195
    /**
196
     * Writes 32-bit float.
197
     *
198
     * \param data Float32 to write.
199
     */
200
    void writeFloat32(float data);
201
202
    /**
203
     * Writes 64-bit float.
204
     *
205
     * \param data Float64 to write.
206
     */
207
    void writeFloat64(double data);
208
209
    /**
210
     * Writes bytes.
211
     *
212
     * \param data Bytes to write.
213
     */
214
    void writeBytes(Span<const uint8_t> data);
215
216
    /**
217
     * Writes UTF-8 string.
218
     *
219
     * \param data String view to write.
220
     */
221
    void writeString(StringView data);
222
223
    /**
224
     * Writes bool as a single bit.
225
     *
226
     * \param data Bool to write.
227
     */
228
    void writeBool(bool data);
229
230
    /**
231
     * Writes bit buffer.
232
     *
233
     * \param bitBuffer Bit buffer to write.
234
     */
235
    template <typename ALLOC>
236
    void writeBitBuffer(const BasicBitBuffer<ALLOC>& bitBuffer)
237
133
    {
238
133
        const size_t bitSize = bitBuffer.getBitSize();
239
133
        writeVarSize(convertSizeToUInt32(bitSize));
240
241
133
        Span<const uint8_t> buffer = bitBuffer.getData();
242
133
        size_t numBytesToWrite = bitSize / 8;
243
133
        const uint8_t numRestBits = static_cast<uint8_t>(bitSize - numBytesToWrite * 8);
244
133
        const BitPosType beginBitPosition = getBitPosition();
245
133
        const Span<const uint8_t>::iterator itEnd = buffer.begin() + numBytesToWrite;
246
133
        if ((beginBitPosition & 0x07U) != 0)
247
67
        {
248
            // we are not aligned to byte
249
147
            for (Span<const uint8_t>::iterator it = buffer.begin(); it != itEnd; 
++it80
)
250
80
            {
251
80
                writeUnsignedBits(*it, 8);
252
80
            }
253
67
        }
254
66
        else
255
66
        {
256
            // we are aligned to byte
257
66
            setBitPosition(beginBitPosition + numBytesToWrite * 8);
258
66
            if (hasWriteBuffer())
259
64
            {
260
64
                std::copy(buffer.begin(), buffer.begin() + numBytesToWrite,
261
64
                        m_buffer.data() + beginBitPosition / 8);
262
64
            }
263
66
        }
264
265
133
        if (numRestBits > 0)
266
128
        {
267
128
            writeUnsignedBits(static_cast<uint32_t>(*itEnd) >> (8U - numRestBits), numRestBits);
268
128
        }
269
133
    }
270
271
    /**
272
     * Gets current bit position.
273
     *
274
     * \return Current bit position.
275
     */
276
    BitPosType getBitPosition() const
277
17.3k
    {
278
17.3k
        return m_bitIndex;
279
17.3k
    }
280
281
    /**
282
     * Sets current bit position. Use with caution!
283
     *
284
     * \param position New bit position.
285
     */
286
    void setBitPosition(BitPosType position);
287
288
    /**
289
     * Moves current bit position to perform the requested bit alignment.
290
     *
291
     * \param alignment Size of the alignment in bits.
292
     */
293
    void alignTo(size_t alignment);
294
295
    /**
296
     * Gets whether the writer has assigned a write buffer.
297
     *
298
     * \return True when a buffer is assigned. False otherwise.
299
     */
300
    bool hasWriteBuffer() const
301
105k
    {
302
105k
        return m_buffer.data() != nullptr;
303
105k
    }
304
305
    /**
306
     * Gets the write buffer.
307
     *
308
     * \return Pointer to the beginning of write buffer.
309
     */
310
    const uint8_t* getWriteBuffer() const;
311
312
    /**
313
     * Gets the write buffer as span.
314
     *
315
     * \return Span which represents the write buffer.
316
     */
317
    Span<const uint8_t> getBuffer() const;
318
319
    /**
320
     * Gets size of the underlying buffer in bits.
321
     *
322
     * \return Buffer bit size.
323
     */
324
    size_t getBufferBitSize() const
325
5
    {
326
5
        return m_bufferBitSize;
327
5
    }
328
329
private:
330
    void writeUnsignedBits(uint32_t data, uint8_t numBits);
331
    void writeUnsignedBits64(uint64_t data, uint8_t numBits);
332
    void writeSignedVarNum(int64_t value, size_t maxVarBytes, size_t numVarBytes);
333
    void writeUnsignedVarNum(uint64_t value, size_t maxVarBytes, size_t numVarBytes);
334
    void writeVarNum(uint64_t value, bool hasSign, bool isNegative, size_t maxVarBytes, size_t numVarBytes);
335
336
    void checkCapacity(size_t bitSize) const;
337
    void throwInsufficientCapacityException() const;
338
339
    Span<uint8_t> m_buffer;
340
    size_t m_bitIndex;
341
    size_t m_bufferBitSize;
342
};
343
344
} // namespace zserio
345
346
#endif // ifndef ZSERIO_BIT_STREAM_WRITER_H_INC