GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/zserio/BitStreamWriter.h Lines: 26 26 100.0 %
Date: 2023-12-13 14:51:09 Branches: 16 24 66.7 %

Line Branch Exec Source
1
#ifndef ZSERIO_BIT_STREAM_WRITER_H_INC
2
#define ZSERIO_BIT_STREAM_WRITER_H_INC
3
4
#include <cstddef>
5
#include <cstring>
6
#include <algorithm>
7
8
#include "zserio/BitBuffer.h"
9
#include "zserio/CppRuntimeException.h"
10
#include "zserio/Span.h"
11
#include "zserio/StringView.h"
12
#include "zserio/Types.h"
13
#include "zserio/SizeConvertUtil.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
71
    class InsufficientCapacityException : public CppRuntimeException
26
    {
27
    public:
28
71
        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
469
    explicit BitStreamWriter(BasicBitBuffer<ALLOC>& bitBuffer) :
72
469
            BitStreamWriter(bitBuffer.getData(), bitBuffer.getBitSize())
73
    {
74
469
    }
75
76
    /**
77
     * Destructor.
78
     */
79
    ~BitStreamWriter() = default;
80
81
    /**
82
     * Copying and moving is disallowed!
83
     * \{
84
     */
85
    BitStreamWriter(const BitStreamWriter&) = delete;
86
    BitStreamWriter& operator=(const BitStreamWriter&) = delete;
87
88
    BitStreamWriter(const BitStreamWriter&&) = delete;
89
    BitStreamWriter& operator=(BitStreamWriter&&) = delete;
90
    /**
91
     * \}
92
     */
93
94
    /**
95
     * Writes unsigned bits up to 32 bits.
96
     *
97
     * \param data Data to write.
98
     * \param numBits Number of bits to write.
99
     */
100
    void writeBits(uint32_t data, uint8_t numBits = 32);
101
102
    /**
103
     * Writes unsigned bits up to 64 bits.
104
     *
105
     * \param data Data to write.
106
     * \param numBits Number of bits to write.
107
     */
108
    void writeBits64(uint64_t data, uint8_t numBits = 64);
109
110
    /**
111
     * Writes signed bits up to 32 bits.
112
     *
113
     * \param data Data to write.
114
     * \param numBits Number of bits to write.
115
     */
116
    void writeSignedBits(int32_t data, uint8_t numBits = 32);
117
118
    /**
119
     * Writes signed bits up to 64 bits.
120
     *
121
     * \param data Data to write.
122
     * \param numBits Number of bits to write.
123
     */
124
    void writeSignedBits64(int64_t data, uint8_t numBits = 64);
125
126
    /**
127
     * Writes signed variable integer up to 64 bits.
128
     *
129
     * \param data Varint64 to write.
130
     */
131
    void writeVarInt64(int64_t data);
132
133
    /**
134
     * Writes signed variable integer up to 32 bits.
135
     *
136
     * \param data Varint32 to write.
137
     */
138
    void writeVarInt32(int32_t data);
139
140
    /**
141
     * Writes signed variable integer up to 16 bits.
142
     *
143
     * \param data Varint16 to write.
144
     */
145
    void writeVarInt16(int16_t data);
146
147
    /**
148
     * Writes unsigned variable integer up to 64 bits.
149
     *
150
     * \param data Varuint64 to write.
151
     */
152
    void writeVarUInt64(uint64_t data);
153
154
    /**
155
     * Writes unsigned variable integer up to 32 bits.
156
     *
157
     * \param data Varuint32 to write.
158
     */
159
    void writeVarUInt32(uint32_t data);
160
161
    /**
162
     * Writes unsigned variable integer up to 16 bits.
163
     *
164
     * \param data Varuint16 to write.
165
     */
166
    void writeVarUInt16(uint16_t data);
167
168
    /**
169
     * Writes signed variable integer up to 72 bits.
170
     *
171
     * \param data Varuint64 to write.
172
     */
173
    void writeVarInt(int64_t data);
174
175
    /**
176
     * Writes signed variable integer up to 72 bits.
177
     *
178
     * \param data Varuint64 to write.
179
     */
180
    void writeVarUInt(uint64_t data);
181
182
    /**
183
     * Writes variable size integer up to 40 bits.
184
     *
185
     * \param data Varsize to write.
186
     */
187
    void writeVarSize(uint32_t data);
188
189
    /**
190
     * Writes 16-bit float.
191
     *
192
     * \param data Float16 to write.
193
     */
194
    void writeFloat16(float data);
195
196
    /**
197
     * Writes 32-bit float.
198
     *
199
     * \param data Float32 to write.
200
     */
201
    void writeFloat32(float data);
202
203
    /**
204
     * Writes 64-bit float.
205
     *
206
     * \param data Float64 to write.
207
     */
208
    void writeFloat64(double data);
209
210
    /**
211
     * Writes bytes.
212
     *
213
     * \param data Bytes to write.
214
     */
215
    void writeBytes(Span<const uint8_t> data);
216
217
    /**
218
     * Writes UTF-8 string.
219
     *
220
     * \param data String view to write.
221
     */
222
    void writeString(StringView data);
223
224
    /**
225
     * Writes bool as a single bit.
226
     *
227
     * \param data Bool to write.
228
     */
229
    void writeBool(bool data);
230
231
    /**
232
     * Writes bit buffer.
233
     *
234
     * \param bitBuffer Bit buffer to write.
235
     */
236
    template <typename ALLOC>
237
133
    void writeBitBuffer(const BasicBitBuffer<ALLOC>& bitBuffer)
238
    {
239
133
        const size_t bitSize = bitBuffer.getBitSize();
240

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