Zserio C++ runtime library  1.0.1
Built for Zserio 2.14.0
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 > 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 > 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 > sizeof(int32_t) * 8 || data < MIN_I32_VALUES[numBits] || data > MAX_I32_VALUES[numBits])
379  {
380  throw CppRuntimeException("BitStreamWriter: Writing of ")
381  << numBits << "-bits value '" << data << "' failed!";
382  }
383 
384  writeUnsignedBits(static_cast<uint32_t>(data) & MAX_U32_VALUES[numBits], numBits);
385 }
386 
387 void BitStreamWriter::writeSignedBits64(int64_t data, uint8_t numBits)
388 {
389  if (numBits > sizeof(int64_t) * 8 || data < MIN_I64_VALUES[numBits] || data > MAX_I64_VALUES[numBits])
390  {
391  throw CppRuntimeException("BitStreamWriter: Writing of ")
392  << numBits << "-bits value '" << data << "' failed!";
393  }
394 
395  writeUnsignedBits64(static_cast<uint64_t>(data) & MAX_U64_VALUES[numBits], numBits);
396 }
397 
399 {
400  writeSignedVarNum(data, 8, zserio::bitSizeOfVarInt64(data) / 8);
401 }
402 
404 {
405  writeSignedVarNum(data, 4, zserio::bitSizeOfVarInt32(data) / 8);
406 }
407 
409 {
410  writeSignedVarNum(data, 2, zserio::bitSizeOfVarInt16(data) / 8);
411 }
412 
414 {
415  writeUnsignedVarNum(data, 8, zserio::bitSizeOfVarUInt64(data) / 8);
416 }
417 
419 {
420  writeUnsignedVarNum(data, 4, zserio::bitSizeOfVarUInt32(data) / 8);
421 }
422 
424 {
425  writeUnsignedVarNum(data, 2, zserio::bitSizeOfVarUInt16(data) / 8);
426 }
427 
429 {
430  if (data == INT64_MIN)
431  writeBits(0x80, 8); // INT64_MIN is encoded as -0
432  else
433  writeSignedVarNum(data, 9, zserio::bitSizeOfVarInt(data) / 8);
434 }
435 
436 void BitStreamWriter::writeVarUInt(uint64_t data)
437 {
438  writeUnsignedVarNum(data, 9, zserio::bitSizeOfVarUInt(data) / 8);
439 }
440 
441 void BitStreamWriter::writeVarSize(uint32_t data)
442 {
443  writeUnsignedVarNum(data, 5, zserio::bitSizeOfVarSize(data) / 8);
444 }
445 
447 {
448  const uint16_t halfPrecisionFloat = convertFloatToUInt16(data);
449  writeUnsignedBits(halfPrecisionFloat, 16);
450 }
451 
453 {
454  const uint32_t singlePrecisionFloat = convertFloatToUInt32(data);
455  writeUnsignedBits(singlePrecisionFloat, 32);
456 }
457 
459 {
460  const uint64_t doublePrecisionFloat = convertDoubleToUInt64(data);
461  writeUnsignedBits64(doublePrecisionFloat, 64);
462 }
463 
465 {
466  const size_t len = data.size();
468 
469  const BitPosType beginBitPosition = getBitPosition();
470  if ((beginBitPosition & 0x07U) != 0)
471  {
472  // we are not aligned to byte
473  for (size_t i = 0; i < len; ++i)
474  writeBits(data[i], 8);
475  }
476  else
477  {
478  // we are aligned to bytes
479  setBitPosition(beginBitPosition + len * 8);
480  if (hasWriteBuffer())
481  std::copy(data.begin(), data.end(), m_buffer.begin() + beginBitPosition / 8);
482  }
483 }
484 
486 {
487  const size_t len = data.size();
489 
490  const BitPosType beginBitPosition = getBitPosition();
491  if ((beginBitPosition & 0x07U) != 0)
492  {
493  // we are not aligned to byte
494  for (size_t i = 0; i < len; ++i)
495  writeBits(static_cast<uint8_t>(data[i]), 8);
496  }
497  else
498  {
499  // we are aligned to bytes
500  setBitPosition(beginBitPosition + len * 8);
501  if (hasWriteBuffer())
502  std::copy(data.begin(), data.begin() + len, m_buffer.data() + beginBitPosition / 8);
503  }
504 }
505 
507 {
508  writeBits((data ? 1 : 0), 1);
509 }
510 
512 {
513  if (hasWriteBuffer())
514  checkCapacity(position);
515 
516  m_bitIndex = position;
517 }
518 
519 void BitStreamWriter::alignTo(size_t alignment)
520 {
521  const BitPosType offset = getBitPosition() % alignment;
522  if (offset != 0)
523  {
524  const uint8_t skip = static_cast<uint8_t>(alignment - offset);
525  writeBits64(0, skip);
526  }
527 }
528 
529 const uint8_t* BitStreamWriter::getWriteBuffer() const
530 {
531  return m_buffer.data();
532 }
533 
535 {
536  return m_buffer;
537 }
538 
539 void BitStreamWriter::writeUnsignedBits(uint32_t data, uint8_t numBits)
540 {
541  if (!hasWriteBuffer())
542  {
543  m_bitIndex += numBits;
544  return;
545  }
546 
547  checkCapacity(m_bitIndex + numBits);
548 
549  uint8_t restNumBits = numBits;
550  const uint8_t bitsUsed = m_bitIndex & 0x07U;
551  uint8_t bitsFree = static_cast<uint8_t>(8 - bitsUsed);
552  size_t byteIndex = m_bitIndex / 8;
553 
554  if (restNumBits > bitsFree)
555  {
556  // first part
557  const uint8_t shiftNum = static_cast<uint8_t>(restNumBits - bitsFree);
558  const uint8_t maskedByte = static_cast<uint8_t>(m_buffer[byteIndex] & ~(0xFFU >> bitsUsed));
559  m_buffer[byteIndex++] = static_cast<uint8_t>(maskedByte | (data >> shiftNum));
560  restNumBits = static_cast<uint8_t>(restNumBits - bitsFree);
561 
562  // middle parts
563  while (restNumBits >= 8)
564  {
565  restNumBits = static_cast<uint8_t>(restNumBits - 8);
566  m_buffer[byteIndex++] = static_cast<uint8_t>((data >> restNumBits) & MAX_U32_VALUES[8]);
567  }
568 
569  // reset bits free
570  bitsFree = 8;
571  }
572 
573  // last part
574  if (restNumBits > 0)
575  {
576  const uint8_t shiftNum = static_cast<uint8_t>(bitsFree - restNumBits);
577  const uint32_t mask = MAX_U32_VALUES[restNumBits];
578  const uint8_t maskedByte =
579  m_buffer[byteIndex] & static_cast<uint8_t>(~static_cast<uint8_t>(mask << shiftNum));
580  m_buffer[byteIndex] = static_cast<uint8_t>(maskedByte | ((data & mask) << shiftNum));
581  }
582 
583  m_bitIndex += numBits;
584 }
585 
586 inline void BitStreamWriter::writeUnsignedBits64(uint64_t data, uint8_t numBits)
587 {
588  if (numBits <= 32)
589  {
590  writeUnsignedBits(static_cast<uint32_t>(data), numBits);
591  }
592  else
593  {
594  writeUnsignedBits(static_cast<uint32_t>(data >> 32U), static_cast<uint8_t>(numBits - 32));
595  writeUnsignedBits(static_cast<uint32_t>(data), 32);
596  }
597 }
598 
599 inline void BitStreamWriter::writeSignedVarNum(int64_t value, size_t maxVarBytes, size_t numVarBytes)
600 {
601  const uint64_t absValue = static_cast<uint64_t>(value < 0 ? -value : value);
602  writeVarNum(absValue, true, value < 0, maxVarBytes, numVarBytes);
603 }
604 
605 inline void BitStreamWriter::writeUnsignedVarNum(uint64_t value, size_t maxVarBytes, size_t numVarBytes)
606 {
607  writeVarNum(value, false, false, maxVarBytes, numVarBytes);
608 }
609 
610 inline void BitStreamWriter::writeVarNum(
611  uint64_t value, bool hasSign, bool isNegative, size_t maxVarBytes, size_t numVarBytes)
612 {
613  static const std::array<uint64_t, 8> bitMasks = {0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF};
614  const bool hasMaxByteRange = (numVarBytes == maxVarBytes);
615 
616  for (size_t i = 0; i < numVarBytes; i++)
617  {
618  uint8_t byte = 0x00;
619  uint8_t numBits = 8;
620  const bool hasNextByte = (i < numVarBytes - 1);
621  const bool hasSignBit = (hasSign && i == 0);
622  if (hasSignBit)
623  {
624  if (isNegative)
625  byte |= 0x80U;
626  numBits--;
627  }
628  if (hasNextByte)
629  {
630  numBits--;
631  const uint8_t add = static_cast<uint8_t>(0x01U << numBits);
632  byte = static_cast<uint8_t>(byte | add); // use bit 6 if signed bit is present, use bit 7 otherwise
633  }
634  else // this is the last byte
635  {
636  if (!hasMaxByteRange) // next byte indicator is not used in last byte in case of max byte range
637  numBits--;
638  }
639 
640  const size_t shiftBits = (numVarBytes - (i + 1)) * 7 + ((hasMaxByteRange && hasNextByte) ? 1 : 0);
641  const uint8_t add = static_cast<uint8_t>((value >> shiftBits) & bitMasks[numBits - 1]);
642  byte = static_cast<uint8_t>(byte | add);
643  writeUnsignedBits(byte, 8);
644  }
645 }
646 
647 inline void BitStreamWriter::throwInsufficientCapacityException() const
648 {
649  throw InsufficientCapacityException("BitStreamWriter: Reached end of bit buffer!");
650 }
651 
652 inline void BitStreamWriter::checkCapacity(size_t bitSize) const
653 {
654  if (bitSize > m_bufferBitSize)
655  throwInsufficientCapacityException();
656 }
657 
658 } // 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:186
uint32_t convertFloatToUInt32(float float32)
Definition: FloatUtil.cpp:172
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)