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