Zserio C++17 runtime library  0.5.0
Built for Zserio 2.17.0
BitBuffer.h
Go to the documentation of this file.
1 #ifndef ZSERIO_BIT_BUFFER_H_INC
2 #define ZSERIO_BIT_BUFFER_H_INC
3 
4 #include <cstddef>
5 #include <cstring>
6 #include <functional>
7 #include <string_view>
8 #include <type_traits>
9 #include <vector>
10 
11 #include "zserio/BitSize.h"
13 #include "zserio/HashCodeUtil.h"
14 #include "zserio/SizeConvertUtil.h"
15 #include "zserio/Span.h"
16 #include "zserio/Traits.h"
17 
18 namespace zserio
19 {
20 
25 struct BitsTag
26 {};
27 
34 template <typename ALLOC = std::allocator<uint8_t>>
36 {
37 public:
38  static_assert(std::is_same<uint8_t, typename ALLOC::value_type>::value,
39  "Allocator with uint8_t value_type is required!");
40 
41  using allocator_type = ALLOC;
42 
48  ALLOC get_allocator() const
49  {
50  return m_buffer.get_allocator();
51  }
52 
59 
65  explicit BasicBitBuffer(const ALLOC& allocator);
66 
73  explicit BasicBitBuffer(size_t bitSize, const ALLOC& allocator = {});
74 
81  explicit BasicBitBuffer(Span<const uint8_t> buffer, const ALLOC& allocator = {});
82 
92  explicit BasicBitBuffer(Span<const uint8_t> buffer, size_t bitSize, const ALLOC& allocator = {});
93 
99  explicit BasicBitBuffer(std::vector<uint8_t, ALLOC>&& buffer);
100 
109  explicit BasicBitBuffer(std::vector<uint8_t, ALLOC>&& buffer, size_t bitSize);
110 
114  BasicBitBuffer(const BasicBitBuffer& other, const ALLOC& allocator);
115 
119  BasicBitBuffer(BasicBitBuffer&& other, const ALLOC& allocator);
120 
125  ~BasicBitBuffer() = default;
126 
127  BasicBitBuffer(const BasicBitBuffer&) = default;
129 
143  bool operator==(const BasicBitBuffer& other) const;
144 
152  bool operator!=(const BasicBitBuffer& other) const
153  {
154  return !(*this == other);
155  }
156 
164  bool operator<(const BasicBitBuffer& other) const;
165 
173  bool operator>(const BasicBitBuffer& other) const
174  {
175  return other < *this;
176  }
177 
185  bool operator<=(const BasicBitBuffer& other) const
186  {
187  return !(other < *this);
188  }
189 
197  bool operator>=(const BasicBitBuffer& other) const
198  {
199  return !(*this < other);
200  }
201 
207  uint32_t hashCode() const;
208 
214  const uint8_t* getBuffer() const;
215 
221  uint8_t* getBuffer();
222 
228  size_t getBitSize() const;
229 
237  size_t getByteSize() const;
238 
244  const std::vector<uint8_t, ALLOC>& getBytes() const;
245 
252 
259 
260 private:
261  uint8_t getMaskedLastByte() const;
262 
263  std::vector<uint8_t, ALLOC> m_buffer;
264  size_t m_bitSize;
265 };
266 
267 template <typename ALLOC>
269  m_buffer(ALLOC()),
270  m_bitSize(0)
271 {}
272 
273 template <typename ALLOC>
274 BasicBitBuffer<ALLOC>::BasicBitBuffer(const ALLOC& allocator) :
275  m_buffer(allocator),
276  m_bitSize(0)
277 {}
278 
279 template <typename ALLOC>
280 BasicBitBuffer<ALLOC>::BasicBitBuffer(size_t bitSize, const ALLOC& allocator) :
281  m_buffer((bitSize + 7) / 8, 0, allocator),
282  m_bitSize(bitSize)
283 {}
284 
285 template <typename ALLOC>
287  m_buffer(buffer.begin(), buffer.end(), allocator),
288  m_bitSize(8 * buffer.size())
289 {}
290 
291 template <typename ALLOC>
292 BasicBitBuffer<ALLOC>::BasicBitBuffer(Span<const uint8_t> buffer, size_t bitSize, const ALLOC& allocator) :
293  m_buffer(buffer.begin(), buffer.end(), allocator),
294  m_bitSize(bitSize)
295 {
296  const size_t byteSize = (bitSize + 7) / 8;
297  if (buffer.size() < byteSize)
298  {
299  throw CppRuntimeException("BitBuffer: Bit size ")
300  << bitSize << " out of range for given span byte size " << buffer.size() << "!";
301  }
302 }
303 
304 template <typename ALLOC>
305 BasicBitBuffer<ALLOC>::BasicBitBuffer(std::vector<uint8_t, ALLOC>&& buffer) :
306  m_buffer(std::move(buffer)),
307  m_bitSize(8 * m_buffer.size())
308 {}
309 
310 template <typename ALLOC>
311 BasicBitBuffer<ALLOC>::BasicBitBuffer(std::vector<uint8_t, ALLOC>&& buffer, size_t bitSize) :
312  m_buffer(std::move(buffer)),
313  m_bitSize(bitSize)
314 {
315  const size_t byteSize = (bitSize + 7) / 8;
316  if (m_buffer.size() < byteSize)
317  {
318  throw CppRuntimeException("BitBuffer: Bit size ")
319  << bitSize << " out of range for given vector byte size " << m_buffer.size() << "!";
320  }
321 }
322 
323 template <typename ALLOC>
324 inline BasicBitBuffer<ALLOC>::BasicBitBuffer(const BasicBitBuffer& other, const ALLOC& allocator) :
325  m_buffer(other.m_buffer, allocator),
326  m_bitSize(other.m_bitSize)
327 {}
328 
329 template <typename ALLOC>
330 inline BasicBitBuffer<ALLOC>::BasicBitBuffer(BasicBitBuffer&& other, const ALLOC& allocator) :
331  m_buffer(std::move(other.m_buffer), allocator),
332  m_bitSize(other.m_bitSize)
333 {}
334 
335 template <typename ALLOC>
337 {
338  if (this != &other)
339  {
340  if (m_bitSize != other.m_bitSize)
341  {
342  return false;
343  }
344 
345  const size_t byteSize = getByteSize();
346  if (byteSize > 0)
347  {
348  if (byteSize > 1)
349  {
350  if (std::memcmp(getBuffer(), other.getBuffer(), byteSize - 1) != 0)
351  {
352  return false;
353  }
354  }
355 
356  if (getMaskedLastByte() != other.getMaskedLastByte())
357  {
358  return false;
359  }
360  }
361  }
362 
363  return true;
364 }
365 
366 template <typename ALLOC>
368 {
369  const size_t byteSize1 = getByteSize();
370  const size_t byteSize2 = other.getByteSize();
371 
372  if (byteSize1 == 0)
373  {
374  return byteSize2 != 0;
375  }
376  if (byteSize2 == 0)
377  {
378  return false;
379  }
380 
381  using DifferenceType = typename std::vector<uint8_t, ALLOC>::iterator::difference_type;
382 
383  auto first1 = m_buffer.begin();
384  const auto last1 = first1 + static_cast<DifferenceType>(byteSize1 - 1);
385  auto first2 = other.m_buffer.begin();
386  const auto last2 = first2 + static_cast<DifferenceType>(byteSize2 - 1);
387  for (; (first1 != last1) && (first2 != last2); ++first1, ++first2)
388  {
389  if (*first1 < *first2)
390  {
391  return true;
392  }
393  if (*first2 < *first1)
394  {
395  return false;
396  }
397  }
398 
399  const auto lastValue1 = first1 != last1 ? *first1 : getMaskedLastByte();
400  const auto lastValue2 = first2 != last2 ? *first2 : other.getMaskedLastByte();
401  if (lastValue1 < lastValue2)
402  {
403  return true;
404  }
405  if (lastValue2 < lastValue1)
406  {
407  return false;
408  }
409 
410  return (first1 == last1) && (first2 != last2);
411 }
412 
413 template <typename ALLOC>
415 {
416  uint32_t result = HASH_SEED;
417  const size_t byteSize = getByteSize();
418  if (byteSize > 0)
419  {
420  if (byteSize > 1)
421  {
422  auto lastIt = m_buffer.begin() + static_cast<int>(byteSize) - 1;
423  for (auto it = m_buffer.begin(); it != lastIt; ++it)
424  {
425  result = calcHashCode(result, *it);
426  }
427  }
428  result = calcHashCode(result, getMaskedLastByte());
429  }
430 
431  return result;
432 }
433 
434 template <typename ALLOC>
435 const uint8_t* BasicBitBuffer<ALLOC>::getBuffer() const
436 {
437  return m_buffer.data();
438 }
439 
440 template <typename ALLOC>
442 {
443  return m_buffer.data();
444 }
445 
446 template <typename ALLOC>
448 {
449  return m_bitSize;
450 }
451 
452 template <typename ALLOC>
454 {
455  return (m_bitSize + 7) / 8;
456 }
457 
458 template <typename ALLOC>
459 const std::vector<uint8_t, ALLOC>& BasicBitBuffer<ALLOC>::getBytes() const
460 {
461  return m_buffer;
462 }
463 
464 template <typename ALLOC>
466 {
467  return Span<const uint8_t>(m_buffer);
468 }
469 
470 template <typename ALLOC>
472 {
473  return Span<uint8_t>(m_buffer);
474 }
475 
476 template <typename ALLOC>
478 {
479  const size_t roundedByteSize = m_bitSize / 8;
480  const uint8_t lastByteBits = static_cast<uint8_t>(m_bitSize - 8 * roundedByteSize);
481 
482  return (lastByteBits == 0)
483  ? m_buffer[roundedByteSize - 1]
484  : static_cast<uint8_t>(m_buffer[roundedByteSize] & (0xFFU << (8U - lastByteBits)));
485 }
486 
489 
491 template <typename ALLOC>
492 using BasicBitBufferView = std::reference_wrapper<const BasicBitBuffer<ALLOC>>;
493 
495 using BitBufferView = std::reference_wrapper<const BitBuffer>;
496 
497 template <typename ALLOC>
498 struct view_type<BasicBitBuffer<ALLOC>>
499 {
501 };
502 
506 template <typename ALLOC>
508 {
509  return lhs.get() == rhs.get();
510 }
511 
512 template <typename ALLOC>
514 {
515  return lhs.get() != rhs.get();
516 }
517 
518 template <typename ALLOC>
520 {
521  return lhs.get() < rhs.get();
522 }
523 
524 template <typename ALLOC>
526 {
527  return lhs.get() > rhs.get();
528 }
529 
530 template <typename ALLOC>
532 {
533  return lhs.get() <= rhs.get();
534 }
535 
536 template <typename ALLOC>
538 {
539  return lhs.get() >= rhs.get();
540 }
541 
552 template <typename ALLOC>
554 {
555  return exception << "BitBuffer([...], " << bitBuffer.getBitSize() << ")";
556 }
557 
566 template <typename ALLOC>
567 uint32_t calcHashCode(uint32_t seedValue, const BasicBitBuffer<ALLOC>& value)
568 {
569  return calcHashCode(seedValue, std::hash<BasicBitBuffer<ALLOC>>{}(value));
570 }
571 
572 namespace detail
573 {
574 
575 template <typename ALLOC>
576 void validate(const BasicBitBufferView<ALLOC>&, std::string_view)
577 {
578  // always valid
579 }
580 
581 template <typename ALLOC>
582 BitSize bitSizeOf(const BasicBitBufferView<ALLOC>& bitBufferView, BitSize = 0)
583 {
584  const BasicBitBuffer<ALLOC>& bitBuffer = bitBufferView.get();
585  const VarSize bitBufferSize = fromCheckedValue<VarSize>(convertSizeToUInt32(bitBuffer.getBitSize()));
586 
587  // bit buffer consists of varsize for bit size followed by the bits
588  return bitSizeOf(bitBufferSize) + bitBufferSize;
589 }
590 
591 template <typename ALLOC>
592 BitSize initializeOffsets(const BasicBitBufferView<ALLOC>& bitBufferView, BitSize bitPosition)
593 {
594  return bitSizeof(bitBufferView, bitPosition);
595 }
596 
597 } // namespace detail
598 
599 } // namespace zserio
600 
601 namespace std
602 {
603 
607 template <typename ALLOC>
608 struct hash<zserio::BasicBitBuffer<ALLOC>>
609 {
610  size_t operator()(const zserio::BasicBitBuffer<ALLOC>& bitBuffer) const
611  {
612  return static_cast<size_t>(bitBuffer.hashCode());
613  }
614 };
615 
619 template <typename ALLOC>
620 struct hash<zserio::BasicBitBufferView<ALLOC>>
621 {
622  size_t operator()(const zserio::BasicBitBufferView<ALLOC>& bitBuffer) const
623  {
624  return static_cast<size_t>(bitBuffer.get().hashCode());
625  }
626 };
627 
628 } // namespace std
629 
630 #endif // ifndef ZSERIO_BIT_BUFFER_H_INC
size_t getByteSize() const
Definition: BitBuffer.h:453
BasicBitBuffer(const BasicBitBuffer &other, const ALLOC &allocator)
Definition: BitBuffer.h:324
ALLOC get_allocator() const
Definition: BitBuffer.h:48
bool operator<=(const BasicBitBuffer &other) const
Definition: BitBuffer.h:185
BasicBitBuffer(std::vector< uint8_t, ALLOC > &&buffer)
Definition: BitBuffer.h:305
BasicBitBuffer(Span< const uint8_t > buffer, const ALLOC &allocator={})
Definition: BitBuffer.h:286
BasicBitBuffer & operator=(BasicBitBuffer &&)=default
bool operator>(const BasicBitBuffer &other) const
Definition: BitBuffer.h:173
BasicBitBuffer(BasicBitBuffer &&)=default
BasicBitBuffer(const BasicBitBuffer &)=default
Span< const uint8_t > getData() const
Definition: BitBuffer.h:465
size_t getBitSize() const
Definition: BitBuffer.h:447
uint32_t hashCode() const
Definition: BitBuffer.h:414
BasicBitBuffer(size_t bitSize, const ALLOC &allocator={})
Definition: BitBuffer.h:280
BasicBitBuffer(std::vector< uint8_t, ALLOC > &&buffer, size_t bitSize)
Definition: BitBuffer.h:311
bool operator>=(const BasicBitBuffer &other) const
Definition: BitBuffer.h:197
bool operator==(const BasicBitBuffer &other) const
Definition: BitBuffer.h:336
bool operator<(const BasicBitBuffer &other) const
Definition: BitBuffer.h:367
BasicBitBuffer & operator=(const BasicBitBuffer &)=default
uint8_t * getBuffer()
Definition: BitBuffer.h:441
const std::vector< uint8_t, ALLOC > & getBytes() const
Definition: BitBuffer.h:459
Span< uint8_t > getData()
Definition: BitBuffer.h:471
const uint8_t * getBuffer() const
Definition: BitBuffer.h:435
BasicBitBuffer(const ALLOC &allocator)
Definition: BitBuffer.h:274
BasicBitBuffer(Span< const uint8_t > buffer, size_t bitSize, const ALLOC &allocator={})
Definition: BitBuffer.h:292
bool operator!=(const BasicBitBuffer &other) const
Definition: BitBuffer.h:152
BasicBitBuffer(BasicBitBuffer &&other, const ALLOC &allocator)
Definition: BitBuffer.h:330
constexpr size_type size() const noexcept
Definition: Span.h:281
Definition: BitBuffer.h:602
bool operator>(const BasicBitBufferView< ALLOC > &lhs, const BasicBitBufferView< ALLOC > &rhs)
Definition: BitBuffer.h:525
bool operator==(const BasicBitBufferView< ALLOC > &lhs, const BasicBitBufferView< ALLOC > &rhs)
Definition: BitBuffer.h:507
unsigned int BitSize
Definition: BitSize.h:8
std::reference_wrapper< const BitBuffer > BitBufferView
Definition: BitBuffer.h:495
bool operator<(const BasicBitBufferView< ALLOC > &lhs, const BasicBitBufferView< ALLOC > &rhs)
Definition: BitBuffer.h:519
uint32_t calcHashCode(uint32_t seedValue, const ArrayView< T, ARRAY_TRAITS > &array)
Definition: ArrayView.h:860
CppRuntimeException & operator<<(CppRuntimeException &exception, const BasicBitBuffer< ALLOC > &bitBuffer)
Definition: BitBuffer.h:553
uint32_t convertSizeToUInt32(size_t value)
bool operator<=(const BasicBitBufferView< ALLOC > &lhs, const BasicBitBufferView< ALLOC > &rhs)
Definition: BitBuffer.h:531
bool operator>=(const BasicBitBufferView< ALLOC > &lhs, const BasicBitBufferView< ALLOC > &rhs)
Definition: BitBuffer.h:537
std::reference_wrapper< const BasicBitBuffer< ALLOC > > BasicBitBufferView
Definition: BitBuffer.h:492
bool operator!=(const BasicBitBufferView< ALLOC > &lhs, const BasicBitBufferView< ALLOC > &rhs)
Definition: BitBuffer.h:513
detail::VarIntWrapper< uint32_t, detail::VarIntType::VARSIZE > VarSize
Definition: Types.h:890
size_t operator()(const zserio::BasicBitBufferView< ALLOC > &bitBuffer) const
Definition: BitBuffer.h:622
size_t operator()(const zserio::BasicBitBuffer< ALLOC > &bitBuffer) const
Definition: BitBuffer.h:610
BasicBitBufferView< ALLOC > type
Definition: BitBuffer.h:500