Zserio C++ runtime library  1.0.0
Built for Zserio 2.13.0
BitStreamWriter.cpp
Go to the documentation of this file.
1 #include <cstring>
2 #include <fstream>
3 #include <array>
4 #include <algorithm>
5 
8 #include "zserio/FloatUtil.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 BitStreamWriter::BitStreamWriter(uint8_t* buffer, size_t bufferBitSize, BitsTag) :
117  m_buffer(buffer, (bufferBitSize + 7) / 8),
118  m_bitIndex(0),
119  m_bufferBitSize(bufferBitSize)
120 {}
121 
122 BitStreamWriter::BitStreamWriter(uint8_t* buffer, size_t bufferByteSize) :
123  BitStreamWriter(Span<uint8_t>(buffer, bufferByteSize))
124 {}
125 
127  m_buffer(buffer),
128  m_bitIndex(0),
129  m_bufferBitSize(buffer.size() * 8)
130 {}
131 
132 BitStreamWriter::BitStreamWriter(Span<uint8_t> buffer, size_t bufferBitSize) :
133  m_buffer(buffer),
134  m_bitIndex(0),
135  m_bufferBitSize(bufferBitSize)
136 {
137  if (buffer.size() < (bufferBitSize + 7) / 8)
138  {
139  throw CppRuntimeException("BitStreamWriter: Wrong buffer bit size ('") << buffer.size() <<
140  "' < '" << (bufferBitSize + 7) / 8 << "')!";
141  }
142 }
143 
144 void BitStreamWriter::writeBits(uint32_t data, uint8_t numBits)
145 {
146  if (numBits > sizeof(uint32_t) * 8 || data > MAX_U32_VALUES[numBits])
147  {
148  throw CppRuntimeException("BitStreamWriter: Writing of ") << numBits << "-bits value '" << data <<
149  "' failed!";
150  }
151 
152  writeUnsignedBits(data, numBits);
153 }
154 
155 void BitStreamWriter::writeBits64(uint64_t data, uint8_t numBits)
156 {
157  if (numBits > sizeof(uint64_t) * 8 || data > MAX_U64_VALUES[numBits])
158  {
159  throw CppRuntimeException("BitStreamWriter: Writing of ") << numBits << "-bits value '" << data <<
160  "' failed!";
161  }
162 
163  writeUnsignedBits64(data, numBits);
164 }
165 
166 void BitStreamWriter::writeSignedBits(int32_t data, uint8_t numBits)
167 {
168  if (numBits > sizeof(int32_t) * 8 || data < MIN_I32_VALUES[numBits] || data > MAX_I32_VALUES[numBits])
169  {
170  throw CppRuntimeException("BitStreamWriter: Writing of ") << numBits << "-bits value '" << data <<
171  "' failed!";
172  }
173 
174  writeUnsignedBits(static_cast<uint32_t>(data) & MAX_U32_VALUES[numBits], numBits);
175 }
176 
177 void BitStreamWriter::writeSignedBits64(int64_t data, uint8_t numBits)
178 {
179  if (numBits > sizeof(int64_t) * 8 || data < MIN_I64_VALUES[numBits] || data > MAX_I64_VALUES[numBits])
180  {
181  throw CppRuntimeException("BitStreamWriter: Writing of ") << numBits << "-bits value '" << data <<
182  "' failed!";
183  }
184 
185  writeUnsignedBits64(static_cast<uint64_t>(data) & MAX_U64_VALUES[numBits], numBits);
186 }
187 
189 {
190  writeSignedVarNum(data, 8, zserio::bitSizeOfVarInt64(data) / 8);
191 }
192 
194 {
195  writeSignedVarNum(data, 4, zserio::bitSizeOfVarInt32(data) / 8);
196 }
197 
199 {
200  writeSignedVarNum(data, 2, zserio::bitSizeOfVarInt16(data) / 8);
201 }
202 
204 {
205  writeUnsignedVarNum(data, 8, zserio::bitSizeOfVarUInt64(data) / 8);
206 }
207 
209 {
210  writeUnsignedVarNum(data, 4, zserio::bitSizeOfVarUInt32(data) / 8);
211 }
212 
214 {
215  writeUnsignedVarNum(data, 2, zserio::bitSizeOfVarUInt16(data) / 8);
216 }
217 
219 {
220  if (data == INT64_MIN)
221  writeBits(0x80, 8); // INT64_MIN is encoded as -0
222  else
223  writeSignedVarNum(data, 9, zserio::bitSizeOfVarInt(data) / 8);
224 }
225 
226 void BitStreamWriter::writeVarUInt(uint64_t data)
227 {
228  writeUnsignedVarNum(data, 9, zserio::bitSizeOfVarUInt(data) / 8);
229 }
230 
231 void BitStreamWriter::writeVarSize(uint32_t data)
232 {
233  writeUnsignedVarNum(data, 5, zserio::bitSizeOfVarSize(data) / 8);
234 }
235 
237 {
238  const uint16_t halfPrecisionFloat = convertFloatToUInt16(data);
239  writeUnsignedBits(halfPrecisionFloat, 16);
240 }
241 
243 {
244  const uint32_t singlePrecisionFloat = convertFloatToUInt32(data);
245  writeUnsignedBits(singlePrecisionFloat, 32);
246 }
247 
249 {
250  const uint64_t doublePrecisionFloat = convertDoubleToUInt64(data);
251  writeUnsignedBits64(doublePrecisionFloat, 64);
252 }
253 
255 {
256  const size_t len = data.size();
258 
259  const BitPosType beginBitPosition = getBitPosition();
260  if ((beginBitPosition & 0x07U) != 0)
261  {
262  // we are not aligned to byte
263  for (size_t i = 0; i < len; ++i)
264  writeBits(data[i], 8);
265  }
266  else
267  {
268  // we are aligned to bytes
269  setBitPosition(beginBitPosition + len * 8);
270  if (hasWriteBuffer())
271  std::copy(data.begin(), data.end(), m_buffer.begin() + beginBitPosition / 8);
272  }
273 }
274 
276 {
277  const size_t len = data.size();
279 
280  const BitPosType beginBitPosition = getBitPosition();
281  if ((beginBitPosition & 0x07U) != 0)
282  {
283  // we are not aligned to byte
284  for (size_t i = 0; i < len; ++i)
285  writeBits(static_cast<uint8_t>(data[i]), 8);
286  }
287  else
288  {
289  // we are aligned to bytes
290  setBitPosition(beginBitPosition + len * 8);
291  if (hasWriteBuffer())
292  std::copy(data.begin(), data.begin() + len, m_buffer.data() + beginBitPosition / 8);
293  }
294 }
295 
297 {
298  writeBits((data ? 1 : 0), 1);
299 }
300 
302 {
303  if (hasWriteBuffer())
304  checkCapacity(position);
305 
306  m_bitIndex = position;
307 }
308 
309 void BitStreamWriter::alignTo(size_t alignment)
310 {
311  const BitPosType offset = getBitPosition() % alignment;
312  if (offset != 0)
313  {
314  const uint8_t skip = static_cast<uint8_t>(alignment - offset);
315  writeBits64(0, skip);
316  }
317 }
318 
319 const uint8_t* BitStreamWriter::getWriteBuffer() const
320 {
321  return m_buffer.data();
322 }
323 
325 {
326  return m_buffer;
327 }
328 
329 void BitStreamWriter::writeUnsignedBits(uint32_t data, uint8_t numBits)
330 {
331  if (!hasWriteBuffer())
332  {
333  m_bitIndex += numBits;
334  return;
335  }
336 
337  checkCapacity(m_bitIndex + numBits);
338 
339  uint8_t restNumBits = numBits;
340  const uint8_t bitsUsed = m_bitIndex & 0x07U;
341  uint8_t bitsFree = 8 - bitsUsed;
342  size_t byteIndex = m_bitIndex / 8;
343 
344  if (restNumBits > bitsFree)
345  {
346  // first part
347  const uint8_t shiftNum = restNumBits - bitsFree;
348  const uint8_t maskedByte = m_buffer[byteIndex] & ~(0xFFU >> bitsUsed);
349  m_buffer[byteIndex++] = maskedByte | static_cast<uint8_t>(data >> shiftNum);
350  restNumBits -= bitsFree;
351 
352  // middle parts
353  while (restNumBits >= 8)
354  {
355  restNumBits -= 8;
356  m_buffer[byteIndex++] = static_cast<uint8_t>((data >> restNumBits) & MAX_U32_VALUES[8]);
357  }
358 
359  // reset bits free
360  bitsFree = 8;
361  }
362 
363  // last part
364  if (restNumBits > 0)
365  {
366  const uint8_t shiftNum = bitsFree - restNumBits;
367  const uint32_t mask = MAX_U32_VALUES[restNumBits];
368  const uint8_t maskedByte = m_buffer[byteIndex] &
369  static_cast<uint8_t>(~static_cast<uint8_t>(mask << shiftNum));
370  m_buffer[byteIndex] = maskedByte | static_cast<uint8_t>((data & mask) << shiftNum);
371  }
372 
373  m_bitIndex += numBits;
374 }
375 
376 inline void BitStreamWriter::writeUnsignedBits64(uint64_t data, uint8_t numBits)
377 {
378  if (numBits <= 32)
379  {
380  writeUnsignedBits(static_cast<uint32_t>(data), numBits);
381  }
382  else
383  {
384  writeUnsignedBits(static_cast<uint32_t>(data >> 32U), numBits - 32);
385  writeUnsignedBits(static_cast<uint32_t>(data), 32);
386  }
387 }
388 
389 inline void BitStreamWriter::writeSignedVarNum(int64_t value, size_t maxVarBytes, size_t numVarBytes)
390 {
391  const uint64_t absValue = static_cast<uint64_t>(value < 0 ? -value : value);
392  writeVarNum(absValue, true, value < 0, maxVarBytes, numVarBytes);
393 }
394 
395 inline void BitStreamWriter::writeUnsignedVarNum(uint64_t value, size_t maxVarBytes, size_t numVarBytes)
396 {
397  writeVarNum(value, false, false, maxVarBytes, numVarBytes);
398 }
399 
400 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  const bool hasMaxByteRange = (numVarBytes == maxVarBytes);
405 
406  for (size_t i = 0; i < numVarBytes; i++)
407  {
408  uint8_t byte = 0x00;
409  uint8_t numBits = 8;
410  const bool hasNextByte = (i < numVarBytes - 1);
411  const bool hasSignBit = (hasSign && i == 0);
412  if (hasSignBit)
413  {
414  if (isNegative)
415  byte |= 0x80U;
416  numBits--;
417  }
418  if (hasNextByte)
419  {
420  numBits--;
421  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  if (!hasMaxByteRange) // next byte indicator is not used in last byte in case of max byte range
426  numBits--;
427  }
428 
429  const size_t shiftBits = (numVarBytes - (i + 1)) * 7 + ((hasMaxByteRange && hasNextByte) ? 1 : 0);
430  byte |= static_cast<uint8_t>((value >> shiftBits) & bitMasks[numBits - 1]);
431  writeUnsignedBits(byte, 8);
432  }
433 }
434 
435 inline void BitStreamWriter::throwInsufficientCapacityException() const
436 {
437  throw InsufficientCapacityException("BitStreamWriter: Reached end of bit buffer!");
438 }
439 
440 inline void BitStreamWriter::checkCapacity(size_t bitSize) const
441 {
442  if (bitSize > m_bufferBitSize)
443  throwInsufficientCapacityException();
444 }
445 
446 } // namespace zserio
void writeVarInt64(int64_t data)
void alignTo(size_t alignment)
void writeVarUInt16(uint16_t data)
constexpr size_type size() const noexcept
Definition: StringView.h:237
void writeBytes(Span< const uint8_t > data)
void writeFloat16(float data)
void writeVarUInt64(uint64_t data)
void writeVarInt16(int16_t data)
size_t bitSizeOfVarUInt64(uint64_t value)
uint8_t numBits(uint64_t numValues)
const uint8_t * getWriteBuffer() const
BitStreamWriter(uint8_t *buffer, size_t bufferBitSize, BitsTag)
void writeFloat32(float data)
void writeVarInt(int64_t data)
void writeVarInt32(int32_t data)
void writeVarUInt32(uint32_t data)
void writeString(StringView data)
void writeVarSize(uint32_t data)
void writeSignedBits(int32_t data, uint8_t numBits=32)
size_t bitSizeOfVarSize(uint32_t value)
size_t bitSizeOfVarInt64(int64_t value)
size_t bitSizeOfVarInt16(int16_t value)
uint32_t convertSizeToUInt32(size_t value)
bool hasWriteBuffer() const
size_t bitSizeOfVarUInt16(uint16_t value)
constexpr size_type size() const noexcept
Definition: Span.h:276
Span< const uint8_t > getBuffer() const
void writeFloat64(double data)
void setBitPosition(BitPosType position)
size_t bitSizeOfVarUInt32(uint32_t value)
BitPosType getBitPosition() const
void writeBits(uint32_t data, uint8_t numBits=32)
void writeVarUInt(uint64_t data)
size_t bitSizeOfVarUInt(uint64_t value)
uint32_t convertFloatToUInt32(float float32)
Definition: FloatUtil.cpp:169
size_t bitSizeOfVarInt(int64_t value)
constexpr pointer data() const noexcept
Definition: Span.h:266
constexpr iterator begin() const noexcept
Definition: Span.h:195
constexpr const_iterator begin() const noexcept
Definition: StringView.h:98
constexpr iterator end() const noexcept
Definition: Span.h:205
void writeSignedBits64(int64_t data, uint8_t numBits=64)
size_t bitSizeOfVarInt32(int32_t value)
uint64_t convertDoubleToUInt64(double float64)
Definition: FloatUtil.cpp:183
void writeBits64(uint64_t data, uint8_t numBits=64)
uint16_t convertFloatToUInt16(float float32)
Definition: FloatUtil.cpp:81