Zserio C++ runtime library  1.4.0
Built for Zserio 2.18.1
BitStreamReader.h
Go to the documentation of this file.
1 #ifndef ZSERIO_BIT_STREAM_READER_H_INC
2 #define ZSERIO_BIT_STREAM_READER_H_INC
3 
4 #include <algorithm>
5 #include <cstring>
6 #include <string>
7 
8 #include "zserio/BitBuffer.h"
9 #include "zserio/RebindAlloc.h"
10 #include "zserio/Span.h"
11 #include "zserio/String.h"
12 #include "zserio/Types.h"
13 #include "zserio/Vector.h"
14 
15 namespace zserio
16 {
17 
22 {
23 public:
24  static constexpr size_t MAX_INITIAL_ARRAY_ALLOCATION = 128 * 1024;
25 
31  {}
37  explicit ArrayPreallocation(size_t alloc) :
38  allocation(alloc)
39  {}
43  operator size_t() const
44  {
45  return allocation;
46  }
47 
48 private:
49  size_t allocation;
50 };
51 
56 {
57 public:
59  using BitPosType = size_t;
60 
65  {
72  explicit ReaderContext(
73  Span<const uint8_t> readBuffer, size_t readBufferBitSize, size_t maxArrayPrealloc);
74 
78  ~ReaderContext() = default;
79 
84  ReaderContext(const ReaderContext&) = delete;
86 
87  ReaderContext(const ReaderContext&&) = delete;
96  uintptr_t cache;
97  uint8_t cacheNumBits;
101  const size_t maxArrayPreallocation;
102  };
103 
111  explicit BitStreamReader(
112  const uint8_t* buffer, size_t bufferByteSize, ArrayPreallocation maxArrayPrealloc = {});
113 
120  explicit BitStreamReader(Span<const uint8_t> buffer, ArrayPreallocation maxArrayPrealloc = {});
121 
129  explicit BitStreamReader(
130  Span<const uint8_t> buffer, size_t bufferBitSize, ArrayPreallocation maxArrayPrealloc = {});
131 
139  explicit BitStreamReader(
140  const uint8_t* buffer, size_t bufferBitSize, BitsTag, ArrayPreallocation maxArrayPrealloc = {});
141 
148  template <typename ALLOC>
149  explicit BitStreamReader(const BasicBitBuffer<ALLOC>& bitBuffer, ArrayPreallocation maxArrayPrealloc = {}) :
150  BitStreamReader(bitBuffer.getData(), bitBuffer.getBitSize(), maxArrayPrealloc)
151  {}
152 
156  ~BitStreamReader() = default;
157 
165  uint32_t readBits(uint8_t numBits = 32);
166 
174  uint64_t readBits64(uint8_t numBits = 64);
175 
183  int32_t readSignedBits(uint8_t numBits = 32);
184 
192  int64_t readSignedBits64(uint8_t numBits = 64);
193 
199  int64_t readVarInt64();
200 
206  int32_t readVarInt32();
207 
213  int16_t readVarInt16();
214 
220  uint64_t readVarUInt64();
221 
227  uint32_t readVarUInt32();
228 
234  uint16_t readVarUInt16();
235 
241  int64_t readVarInt();
242 
248  uint64_t readVarUInt();
249 
255  uint32_t readVarSize();
256 
262  float readFloat16();
263 
269  float readFloat32();
270 
276  double readFloat64();
277 
285  template <typename ALLOC = std::allocator<uint8_t>>
286  vector<uint8_t, ALLOC> readBytes(const ALLOC& alloc = ALLOC())
287  {
288  const size_t len = static_cast<size_t>(readVarSize());
289  const BitPosType beginBitPosition = getBitPosition();
290  if (beginBitPosition + 8ULL * len > getBufferBitSize())
291  {
292  throw CppRuntimeException("BitStreamReader: Byte array size exceeds available buffer!");
293  }
294  if ((beginBitPosition & 0x07U) != 0)
295  {
296  // we are not aligned to byte
297  vector<uint8_t, ALLOC> value{alloc};
298  value.reserve(len);
299  for (size_t i = 0; i < len; ++i)
300  {
301  value.push_back(readByte());
302  }
303  return value;
304  }
305  else
306  {
307  // we are aligned to byte
308  setBitPosition(beginBitPosition + len * 8);
309  Span<const uint8_t>::iterator beginIt = m_context.buffer.begin() + beginBitPosition / 8;
310  return vector<uint8_t, ALLOC>(beginIt, beginIt + len, alloc);
311  }
312  }
313 
321  template <typename ALLOC = std::allocator<char>>
322  string<ALLOC> readString(const ALLOC& alloc = ALLOC())
323  {
324  const size_t len = static_cast<size_t>(readVarSize());
325  const BitPosType beginBitPosition = getBitPosition();
326  if (beginBitPosition + 8ULL * len > getBufferBitSize())
327  {
328  throw CppRuntimeException("BitStreamReader: String size exceeds available buffer!");
329  }
330  if ((beginBitPosition & 0x07U) != 0)
331  {
332  // we are not aligned to byte
333  string<ALLOC> value{alloc};
334  value.reserve(len);
335  for (size_t i = 0; i < len; ++i)
336  {
337  using char_traits = std::char_traits<char>;
338  const char readCharacter =
339  char_traits::to_char_type(static_cast<char_traits::int_type>(readByte()));
340  value.push_back(readCharacter);
341  }
342  return value;
343  }
344  else
345  {
346  // we are aligned to byte
347  setBitPosition(beginBitPosition + len * 8);
348  Span<const uint8_t>::iterator beginIt = m_context.buffer.begin() + beginBitPosition / 8;
349  return string<ALLOC>(beginIt, beginIt + len, alloc);
350  }
351  }
352 
358  bool readBool();
359 
367  template <typename ALLOC = std::allocator<uint8_t>>
369  {
370  const size_t bitSize = static_cast<size_t>(readVarSize());
371  const BitPosType beginBitPosition = getBitPosition();
372  if (beginBitPosition + static_cast<uint64_t>(bitSize) > getBufferBitSize())
373  {
374  throw CppRuntimeException("BitStreamReader: Bit buffer size exceeds available buffer!");
375  }
376 
377  const size_t numBytesToRead = bitSize / 8;
378  const uint8_t numRestBits = static_cast<uint8_t>(bitSize - numBytesToRead * 8);
379  BasicBitBuffer<RebindAlloc<ALLOC, uint8_t>> bitBuffer(bitSize, allocator);
380  Span<uint8_t> buffer = bitBuffer.getData();
381  const Span<uint8_t>::iterator itEnd = buffer.begin() + numBytesToRead;
382  if ((beginBitPosition & 0x07U) != 0)
383  {
384  // we are not aligned to byte
385  for (Span<uint8_t>::iterator it = buffer.begin(); it != itEnd; ++it)
386  {
387  *it = static_cast<uint8_t>(readBits(8));
388  }
389  }
390  else
391  {
392  // we are aligned to byte
393  setBitPosition(beginBitPosition + numBytesToRead * 8);
394  Span<const uint8_t>::const_iterator sourceIt = m_context.buffer.begin() + beginBitPosition / 8;
395  (void)std::copy(sourceIt, sourceIt + numBytesToRead, buffer.begin());
396  }
397 
398  if (numRestBits > 0)
399  {
400  *itEnd = static_cast<uint8_t>(readBits(numRestBits) << (8U - numRestBits));
401  }
402 
403  return bitBuffer;
404  }
405 
412  {
413  return m_context.bitIndex;
414  }
415 
421  void setBitPosition(BitPosType position);
422 
428  void alignTo(size_t alignment);
429 
435  size_t getBufferBitSize() const
436  {
437  return m_context.bufferBitSize;
438  }
439 
446  {
447  return m_context.maxArrayPreallocation;
448  }
449 
450 private:
451  uint8_t readByte();
452 
453  ReaderContext m_context;
454 };
455 
456 } // namespace zserio
457 
458 #endif // ifndef ZSERIO_BIT_STREAM_READER_H_INC
static constexpr size_t MAX_INITIAL_ARRAY_ALLOCATION
ArrayPreallocation(size_t alloc)
Span< const uint8_t > getData() const
Definition: BitBuffer.h:420
size_t getBitSize() const
Definition: BitBuffer.h:402
void setBitPosition(BitPosType position)
void alignTo(size_t alignment)
uint64_t readBits64(uint8_t numBits=64)
size_t getMaxArrayPreallocation() const
uint32_t readBits(uint8_t numBits=32)
BasicBitBuffer< RebindAlloc< ALLOC, uint8_t > > readBitBuffer(const ALLOC &allocator=ALLOC())
BitStreamReader(const BasicBitBuffer< ALLOC > &bitBuffer, ArrayPreallocation maxArrayPrealloc={})
size_t getBufferBitSize() const
string< ALLOC > readString(const ALLOC &alloc=ALLOC())
vector< uint8_t, ALLOC > readBytes(const ALLOC &alloc=ALLOC())
int32_t readSignedBits(uint8_t numBits=32)
int64_t readSignedBits64(uint8_t numBits=64)
BitStreamReader(const uint8_t *buffer, size_t bufferByteSize, ArrayPreallocation maxArrayPrealloc={})
BitPosType getBitPosition() const
constexpr iterator begin() const noexcept
Definition: Span.h:202
uint8_t numBits(uint64_t numValues)
std::basic_string< char, std::char_traits< char >, RebindAlloc< ALLOC, char > > string
Definition: String.h:17
std::vector< T, RebindAlloc< ALLOC, T > > vector
Definition: Vector.h:17
ReaderContext(Span< const uint8_t > readBuffer, size_t readBufferBitSize, size_t maxArrayPrealloc)
ReaderContext & operator=(const ReaderContext &&)=delete
ReaderContext(const ReaderContext &&)=delete
ReaderContext & operator=(const ReaderContext &)=delete
ReaderContext(const ReaderContext &)=delete