Coverage Report

Created: 2024-04-30 09:35

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
                writeUnsignedBits(*it, 8);
251
67
        }
252
66
        else
253
66
        {
254
            // we are aligned to byte
255
66
            setBitPosition(beginBitPosition + numBytesToWrite * 8);
256
66
            if (hasWriteBuffer())
257
64
            {
258
64
                std::copy(buffer.begin(), buffer.begin() + numBytesToWrite,
259
64
                        m_buffer.data() + beginBitPosition / 8);
260
64
            }
261
66
        }
262
263
133
        if (numRestBits > 0)
264
128
            writeUnsignedBits(*itEnd >> (8U - numRestBits), numRestBits);
265
133
    }
266
267
    /**
268
     * Gets current bit position.
269
     *
270
     * \return Current bit position.
271
     */
272
    BitPosType getBitPosition() const
273
17.3k
    {
274
17.3k
        return m_bitIndex;
275
17.3k
    }
276
277
    /**
278
     * Sets current bit position. Use with caution!
279
     *
280
     * \param position New bit position.
281
     */
282
    void setBitPosition(BitPosType position);
283
284
    /**
285
     * Moves current bit position to perform the requested bit alignment.
286
     *
287
     * \param alignment Size of the alignment in bits.
288
     */
289
    void alignTo(size_t alignment);
290
291
    /**
292
     * Gets whether the writer has assigned a write buffer.
293
     *
294
     * \return True when a buffer is assigned. False otherwise.
295
     */
296
    bool hasWriteBuffer() const
297
105k
    {
298
105k
        return m_buffer.data() != nullptr;
299
105k
    }
300
301
    /**
302
     * Gets the write buffer.
303
     *
304
     * \return Pointer to the beginning of write buffer.
305
     */
306
    const uint8_t* getWriteBuffer() const;
307
308
    /**
309
     * Gets the write buffer as span.
310
     *
311
     * \return Span which represents the write buffer.
312
     */
313
    Span<const uint8_t> getBuffer() const;
314
315
    /**
316
     * Gets size of the underlying buffer in bits.
317
     *
318
     * \return Buffer bit size.
319
     */
320
    size_t getBufferBitSize() const
321
5
    {
322
5
        return m_bufferBitSize;
323
5
    }
324
325
private:
326
    void writeUnsignedBits(uint32_t data, uint8_t numBits);
327
    void writeUnsignedBits64(uint64_t data, uint8_t numBits);
328
    void writeSignedVarNum(int64_t value, size_t maxVarBytes, size_t numVarBytes);
329
    void writeUnsignedVarNum(uint64_t value, size_t maxVarBytes, size_t numVarBytes);
330
    void writeVarNum(uint64_t value, bool hasSign, bool isNegative, size_t maxVarBytes, size_t numVarBytes);
331
332
    void checkCapacity(size_t bitSize) const;
333
    void throwInsufficientCapacityException() const;
334
335
    Span<uint8_t> m_buffer;
336
    size_t m_bitIndex;
337
    size_t m_bufferBitSize;
338
};
339
340
} // namespace zserio
341
342
#endif // ifndef ZSERIO_BIT_STREAM_WRITER_H_INC