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