Zserio C++ runtime library  1.1.0
Built for Zserio 2.15.0
BitStreamWriter.cpp
Go to the documentation of this file.
1 #include <algorithm>
2 #include <array>
3 #include <cstring>
4 #include <fstream>
5 #include <string>
6 
10 #include "zserio/FloatUtil.h"
11 
12 namespace zserio
13 {
14 
15 static const std::array<uint32_t, 33> MAX_U32_VALUES = {
16  0x00U,
17  0x0001U,
18  0x0003U,
19  0x0007U,
20  0x000fU,
21  0x001fU,
22  0x003fU,
23  0x007fU,
24  0x00ffU,
25  0x01ffU,
26  0x03ffU,
27  0x07ffU,
28  0x0fffU,
29  0x1fffU,
30  0x3fffU,
31  0x7fffU,
32  0xffffU,
33  0x0001ffffU,
34  0x0003ffffU,
35  0x0007ffffU,
36  0x000fffffU,
37  0x001fffffU,
38  0x003fffffU,
39  0x007fffffU,
40  0x00ffffffU,
41  0x01ffffffU,
42  0x03ffffffU,
43  0x07ffffffU,
44  0x0fffffffU,
45  0x1fffffffU,
46  0x3fffffffU,
47  0x7fffffffU,
48  0xffffffffU,
49 };
50 
51 static const std::array<int32_t, 33> MIN_I32_VALUES = {
52  0,
53  -0x0001,
54  -0x0002,
55  -0x0004,
56  -0x0008,
57  -0x0010,
58  -0x0020,
59  -0x0040,
60  -0x0080,
61  -0x0100,
62  -0x0200,
63  -0x0400,
64  -0x0800,
65  -0x1000,
66  -0x2000,
67  -0x4000,
68  -0x8000,
69  -0x00010000,
70  -0x00020000,
71  -0x00040000,
72  -0x00080000,
73  -0x00100000,
74  -0x00200000,
75  -0x00400000,
76  -0x00800000,
77  -0x01000000,
78  -0x02000000,
79  -0x04000000,
80  -0x08000000,
81  -0x10000000,
82  -0x20000000,
83  -0x40000000,
84  INT32_MIN,
85 };
86 
87 static const std::array<int32_t, 33> MAX_I32_VALUES = {
88  0x00,
89  0x0000,
90  0x0001,
91  0x0003,
92  0x0007,
93  0x000f,
94  0x001f,
95  0x003f,
96  0x007f,
97  0x00ff,
98  0x01ff,
99  0x03ff,
100  0x07ff,
101  0x0fff,
102  0x1fff,
103  0x3fff,
104  0x7fff,
105  0x0000ffff,
106  0x0001ffff,
107  0x0003ffff,
108  0x0007ffff,
109  0x000fffff,
110  0x001fffff,
111  0x003fffff,
112  0x007fffff,
113  0x00ffffff,
114  0x01ffffff,
115  0x03ffffff,
116  0x07ffffff,
117  0x0fffffff,
118  0x1fffffff,
119  0x3fffffff,
120  0x7fffffff,
121 };
122 
123 static const std::array<uint64_t, 65> MAX_U64_VALUES = {
124  0x00ULL,
125  0x0001ULL,
126  0x0003ULL,
127  0x0007ULL,
128  0x000fULL,
129  0x001fULL,
130  0x003fULL,
131  0x007fULL,
132  0x00ffULL,
133  0x01ffULL,
134  0x03ffULL,
135  0x07ffULL,
136  0x0fffULL,
137  0x1fffULL,
138  0x3fffULL,
139  0x7fffULL,
140  0xffffULL,
141  0x0001ffffULL,
142  0x0003ffffULL,
143  0x0007ffffULL,
144  0x000fffffULL,
145  0x001fffffULL,
146  0x003fffffULL,
147  0x007fffffULL,
148  0x00ffffffULL,
149  0x01ffffffULL,
150  0x03ffffffULL,
151  0x07ffffffULL,
152  0x0fffffffULL,
153  0x1fffffffULL,
154  0x3fffffffULL,
155  0x7fffffffULL,
156  0xffffffffULL,
157  0x0001ffffffffULL,
158  0x0003ffffffffULL,
159  0x0007ffffffffULL,
160  0x000fffffffffULL,
161  0x001fffffffffULL,
162  0x003fffffffffULL,
163  0x007fffffffffULL,
164  0x00ffffffffffULL,
165  0x01ffffffffffULL,
166  0x03ffffffffffULL,
167  0x07ffffffffffULL,
168  0x0fffffffffffULL,
169  0x1fffffffffffULL,
170  0x3fffffffffffULL,
171  0x7fffffffffffULL,
172  0xffffffffffffULL,
173  0x0001ffffffffffffULL,
174  0x0003ffffffffffffULL,
175  0x0007ffffffffffffULL,
176  0x000fffffffffffffULL,
177  0x001fffffffffffffULL,
178  0x003fffffffffffffULL,
179  0x007fffffffffffffULL,
180  0x00ffffffffffffffULL,
181  0x01ffffffffffffffULL,
182  0x03ffffffffffffffULL,
183  0x07ffffffffffffffULL,
184  0x0fffffffffffffffULL,
185  0x1fffffffffffffffULL,
186  0x3fffffffffffffffULL,
187  0x7fffffffffffffffULL,
188  0xffffffffffffffffULL,
189 };
190 
191 static const std::array<int64_t, 65> MIN_I64_VALUES = {
192  0LL,
193  -0x0001LL,
194  -0x0002LL,
195  -0x0004LL,
196  -0x0008LL,
197  -0x0010LL,
198  -0x0020LL,
199  -0x0040LL,
200  -0x0080LL,
201  -0x0100LL,
202  -0x0200LL,
203  -0x0400LL,
204  -0x0800LL,
205  -0x1000LL,
206  -0x2000LL,
207  -0x4000LL,
208  -0x8000LL,
209  -0x00010000LL,
210  -0x00020000LL,
211  -0x00040000LL,
212  -0x00080000LL,
213  -0x00100000LL,
214  -0x00200000LL,
215  -0x00400000LL,
216  -0x00800000LL,
217  -0x01000000LL,
218  -0x02000000LL,
219  -0x04000000LL,
220  -0x08000000LL,
221  -0x10000000LL,
222  -0x20000000LL,
223  -0x40000000LL,
224  -0x80000000LL,
225  -0x000100000000LL,
226  -0x000200000000LL,
227  -0x000400000000LL,
228  -0x000800000000LL,
229  -0x001000000000LL,
230  -0x002000000000LL,
231  -0x004000000000LL,
232  -0x008000000000LL,
233  -0x010000000000LL,
234  -0x020000000000LL,
235  -0x040000000000LL,
236  -0x080000000000LL,
237  -0x100000000000LL,
238  -0x200000000000LL,
239  -0x400000000000LL,
240  -0x800000000000LL,
241  -0x0001000000000000LL,
242  -0x0002000000000000LL,
243  -0x0004000000000000LL,
244  -0x0008000000000000LL,
245  -0x0010000000000000LL,
246  -0x0020000000000000LL,
247  -0x0040000000000000LL,
248  -0x0080000000000000LL,
249  -0x0100000000000000LL,
250  -0x0200000000000000LL,
251  -0x0400000000000000LL,
252  -0x0800000000000000LL,
253  -0x1000000000000000LL,
254  -0x2000000000000000LL,
255  -0x4000000000000000LL,
256  INT64_MIN,
257 };
258 
259 static const std::array<int64_t, 65> MAX_I64_VALUES = {
260  0x00LL,
261  0x0000LL,
262  0x0001LL,
263  0x0003LL,
264  0x0007LL,
265  0x000fLL,
266  0x001fLL,
267  0x003fLL,
268  0x007fLL,
269  0x00ffLL,
270  0x01ffLL,
271  0x03ffLL,
272  0x07ffLL,
273  0x0fffLL,
274  0x1fffLL,
275  0x3fffLL,
276  0x7fffLL,
277  0x0000ffffLL,
278  0x0001ffffLL,
279  0x0003ffffLL,
280  0x0007ffffLL,
281  0x000fffffLL,
282  0x001fffffLL,
283  0x003fffffLL,
284  0x007fffffLL,
285  0x00ffffffLL,
286  0x01ffffffLL,
287  0x03ffffffLL,
288  0x07ffffffLL,
289  0x0fffffffLL,
290  0x1fffffffLL,
291  0x3fffffffLL,
292  0x7fffffffLL,
293  0x0000ffffffffLL,
294  0x0001ffffffffLL,
295  0x0003ffffffffLL,
296  0x0007ffffffffLL,
297  0x000fffffffffLL,
298  0x001fffffffffLL,
299  0x003fffffffffLL,
300  0x007fffffffffLL,
301  0x00ffffffffffLL,
302  0x01ffffffffffLL,
303  0x03ffffffffffLL,
304  0x07ffffffffffLL,
305  0x0fffffffffffLL,
306  0x1fffffffffffLL,
307  0x3fffffffffffLL,
308  0x7fffffffffffLL,
309  0x0000ffffffffffffLL,
310  0x0001ffffffffffffLL,
311  0x0003ffffffffffffLL,
312  0x0007ffffffffffffLL,
313  0x000fffffffffffffLL,
314  0x001fffffffffffffLL,
315  0x003fffffffffffffLL,
316  0x007fffffffffffffLL,
317  0x00ffffffffffffffLL,
318  0x01ffffffffffffffLL,
319  0x03ffffffffffffffLL,
320  0x07ffffffffffffffLL,
321  0x0fffffffffffffffLL,
322  0x1fffffffffffffffLL,
323  0x3fffffffffffffffLL,
324  0x7fffffffffffffffLL,
325 };
326 
327 BitStreamWriter::BitStreamWriter(uint8_t* buffer, size_t bufferBitSize, BitsTag) :
328  m_buffer(buffer, (bufferBitSize + 7) / 8),
329  m_bitIndex(0),
330  m_bufferBitSize(bufferBitSize)
331 {}
332 
333 BitStreamWriter::BitStreamWriter(uint8_t* buffer, size_t bufferByteSize) :
334  BitStreamWriter(Span<uint8_t>(buffer, bufferByteSize))
335 {}
336 
338  m_buffer(buffer),
339  m_bitIndex(0),
340  m_bufferBitSize(buffer.size() * 8)
341 {}
342 
343 BitStreamWriter::BitStreamWriter(Span<uint8_t> buffer, size_t bufferBitSize) :
344  m_buffer(buffer),
345  m_bitIndex(0),
346  m_bufferBitSize(bufferBitSize)
347 {
348  if (buffer.size() < (bufferBitSize + 7) / 8)
349  {
350  throw CppRuntimeException("BitStreamWriter: Wrong buffer bit size ('")
351  << buffer.size() << "' < '" << (bufferBitSize + 7) / 8 << "')!";
352  }
353 }
354 
355 void BitStreamWriter::writeBits(uint32_t data, uint8_t numBits)
356 {
357  if (numBits == 0 || numBits > sizeof(uint32_t) * 8 || data > MAX_U32_VALUES[numBits])
358  {
359  throw CppRuntimeException("BitStreamWriter: Writing of ")
360  << numBits << "-bits value '" << data << "' failed!";
361  }
362 
363  writeUnsignedBits(data, numBits);
364 }
365 
366 void BitStreamWriter::writeBits64(uint64_t data, uint8_t numBits)
367 {
368  if (numBits == 0 || numBits > sizeof(uint64_t) * 8 || data > MAX_U64_VALUES[numBits])
369  {
370  throw CppRuntimeException("BitStreamWriter: Writing of ")
371  << numBits << "-bits value '" << data << "' failed!";
372  }
373 
374  writeUnsignedBits64(data, numBits);
375 }
376 
377 void BitStreamWriter::writeSignedBits(int32_t data, uint8_t numBits)
378 {
379  if (numBits == 0 || numBits > sizeof(int32_t) * 8 || data < MIN_I32_VALUES[numBits] ||
380  data > MAX_I32_VALUES[numBits])
381  {
382  throw CppRuntimeException("BitStreamWriter: Writing of ")
383  << numBits << "-bits value '" << data << "' failed!";
384  }
385 
386  writeUnsignedBits(static_cast<uint32_t>(data) & MAX_U32_VALUES[numBits], numBits);
387 }
388 
389 void BitStreamWriter::writeSignedBits64(int64_t data, uint8_t numBits)
390 {
391  if (numBits == 0 || numBits > sizeof(int64_t) * 8 || data < MIN_I64_VALUES[numBits] ||
392  data > MAX_I64_VALUES[numBits])
393  {
394  throw CppRuntimeException("BitStreamWriter: Writing of ")
395  << numBits << "-bits value '" << data << "' failed!";
396  }
397 
398  writeUnsignedBits64(static_cast<uint64_t>(data) & MAX_U64_VALUES[numBits], numBits);
399 }
400 
402 {
403  writeSignedVarNum(data, 8, zserio::bitSizeOfVarInt64(data) / 8);
404 }
405 
407 {
408  writeSignedVarNum(data, 4, zserio::bitSizeOfVarInt32(data) / 8);
409 }
410 
412 {
413  writeSignedVarNum(data, 2, zserio::bitSizeOfVarInt16(data) / 8);
414 }
415 
417 {
418  writeUnsignedVarNum(data, 8, zserio::bitSizeOfVarUInt64(data) / 8);
419 }
420 
422 {
423  writeUnsignedVarNum(data, 4, zserio::bitSizeOfVarUInt32(data) / 8);
424 }
425 
427 {
428  writeUnsignedVarNum(data, 2, zserio::bitSizeOfVarUInt16(data) / 8);
429 }
430 
432 {
433  if (data == INT64_MIN)
434  {
435  writeBits(0x80, 8); // INT64_MIN is encoded as -0
436  }
437  else
438  {
439  writeSignedVarNum(data, 9, zserio::bitSizeOfVarInt(data) / 8);
440  }
441 }
442 
443 void BitStreamWriter::writeVarUInt(uint64_t data)
444 {
445  writeUnsignedVarNum(data, 9, zserio::bitSizeOfVarUInt(data) / 8);
446 }
447 
448 void BitStreamWriter::writeVarSize(uint32_t data)
449 {
450  writeUnsignedVarNum(data, 5, zserio::bitSizeOfVarSize(data) / 8);
451 }
452 
454 {
455  const uint16_t halfPrecisionFloat = convertFloatToUInt16(data);
456  writeUnsignedBits(halfPrecisionFloat, 16);
457 }
458 
460 {
461  const uint32_t singlePrecisionFloat = convertFloatToUInt32(data);
462  writeUnsignedBits(singlePrecisionFloat, 32);
463 }
464 
466 {
467  const uint64_t doublePrecisionFloat = convertDoubleToUInt64(data);
468  writeUnsignedBits64(doublePrecisionFloat, 64);
469 }
470 
472 {
473  const size_t len = data.size();
475 
476  const BitPosType beginBitPosition = getBitPosition();
477  if ((beginBitPosition & 0x07U) != 0)
478  {
479  // we are not aligned to byte
480  for (size_t i = 0; i < len; ++i)
481  {
482  writeBits(data[i], 8);
483  }
484  }
485  else
486  {
487  // we are aligned to bytes
488  setBitPosition(beginBitPosition + len * 8);
489  if (hasWriteBuffer())
490  {
491  (void)std::copy(data.begin(), data.end(), m_buffer.begin() + beginBitPosition / 8);
492  }
493  }
494 }
495 
497 {
498  const size_t len = data.size();
500 
501  const BitPosType beginBitPosition = getBitPosition();
502  if ((beginBitPosition & 0x07U) != 0)
503  {
504  // we are not aligned to byte
505  for (size_t i = 0; i < len; ++i)
506  {
507  writeBits(static_cast<uint32_t>(std::char_traits<char>::to_int_type(data[i])), 8);
508  }
509  }
510  else
511  {
512  // we are aligned to bytes
513  setBitPosition(beginBitPosition + len * 8);
514  if (hasWriteBuffer())
515  {
516  (void)std::copy(data.begin(), data.begin() + len, m_buffer.data() + beginBitPosition / 8);
517  }
518  }
519 }
520 
522 {
523  writeBits((data ? 1 : 0), 1);
524 }
525 
527 {
528  if (hasWriteBuffer())
529  {
530  checkCapacity(position);
531  }
532 
533  m_bitIndex = position;
534 }
535 
536 void BitStreamWriter::alignTo(size_t alignment)
537 {
538  const BitPosType offset = getBitPosition() % alignment;
539  if (offset != 0)
540  {
541  const uint8_t skip = static_cast<uint8_t>(alignment - offset);
542  writeBits64(0, skip);
543  }
544 }
545 
546 const uint8_t* BitStreamWriter::getWriteBuffer() const
547 {
548  return m_buffer.data();
549 }
550 
552 {
553  return m_buffer;
554 }
555 
556 void BitStreamWriter::writeUnsignedBits(uint32_t data, uint8_t numBits)
557 {
558  if (!hasWriteBuffer())
559  {
560  m_bitIndex += numBits;
561  return;
562  }
563 
564  checkCapacity(m_bitIndex + numBits);
565 
566  uint8_t restNumBits = numBits;
567  const uint8_t bitsUsed = m_bitIndex & 0x07U;
568  uint8_t bitsFree = static_cast<uint8_t>(8 - bitsUsed);
569  size_t byteIndex = m_bitIndex / 8;
570 
571  if (restNumBits > bitsFree)
572  {
573  // first part
574  const uint8_t shiftNum = static_cast<uint8_t>(restNumBits - bitsFree);
575  const uint8_t maskedByte = static_cast<uint8_t>(m_buffer[byteIndex] & ~(0xFFU >> bitsUsed));
576  m_buffer[byteIndex++] = static_cast<uint8_t>(maskedByte | (data >> shiftNum));
577  restNumBits = static_cast<uint8_t>(restNumBits - bitsFree);
578 
579  // middle parts
580  while (restNumBits >= 8)
581  {
582  restNumBits = static_cast<uint8_t>(restNumBits - 8);
583  m_buffer[byteIndex++] = static_cast<uint8_t>((data >> restNumBits) & MAX_U32_VALUES[8]);
584  }
585 
586  // reset bits free
587  bitsFree = 8;
588  }
589 
590  // last part
591  if (restNumBits > 0)
592  {
593  const uint8_t shiftNum = static_cast<uint8_t>(bitsFree - restNumBits);
594  const uint32_t mask = MAX_U32_VALUES[restNumBits];
595  const uint8_t maskedByte =
596  m_buffer[byteIndex] & static_cast<uint8_t>(~static_cast<uint8_t>(mask << shiftNum));
597  m_buffer[byteIndex] = static_cast<uint8_t>(maskedByte | ((data & mask) << shiftNum));
598  }
599 
600  m_bitIndex += numBits;
601 }
602 
603 inline void BitStreamWriter::writeUnsignedBits64(uint64_t data, uint8_t numBits)
604 {
605  if (numBits <= 32)
606  {
607  writeUnsignedBits(static_cast<uint32_t>(data), numBits);
608  }
609  else
610  {
611  writeUnsignedBits(static_cast<uint32_t>(data >> 32U), static_cast<uint8_t>(numBits - 32));
612  writeUnsignedBits(static_cast<uint32_t>(data), 32);
613  }
614 }
615 
616 inline void BitStreamWriter::writeSignedVarNum(int64_t value, size_t maxVarBytes, size_t numVarBytes)
617 {
618  const uint64_t absValue = static_cast<uint64_t>(value < 0 ? -value : value);
619  writeVarNum(absValue, true, value < 0, maxVarBytes, numVarBytes);
620 }
621 
622 inline void BitStreamWriter::writeUnsignedVarNum(uint64_t value, size_t maxVarBytes, size_t numVarBytes)
623 {
624  writeVarNum(value, false, false, maxVarBytes, numVarBytes);
625 }
626 
627 inline void BitStreamWriter::writeVarNum(
628  uint64_t value, bool hasSign, bool isNegative, size_t maxVarBytes, size_t numVarBytes)
629 {
630  static const std::array<uint64_t, 8> bitMasks = {0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF};
631  const bool hasMaxByteRange = (numVarBytes == maxVarBytes);
632 
633  for (size_t i = 0; i < numVarBytes; i++)
634  {
635  uint8_t byte = 0x00;
636  uint8_t numBits = 8;
637  const bool hasNextByte = (i < numVarBytes - 1);
638  const bool hasSignBit = (hasSign && i == 0);
639  if (hasSignBit)
640  {
641  if (isNegative)
642  {
643  byte |= 0x80U;
644  }
645  numBits--;
646  }
647  if (hasNextByte)
648  {
649  numBits--;
650  const uint8_t add = static_cast<uint8_t>(0x01U << numBits);
651  byte = static_cast<uint8_t>(byte | add); // use bit 6 if signed bit is present, use bit 7 otherwise
652  }
653  else // this is the last byte
654  {
655  if (!hasMaxByteRange) // next byte indicator is not used in last byte in case of max byte range
656  {
657  numBits--;
658  }
659  }
660 
661  const size_t shiftBits = (numVarBytes - (i + 1)) * 7 + ((hasMaxByteRange && hasNextByte) ? 1 : 0);
662  const uint8_t add = static_cast<uint8_t>((value >> shiftBits) & bitMasks[numBits - 1U]);
663  byte = static_cast<uint8_t>(byte | add);
664  writeUnsignedBits(byte, 8);
665  }
666 }
667 
668 inline void BitStreamWriter::throwInsufficientCapacityException() const
669 {
670  throw InsufficientCapacityException("BitStreamWriter: Reached end of bit buffer!");
671 }
672 
673 inline void BitStreamWriter::checkCapacity(size_t bitSize) const
674 {
675  if (bitSize > m_bufferBitSize)
676  {
677  throwInsufficientCapacityException();
678  }
679 }
680 
681 } // namespace zserio
constexpr size_type size() const noexcept
Definition: StringView.h:240
constexpr const_iterator begin() const noexcept
Definition: StringView.h:101
void writeFloat64(double data)
void writeVarInt64(int64_t data)
void writeVarInt16(int16_t data)
Span< const uint8_t > getBuffer() const
void writeString(StringView data)
void writeSignedBits(int32_t data, uint8_t numBits=32)
void writeFloat32(float data)
BitPosType getBitPosition() const
void writeVarUInt64(uint64_t data)
void writeVarUInt16(uint16_t data)
const uint8_t * getWriteBuffer() const
void writeVarInt32(int32_t data)
void writeSignedBits64(int64_t data, uint8_t numBits=64)
void writeVarSize(uint32_t data)
void writeVarUInt32(uint32_t data)
void writeVarUInt(uint64_t data)
void writeVarInt(int64_t data)
void writeFloat16(float data)
void writeBits64(uint64_t data, uint8_t numBits=64)
void writeBytes(Span< const uint8_t > data)
BitStreamWriter(uint8_t *buffer, size_t bufferBitSize, BitsTag)
void writeBits(uint32_t data, uint8_t numBits=32)
void setBitPosition(BitPosType position)
void alignTo(size_t alignment)
constexpr size_type size() const noexcept
Definition: Span.h:281
constexpr pointer data() const noexcept
Definition: Span.h:271
constexpr iterator end() const noexcept
Definition: Span.h:210
constexpr iterator begin() const noexcept
Definition: Span.h:200
uint8_t numBits(uint64_t numValues)
size_t bitSizeOfVarInt32(int32_t value)
uint64_t convertDoubleToUInt64(double float64)
Definition: FloatUtil.cpp:193
uint32_t convertFloatToUInt32(float float32)
Definition: FloatUtil.cpp:177
size_t bitSizeOfVarUInt32(uint32_t value)
size_t bitSizeOfVarInt64(int64_t value)
uint16_t convertFloatToUInt16(float float32)
Definition: FloatUtil.cpp:83
size_t bitSizeOfVarSize(uint32_t value)
size_t bitSizeOfVarUInt64(uint64_t value)
uint32_t convertSizeToUInt32(size_t value)
size_t bitSizeOfVarInt16(int16_t value)
size_t bitSizeOfVarUInt(uint64_t value)
size_t bitSizeOfVarInt(int64_t value)
size_t bitSizeOfVarUInt16(uint16_t value)