Zserio C++ runtime library  1.3.0
Built for Zserio 2.18.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 <cstring>
5 #include <type_traits>
6 #include <vector>
7 
9 #include "zserio/HashCodeUtil.h"
10 #include "zserio/Span.h"
11 #include "zserio/Types.h"
12 #include "zserio/Vector.h"
13 
14 namespace zserio
15 {
16 
21 struct BitsTag
22 {};
23 
30 template <typename ALLOC = std::allocator<uint8_t>>
32 {
33 public:
34  static_assert(std::is_same<uint8_t, typename ALLOC::value_type>::value,
35  "Allocator with uint8_t value_type is required!");
36 
37  using allocator_type = ALLOC;
38 
45  {
46  return m_buffer.get_allocator();
47  }
48 
55 
61  explicit BasicBitBuffer(const ALLOC& allocator);
62 
69  explicit BasicBitBuffer(size_t bitSize, const ALLOC& allocator = ALLOC());
70 
77  explicit BasicBitBuffer(Span<const uint8_t> buffer, const ALLOC& allocator = ALLOC());
78 
88  explicit BasicBitBuffer(Span<const uint8_t> buffer, size_t bitSize, const ALLOC& allocator = ALLOC());
89 
96 
105  explicit BasicBitBuffer(vector<uint8_t, ALLOC>&& buffer, size_t bitSize);
106 
114  explicit BasicBitBuffer(const uint8_t* buffer, size_t bitSize, const ALLOC& allocator = ALLOC());
115 
120  ~BasicBitBuffer() = default;
121 
123  BasicBitBuffer(const BasicBitBuffer<ALLOC>& other, const ALLOC& allocator);
125 
127  BasicBitBuffer(const BasicBitBuffer<ALLOC>&& other, const ALLOC& allocator);
140  bool operator==(const BasicBitBuffer<ALLOC>& other) const;
141 
149  bool operator<(const BasicBitBuffer<ALLOC>& other) const;
150 
156  uint32_t hashCode() const;
157 
163  const uint8_t* getBuffer() const;
164 
170  uint8_t* getBuffer();
171 
177  size_t getBitSize() const;
178 
186  size_t getByteSize() const;
187 
194 
201 
208 
209 private:
210  uint8_t getMaskedLastByte() const;
211 
212  vector<uint8_t, ALLOC> m_buffer;
213  size_t m_bitSize;
214 };
215 
216 template <typename ALLOC>
218  m_buffer(ALLOC()),
219  m_bitSize(0)
220 {}
221 
222 template <typename ALLOC>
223 BasicBitBuffer<ALLOC>::BasicBitBuffer(const ALLOC& allocator) :
224  m_buffer(allocator),
225  m_bitSize(0)
226 {}
227 
228 template <typename ALLOC>
229 BasicBitBuffer<ALLOC>::BasicBitBuffer(size_t bitSize, const ALLOC& allocator) :
230  m_buffer((bitSize + 7) / 8, 0, allocator),
231  m_bitSize(bitSize)
232 {}
233 
234 template <typename ALLOC>
236  m_buffer(buffer.begin(), buffer.end(), allocator),
237  m_bitSize(8 * buffer.size())
238 {}
239 
240 template <typename ALLOC>
241 BasicBitBuffer<ALLOC>::BasicBitBuffer(Span<const uint8_t> buffer, size_t bitSize, const ALLOC& allocator) :
242  m_buffer(buffer.begin(), buffer.end(), allocator),
243  m_bitSize(bitSize)
244 {
245  const size_t byteSize = (bitSize + 7) / 8;
246  if (buffer.size() < byteSize)
247  {
248  throw CppRuntimeException("BitBuffer: Bit size ")
249  << bitSize << " out of range for given span byte size " << buffer.size() << "!";
250  }
251 }
252 
253 template <typename ALLOC>
255  m_buffer(std::move(buffer)),
256  m_bitSize(8 * m_buffer.size())
257 {}
258 
259 template <typename ALLOC>
261  m_buffer(std::move(buffer)),
262  m_bitSize(bitSize)
263 {
264  const size_t byteSize = (bitSize + 7) / 8;
265  if (m_buffer.size() < byteSize)
266  {
267  throw CppRuntimeException("BitBuffer: Bit size ")
268  << bitSize << " out of range for given vector byte size " << m_buffer.size() << "!";
269  }
270 }
271 
272 template <typename ALLOC>
273 BasicBitBuffer<ALLOC>::BasicBitBuffer(const uint8_t* buffer, size_t bitSize, const ALLOC& allocator) :
274  m_buffer(buffer, buffer + (bitSize + 7) / 8, allocator),
275  m_bitSize(bitSize)
276 {}
277 
278 template <typename ALLOC>
279 inline BasicBitBuffer<ALLOC>::BasicBitBuffer(const BasicBitBuffer<ALLOC>& other, const ALLOC& allocator) :
280  m_buffer(other.m_buffer, allocator),
281  m_bitSize(other.m_bitSize)
282 {}
283 
284 template <typename ALLOC>
285 inline BasicBitBuffer<ALLOC>::BasicBitBuffer(const BasicBitBuffer<ALLOC>&& other, const ALLOC& allocator) :
286  m_buffer(std::move(other.m_buffer), allocator),
287  m_bitSize(other.m_bitSize)
288 {}
289 
290 template <typename ALLOC>
292 {
293  if (this != &other)
294  {
295  if (m_bitSize != other.m_bitSize)
296  {
297  return false;
298  }
299 
300  const size_t byteSize = getByteSize();
301  if (byteSize > 0)
302  {
303  if (byteSize > 1)
304  {
305  if (memcmp(getBuffer(), other.getBuffer(), byteSize - 1) != 0)
306  {
307  return false;
308  }
309  }
310 
311  if (getMaskedLastByte() != other.getMaskedLastByte())
312  {
313  return false;
314  }
315  }
316  }
317 
318  return true;
319 }
320 
321 template <typename ALLOC>
323 {
324  const size_t byteSize1 = getByteSize();
325  const size_t byteSize2 = other.getByteSize();
326 
327  if (byteSize1 == 0)
328  {
329  return byteSize2 != 0;
330  }
331  if (byteSize2 == 0)
332  {
333  return false;
334  }
335 
336  using difference_type = typename vector<uint8_t, ALLOC>::iterator::difference_type;
337 
338  auto first1 = m_buffer.begin();
339  const auto last1 = first1 + static_cast<difference_type>(byteSize1 - 1);
340  auto first2 = other.m_buffer.begin();
341  const auto last2 = first2 + static_cast<difference_type>(byteSize2 - 1);
342  for (; (first1 != last1) && (first2 != last2); ++first1, ++first2)
343  {
344  if (*first1 < *first2)
345  {
346  return true;
347  }
348  if (*first2 < *first1)
349  {
350  return false;
351  }
352  }
353 
354  const auto lastValue1 = first1 != last1 ? *first1 : getMaskedLastByte();
355  const auto lastValue2 = first2 != last2 ? *first2 : other.getMaskedLastByte();
356  if (lastValue1 < lastValue2)
357  {
358  return true;
359  }
360  if (lastValue2 < lastValue1)
361  {
362  return false;
363  }
364 
365  return (first1 == last1) && (first2 != last2);
366 }
367 
368 template <typename ALLOC>
370 {
371  uint32_t result = ::zserio::HASH_SEED;
372  const size_t byteSize = getByteSize();
373  if (byteSize > 0)
374  {
375  if (byteSize > 1)
376  {
377  auto lastIt = m_buffer.begin() + static_cast<int>(byteSize) - 1;
378  for (auto it = m_buffer.begin(); it != lastIt; ++it)
379  {
380  result = calcHashCode(result, *it);
381  }
382  }
383  result = ::zserio::calcHashCode(result, getMaskedLastByte());
384  }
385 
386  return result;
387 }
388 
389 template <typename ALLOC>
390 const uint8_t* BasicBitBuffer<ALLOC>::getBuffer() const
391 {
392  return m_buffer.data();
393 }
394 
395 template <typename ALLOC>
397 {
398  return m_buffer.data();
399 }
400 
401 template <typename ALLOC>
403 {
404  return m_bitSize;
405 }
406 
407 template <typename ALLOC>
409 {
410  return (m_bitSize + 7) / 8;
411 }
412 
413 template <typename ALLOC>
415 {
416  return m_buffer;
417 }
418 
419 template <typename ALLOC>
421 {
422  return Span<const uint8_t>(m_buffer);
423 }
424 
425 template <typename ALLOC>
427 {
428  return Span<uint8_t>(m_buffer);
429 }
430 
431 template <typename ALLOC>
433 {
434  const size_t roundedByteSize = m_bitSize / 8;
435  const uint8_t lastByteBits = static_cast<uint8_t>(m_bitSize - 8 * roundedByteSize);
436 
437  return (lastByteBits == 0)
438  ? m_buffer[roundedByteSize - 1]
439  : static_cast<uint8_t>(m_buffer[roundedByteSize] & (0xFFU << (8U - lastByteBits)));
440 }
441 
444 
453 template <typename ALLOC>
455 {
456  return exception << "BitBuffer([...], " << bitBuffer.getBitSize() << ")";
457 }
458 
459 } // namespace zserio
460 
461 #endif // ifndef ZSERIO_BIT_BUFFER_H_INC
BasicBitBuffer(vector< uint8_t, ALLOC > &&buffer)
Definition: BitBuffer.h:254
size_t getByteSize() const
Definition: BitBuffer.h:408
BasicBitBuffer(const BasicBitBuffer< ALLOC > &other, const ALLOC &allocator)
Definition: BitBuffer.h:279
BasicBitBuffer & operator=(const BasicBitBuffer< ALLOC > &)=default
BasicBitBuffer(vector< uint8_t, ALLOC > &&buffer, size_t bitSize)
Definition: BitBuffer.h:260
allocator_type get_allocator() const
Definition: BitBuffer.h:44
BasicBitBuffer(const uint8_t *buffer, size_t bitSize, const ALLOC &allocator=ALLOC())
Definition: BitBuffer.h:273
BasicBitBuffer(const BasicBitBuffer< ALLOC > &)=default
Span< const uint8_t > getData() const
Definition: BitBuffer.h:420
size_t getBitSize() const
Definition: BitBuffer.h:402
uint32_t hashCode() const
Definition: BitBuffer.h:369
BasicBitBuffer & operator=(BasicBitBuffer< ALLOC > &&)=default
BasicBitBuffer(BasicBitBuffer< ALLOC > &&)=default
BasicBitBuffer(size_t bitSize, const ALLOC &allocator=ALLOC())
Definition: BitBuffer.h:229
uint8_t * getBuffer()
Definition: BitBuffer.h:396
BasicBitBuffer(Span< const uint8_t > buffer, const ALLOC &allocator=ALLOC())
Definition: BitBuffer.h:235
Span< uint8_t > getData()
Definition: BitBuffer.h:426
const uint8_t * getBuffer() const
Definition: BitBuffer.h:390
bool operator<(const BasicBitBuffer< ALLOC > &other) const
Definition: BitBuffer.h:322
BasicBitBuffer(Span< const uint8_t > buffer, size_t bitSize, const ALLOC &allocator=ALLOC())
Definition: BitBuffer.h:241
BasicBitBuffer(const ALLOC &allocator)
Definition: BitBuffer.h:223
BasicBitBuffer(const BasicBitBuffer< ALLOC > &&other, const ALLOC &allocator)
Definition: BitBuffer.h:285
bool operator==(const BasicBitBuffer< ALLOC > &other) const
Definition: BitBuffer.h:291
const vector< uint8_t, ALLOC > & getBytes() const
Definition: BitBuffer.h:414
constexpr size_type size() const noexcept
Definition: Span.h:283
std::vector< T, RebindAlloc< ALLOC, T > > vector
Definition: Vector.h:17
CppRuntimeException & operator<<(CppRuntimeException &exception, const BasicBitBuffer< ALLOC > &bitBuffer)
Definition: BitBuffer.h:454
std::enable_if< std::is_integral< T >::value &&(sizeof(T)<=4), uint32_t >::type calcHashCode(uint32_t seedValue, T value)
Definition: HashCodeUtil.h:43