GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/zserio/BitStreamWriter.cpp Lines: 185 185 100.0 %
Date: 2023-12-13 14:51:09 Branches: 106 132 80.3 %

Line Branch Exec Source
1
#include <cstring>
2
#include <fstream>
3
#include <array>
4
#include <algorithm>
5
6
#include "zserio/CppRuntimeException.h"
7
#include "zserio/BitSizeOfCalculator.h"
8
#include "zserio/FloatUtil.h"
9
#include "zserio/BitStreamWriter.h"
10
11
namespace zserio
12
{
13
14
static const std::array<uint32_t, 33> MAX_U32_VALUES =
15
{
16
    0x00U,
17
    0x0001U,     0x0003U,     0x0007U,     0x000fU,
18
    0x001fU,     0x003fU,     0x007fU,     0x00ffU,
19
    0x01ffU,     0x03ffU,     0x07ffU,     0x0fffU,
20
    0x1fffU,     0x3fffU,     0x7fffU,     0xffffU,
21
    0x0001ffffU, 0x0003ffffU, 0x0007ffffU, 0x000fffffU,
22
    0x001fffffU, 0x003fffffU, 0x007fffffU, 0x00ffffffU,
23
    0x01ffffffU, 0x03ffffffU, 0x07ffffffU, 0x0fffffffU,
24
    0x1fffffffU, 0x3fffffffU, 0x7fffffffU, 0xffffffffU,
25
};
26
27
static const std::array<int32_t, 33> MIN_I32_VALUES =
28
{
29
    0,
30
   -0x0001,     -0x0002,     -0x0004,     -0x0008,
31
   -0x0010,     -0x0020,     -0x0040,     -0x0080,
32
   -0x0100,     -0x0200,     -0x0400,     -0x0800,
33
   -0x1000,     -0x2000,     -0x4000,     -0x8000,
34
   -0x00010000, -0x00020000, -0x00040000, -0x00080000,
35
   -0x00100000, -0x00200000, -0x00400000, -0x00800000,
36
   -0x01000000, -0x02000000, -0x04000000, -0x08000000,
37
   -0x10000000, -0x20000000, -0x40000000, INT32_MIN
38
};
39
40
static const std::array<int32_t, 33> MAX_I32_VALUES =
41
{
42
    0x00,
43
    0x0000,      0x0001,      0x0003,      0x0007,
44
    0x000f,      0x001f,      0x003f,      0x007f,
45
    0x00ff,      0x01ff,      0x03ff,      0x07ff,
46
    0x0fff,      0x1fff,      0x3fff,      0x7fff,
47
    0x0000ffff,  0x0001ffff,  0x0003ffff,  0x0007ffff,
48
    0x000fffff,  0x001fffff,  0x003fffff,  0x007fffff,
49
    0x00ffffff,  0x01ffffff,  0x03ffffff,  0x07ffffff,
50
    0x0fffffff,  0x1fffffff,  0x3fffffff,  0x7fffffff
51
};
52
53
static const std::array<uint64_t, 65> MAX_U64_VALUES =
54
{
55
    0x00ULL,
56
    0x0001ULL,             0x0003ULL,             0x0007ULL,             0x000fULL,
57
    0x001fULL,             0x003fULL,             0x007fULL,             0x00ffULL,
58
    0x01ffULL,             0x03ffULL,             0x07ffULL,             0x0fffULL,
59
    0x1fffULL,             0x3fffULL,             0x7fffULL,             0xffffULL,
60
    0x0001ffffULL,         0x0003ffffULL,         0x0007ffffULL,         0x000fffffULL,
61
    0x001fffffULL,         0x003fffffULL,         0x007fffffULL,         0x00ffffffULL,
62
    0x01ffffffULL,         0x03ffffffULL,         0x07ffffffULL,         0x0fffffffULL,
63
    0x1fffffffULL,         0x3fffffffULL,         0x7fffffffULL,         0xffffffffULL,
64
    0x0001ffffffffULL,     0x0003ffffffffULL,     0x0007ffffffffULL,     0x000fffffffffULL,
65
    0x001fffffffffULL,     0x003fffffffffULL,     0x007fffffffffULL,     0x00ffffffffffULL,
66
    0x01ffffffffffULL,     0x03ffffffffffULL,     0x07ffffffffffULL,     0x0fffffffffffULL,
67
    0x1fffffffffffULL,     0x3fffffffffffULL,     0x7fffffffffffULL,     0xffffffffffffULL,
68
    0x0001ffffffffffffULL, 0x0003ffffffffffffULL, 0x0007ffffffffffffULL, 0x000fffffffffffffULL,
69
    0x001fffffffffffffULL, 0x003fffffffffffffULL, 0x007fffffffffffffULL, 0x00ffffffffffffffULL,
70
    0x01ffffffffffffffULL, 0x03ffffffffffffffULL, 0x07ffffffffffffffULL, 0x0fffffffffffffffULL,
71
    0x1fffffffffffffffULL, 0x3fffffffffffffffULL, 0x7fffffffffffffffULL, 0xffffffffffffffffULL
72
};
73
74
static const std::array<int64_t, 65> MIN_I64_VALUES =
75
{
76
    0LL,
77
   -0x0001LL,             -0x0002LL,             -0x0004LL,             -0x0008LL,
78
   -0x0010LL,             -0x0020LL,             -0x0040LL,             -0x0080LL,
79
   -0x0100LL,             -0x0200LL,             -0x0400LL,             -0x0800LL,
80
   -0x1000LL,             -0x2000LL,             -0x4000LL,             -0x8000LL,
81
   -0x00010000LL,         -0x00020000LL,         -0x00040000LL,         -0x00080000LL,
82
   -0x00100000LL,         -0x00200000LL,         -0x00400000LL,         -0x00800000LL,
83
   -0x01000000LL,         -0x02000000LL,         -0x04000000LL,         -0x08000000LL,
84
   -0x10000000LL,         -0x20000000LL,         -0x40000000LL,         -0x80000000LL,
85
   -0x000100000000LL,     -0x000200000000LL,     -0x000400000000LL,     -0x000800000000LL,
86
   -0x001000000000LL,     -0x002000000000LL,     -0x004000000000LL,     -0x008000000000LL,
87
   -0x010000000000LL,     -0x020000000000LL,     -0x040000000000LL,     -0x080000000000LL,
88
   -0x100000000000LL,     -0x200000000000LL,     -0x400000000000LL,     -0x800000000000LL,
89
   -0x0001000000000000LL, -0x0002000000000000LL, -0x0004000000000000LL, -0x0008000000000000LL,
90
   -0x0010000000000000LL, -0x0020000000000000LL, -0x0040000000000000LL, -0x0080000000000000LL,
91
   -0x0100000000000000LL, -0x0200000000000000LL, -0x0400000000000000LL, -0x0800000000000000LL,
92
   -0x1000000000000000LL, -0x2000000000000000LL, -0x4000000000000000LL, INT64_MIN
93
};
94
95
static const std::array<int64_t, 65> MAX_I64_VALUES =
96
{
97
    0x00LL,
98
    0x0000LL,              0x0001LL,              0x0003LL,             0x0007LL,
99
    0x000fLL,              0x001fLL,              0x003fLL,             0x007fLL,
100
    0x00ffLL,              0x01ffLL,              0x03ffLL,             0x07ffLL,
101
    0x0fffLL,              0x1fffLL,              0x3fffLL,             0x7fffLL,
102
    0x0000ffffLL,          0x0001ffffLL,          0x0003ffffLL,         0x0007ffffLL,
103
    0x000fffffLL,          0x001fffffLL,          0x003fffffLL,         0x007fffffLL,
104
    0x00ffffffLL,          0x01ffffffLL,          0x03ffffffLL,         0x07ffffffLL,
105
    0x0fffffffLL,          0x1fffffffLL,          0x3fffffffLL,         0x7fffffffLL,
106
    0x0000ffffffffLL,      0x0001ffffffffLL,      0x0003ffffffffLL,     0x0007ffffffffLL,
107
    0x000fffffffffLL,      0x001fffffffffLL,      0x003fffffffffLL,     0x007fffffffffLL,
108
    0x00ffffffffffLL,      0x01ffffffffffLL,      0x03ffffffffffLL,     0x07ffffffffffLL,
109
    0x0fffffffffffLL,      0x1fffffffffffLL,      0x3fffffffffffLL,     0x7fffffffffffLL,
110
    0x0000ffffffffffffLL,  0x0001ffffffffffffLL,  0x0003ffffffffffffLL, 0x0007ffffffffffffLL,
111
    0x000fffffffffffffLL,  0x001fffffffffffffLL,  0x003fffffffffffffLL, 0x007fffffffffffffLL,
112
    0x00ffffffffffffffLL,  0x01ffffffffffffffLL,  0x03ffffffffffffffLL, 0x07ffffffffffffffLL,
113
    0x0fffffffffffffffLL,  0x1fffffffffffffffLL,  0x3fffffffffffffffLL, 0x7fffffffffffffffLL
114
};
115
116
1
BitStreamWriter::BitStreamWriter(uint8_t* buffer, size_t bufferBitSize, BitsTag) :
117
1
        m_buffer(buffer, (bufferBitSize + 7) / 8),
118
        m_bitIndex(0),
119
1
        m_bufferBitSize(bufferBitSize)
120
1
{}
121
122
3409
BitStreamWriter::BitStreamWriter(uint8_t* buffer, size_t bufferByteSize) :
123
3409
        BitStreamWriter(Span<uint8_t>(buffer, bufferByteSize))
124
3409
{}
125
126
3410
BitStreamWriter::BitStreamWriter(Span<uint8_t> buffer) :
127
        m_buffer(buffer),
128
        m_bitIndex(0),
129
3410
        m_bufferBitSize(buffer.size() * 8)
130
3410
{}
131
132
471
BitStreamWriter::BitStreamWriter(Span<uint8_t> buffer, size_t bufferBitSize) :
133
        m_buffer(buffer),
134
        m_bitIndex(0),
135
471
        m_bufferBitSize(bufferBitSize)
136
{
137
471
    if (buffer.size() < (bufferBitSize + 7) / 8)
138
    {
139

2
        throw CppRuntimeException("BitStreamWriter: Wrong buffer bit size ('") << buffer.size() <<
140

3
                "' < '" << (bufferBitSize + 7) / 8 << "')!";
141
    }
142
470
}
143
144
8852
void BitStreamWriter::writeBits(uint32_t data, uint8_t numBits)
145
{
146

8852
    if (numBits > sizeof(uint32_t) * 8 || data > MAX_U32_VALUES[numBits])
147
    {
148


68
        throw CppRuntimeException("BitStreamWriter: Writing of ") << numBits << "-bits value '" << data <<
149
102
                "' failed!";
150
    }
151
152
8818
    writeUnsignedBits(data, numBits);
153
8813
}
154
155
4355
void BitStreamWriter::writeBits64(uint64_t data, uint8_t numBits)
156
{
157

4355
    if (numBits > sizeof(uint64_t) * 8 || data > MAX_U64_VALUES[numBits])
158
    {
159


132
        throw CppRuntimeException("BitStreamWriter: Writing of ") << numBits << "-bits value '" << data <<
160
198
                "' failed!";
161
    }
162
163
4289
    writeUnsignedBits64(data, numBits);
164
4224
}
165
166
1629
void BitStreamWriter::writeSignedBits(int32_t data, uint8_t numBits)
167
{
168


1629
    if (numBits > sizeof(int32_t) * 8 || data < MIN_I32_VALUES[numBits] || data > MAX_I32_VALUES[numBits])
169
    {
170


130
        throw CppRuntimeException("BitStreamWriter: Writing of ") << numBits << "-bits value '" << data <<
171
195
                "' failed!";
172
    }
173
174
1564
    writeUnsignedBits(static_cast<uint32_t>(data) & MAX_U32_VALUES[numBits], numBits);
175
1564
}
176
177
2186
void BitStreamWriter::writeSignedBits64(int64_t data, uint8_t numBits)
178
{
179


2186
    if (numBits > sizeof(int64_t) * 8 || data < MIN_I64_VALUES[numBits] || data > MAX_I64_VALUES[numBits])
180
    {
181


258
        throw CppRuntimeException("BitStreamWriter: Writing of ") << numBits << "-bits value '" << data <<
182
387
                "' failed!";
183
    }
184
185
2057
    writeUnsignedBits64(static_cast<uint64_t>(data) & MAX_U64_VALUES[numBits], numBits);
186
2057
}
187
188
4424
void BitStreamWriter::writeVarInt64(int64_t data)
189
{
190
4424
    writeSignedVarNum(data, 8, zserio::bitSizeOfVarInt64(data) / 8);
191
4423
}
192
193
1192
void BitStreamWriter::writeVarInt32(int32_t data)
194
{
195
1192
    writeSignedVarNum(data, 4, zserio::bitSizeOfVarInt32(data) / 8);
196
1191
}
197
198
344
void BitStreamWriter::writeVarInt16(int16_t data)
199
{
200
344
    writeSignedVarNum(data, 2, zserio::bitSizeOfVarInt16(data) / 8);
201
343
}
202
203
3140
void BitStreamWriter::writeVarUInt64(uint64_t data)
204
{
205
3140
    writeUnsignedVarNum(data, 8, zserio::bitSizeOfVarUInt64(data) / 8);
206
3139
}
207
208
820
void BitStreamWriter::writeVarUInt32(uint32_t data)
209
{
210
820
    writeUnsignedVarNum(data, 4, zserio::bitSizeOfVarUInt32(data) / 8);
211
819
}
212
213
284
void BitStreamWriter::writeVarUInt16(uint16_t data)
214
{
215
284
    writeUnsignedVarNum(data, 2, zserio::bitSizeOfVarUInt16(data) / 8);
216
283
}
217
218
5503
void BitStreamWriter::writeVarInt(int64_t data)
219
{
220
5503
    if (data == INT64_MIN)
221
159
        writeBits(0x80, 8); // INT64_MIN is encoded as -0
222
    else
223
5344
        writeSignedVarNum(data, 9, zserio::bitSizeOfVarInt(data) / 8);
224
5503
}
225
226
2757
void BitStreamWriter::writeVarUInt(uint64_t data)
227
{
228
2757
    writeUnsignedVarNum(data, 9, zserio::bitSizeOfVarUInt(data) / 8);
229
2757
}
230
231
3113
void BitStreamWriter::writeVarSize(uint32_t data)
232
{
233
3113
    writeUnsignedVarNum(data, 5, zserio::bitSizeOfVarSize(data) / 8);
234
3112
}
235
236
305
void BitStreamWriter::writeFloat16(float data)
237
{
238
305
    const uint16_t halfPrecisionFloat = convertFloatToUInt16(data);
239
305
    writeUnsignedBits(halfPrecisionFloat, 16);
240
305
}
241
242
499
void BitStreamWriter::writeFloat32(float data)
243
{
244
499
    const uint32_t singlePrecisionFloat = convertFloatToUInt32(data);
245
499
    writeUnsignedBits(singlePrecisionFloat, 32);
246
499
}
247
248
859
void BitStreamWriter::writeFloat64(double data)
249
{
250
859
    const uint64_t doublePrecisionFloat = convertDoubleToUInt64(data);
251
859
    writeUnsignedBits64(doublePrecisionFloat, 64);
252
859
}
253
254
99
void BitStreamWriter::writeBytes(Span<const uint8_t> data)
255
{
256
99
    const size_t len = data.size();
257
99
    writeVarSize(convertSizeToUInt32(len));
258
259
99
    const BitPosType beginBitPosition = getBitPosition();
260
99
    if ((beginBitPosition & 0x07U) != 0)
261
    {
262
        // we are not aligned to byte
263
180
        for (size_t i = 0; i < len; ++i)
264
128
            writeBits(data[i], 8);
265
    }
266
    else
267
    {
268
        // we are aligned to bytes
269
47
        setBitPosition(beginBitPosition + len * 8);
270
47
        if (hasWriteBuffer())
271
45
            std::copy(data.begin(), data.end(), m_buffer.begin() + beginBitPosition / 8);
272
    }
273
99
}
274
275
161
void BitStreamWriter::writeString(StringView data)
276
{
277
161
    const size_t len = data.size();
278
161
    writeVarSize(convertSizeToUInt32(len));
279
280
161
    const BitPosType beginBitPosition = getBitPosition();
281
161
    if ((beginBitPosition & 0x07U) != 0)
282
    {
283
        // we are not aligned to byte
284
1548
        for (size_t i = 0; i < len; ++i)
285
1470
            writeBits(static_cast<uint8_t>(data[i]), 8);
286
    }
287
    else
288
    {
289
        // we are aligned to bytes
290
83
        setBitPosition(beginBitPosition + len * 8);
291
83
        if (hasWriteBuffer())
292
80
            std::copy(data.begin(), data.begin() + len, m_buffer.data() + beginBitPosition / 8);
293
    }
294
161
}
295
296
909
void BitStreamWriter::writeBool(bool data)
297
{
298
909
    writeBits((data ? 1 : 0), 1);
299
909
}
300
301
704
void BitStreamWriter::setBitPosition(BitPosType position)
302
{
303
704
    if (hasWriteBuffer())
304
695
        checkCapacity(position);
305
306
703
    m_bitIndex = position;
307
703
}
308
309
4736
void BitStreamWriter::alignTo(size_t alignment)
310
{
311
4736
    const BitPosType offset = getBitPosition() % alignment;
312
4736
    if (offset != 0)
313
    {
314
2465
        const uint8_t skip = static_cast<uint8_t>(alignment - offset);
315
2465
        writeBits64(0, skip);
316
    }
317
4736
}
318
319
515
const uint8_t* BitStreamWriter::getWriteBuffer() const
320
{
321
515
    return m_buffer.data();
322
}
323
324
18
Span<const uint8_t> BitStreamWriter::getBuffer() const
325
{
326
18
    return m_buffer;
327
}
328
329
103734
void BitStreamWriter::writeUnsignedBits(uint32_t data, uint8_t numBits)
330
{
331
103734
    if (!hasWriteBuffer())
332
    {
333
37321
        m_bitIndex += numBits;
334
37321
        return;
335
    }
336
337
66413
    checkCapacity(m_bitIndex + numBits);
338
339
66343
    uint8_t restNumBits = numBits;
340
66343
    const uint8_t bitsUsed = m_bitIndex & 0x07U;
341
66343
    uint8_t bitsFree = 8 - bitsUsed;
342
66343
    size_t byteIndex = m_bitIndex / 8;
343
344
66343
    if (restNumBits > bitsFree)
345
    {
346
        // first part
347
46360
        const uint8_t shiftNum = restNumBits - bitsFree;
348
46360
        const uint8_t maskedByte = m_buffer[byteIndex] & ~(0xFFU >> bitsUsed);
349
46360
        m_buffer[byteIndex++] = maskedByte | static_cast<uint8_t>(data >> shiftNum);
350
46360
        restNumBits -= bitsFree;
351
352
        // middle parts
353
82370
        while (restNumBits >= 8)
354
        {
355
18005
            restNumBits -= 8;
356
18005
            m_buffer[byteIndex++] = static_cast<uint8_t>((data >> restNumBits) & MAX_U32_VALUES[8]);
357
        }
358
359
        // reset bits free
360
46360
        bitsFree = 8;
361
    }
362
363
    // last part
364
66343
    if (restNumBits > 0)
365
    {
366
64200
        const uint8_t shiftNum = bitsFree - restNumBits;
367
64200
        const uint32_t mask = MAX_U32_VALUES[restNumBits];
368
64200
        const uint8_t maskedByte = m_buffer[byteIndex] &
369
64200
                static_cast<uint8_t>(~static_cast<uint8_t>(mask << shiftNum));
370
64200
        m_buffer[byteIndex] = maskedByte | static_cast<uint8_t>((data & mask) << shiftNum);
371
    }
372
373
66343
    m_bitIndex += numBits;
374
}
375
376
7205
inline void BitStreamWriter::writeUnsignedBits64(uint64_t data, uint8_t numBits)
377
{
378
7205
    if (numBits <= 32)
379
    {
380
4045
        writeUnsignedBits(static_cast<uint32_t>(data), numBits);
381
    }
382
    else
383
    {
384
3160
        writeUnsignedBits(static_cast<uint32_t>(data >> 32U), numBits - 32);
385
3160
        writeUnsignedBits(static_cast<uint32_t>(data), 32);
386
    }
387
7140
}
388
389
11301
inline void BitStreamWriter::writeSignedVarNum(int64_t value, size_t maxVarBytes, size_t numVarBytes)
390
{
391
11301
    const uint64_t absValue = static_cast<uint64_t>(value < 0 ? -value : value);
392
11301
    writeVarNum(absValue, true, value < 0, maxVarBytes, numVarBytes);
393
11301
}
394
395
10110
inline void BitStreamWriter::writeUnsignedVarNum(uint64_t value, size_t maxVarBytes, size_t numVarBytes)
396
{
397
10110
    writeVarNum(value, false, false, maxVarBytes, numVarBytes);
398
10110
}
399
400
21411
inline void BitStreamWriter::writeVarNum(uint64_t value, bool hasSign, bool isNegative, size_t maxVarBytes,
401
        size_t numVarBytes)
402
{
403
    static const std::array<uint64_t, 8> bitMasks = { 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
404
21411
    const bool hasMaxByteRange = (numVarBytes == maxVarBytes);
405
406
103386
    for (size_t i = 0; i < numVarBytes; i++)
407
    {
408
81975
        uint8_t byte = 0x00;
409
81975
        uint8_t numBits = 8;
410
81975
        const bool hasNextByte = (i < numVarBytes - 1);
411

81975
        const bool hasSignBit = (hasSign && i == 0);
412
81975
        if (hasSignBit)
413
        {
414
11301
            if (isNegative)
415
3922
                byte |= 0x80U;
416
11301
            numBits--;
417
        }
418
81975
        if (hasNextByte)
419
        {
420
60564
            numBits--;
421
60564
            byte |= (0x01U << numBits); // use bit 6 if signed bit is present, use bit 7 otherwise
422
        }
423
        else // this is the last byte
424
        {
425
21411
            if (!hasMaxByteRange) // next byte indicator is not used in last byte in case of max byte range
426
18801
                numBits--;
427
        }
428
429

81975
        const size_t shiftBits = (numVarBytes - (i + 1)) * 7 + ((hasMaxByteRange && hasNextByte) ? 1 : 0);
430
81975
        byte |= static_cast<uint8_t>((value >> shiftBits) & bitMasks[numBits - 1]);
431
81975
        writeUnsignedBits(byte, 8);
432
    }
433
21411
}
434
435
71
inline void BitStreamWriter::throwInsufficientCapacityException() const
436
{
437
71
    throw InsufficientCapacityException("BitStreamWriter: Reached end of bit buffer!");
438
}
439
440
67108
inline void BitStreamWriter::checkCapacity(size_t bitSize) const
441
{
442
67108
    if (bitSize > m_bufferBitSize)
443
71
        throwInsufficientCapacityException();
444
67037
}
445
446
} // namespace zserio