Zserio C++ runtime library  1.0.1
Built for Zserio 2.14.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  return false;
298 
299  const size_t byteSize = getByteSize();
300  if (byteSize > 0)
301  {
302  if (byteSize > 1)
303  {
304  if (memcmp(getBuffer(), other.getBuffer(), byteSize - 1) != 0)
305  return false;
306  }
307 
308  if (getMaskedLastByte() != other.getMaskedLastByte())
309  return false;
310  }
311  }
312 
313  return true;
314 }
315 
316 template <typename ALLOC>
318 {
319  const size_t byteSize1 = getByteSize();
320  const size_t byteSize2 = other.getByteSize();
321 
322  if (byteSize1 == 0)
323  return byteSize2 != 0;
324  if (byteSize2 == 0)
325  return false;
326 
327  using difference_type = typename vector<uint8_t, ALLOC>::iterator::difference_type;
328 
329  auto first1 = m_buffer.begin();
330  const auto last1 = first1 + static_cast<difference_type>(byteSize1 - 1);
331  auto first2 = other.m_buffer.begin();
332  const auto last2 = first2 + static_cast<difference_type>(byteSize2 - 1);
333  for (; (first1 != last1) && (first2 != last2); ++first1, ++first2)
334  {
335  if (*first1 < *first2)
336  return true;
337  if (*first2 < *first1)
338  return false;
339  }
340 
341  const auto lastValue1 = first1 != last1 ? *first1 : getMaskedLastByte();
342  const auto lastValue2 = first2 != last2 ? *first2 : other.getMaskedLastByte();
343  if (lastValue1 < lastValue2)
344  return true;
345  if (lastValue2 < lastValue1)
346  return false;
347 
348  return (first1 == last1) && (first2 != last2);
349 }
350 
351 template <typename ALLOC>
353 {
354  uint32_t result = ::zserio::HASH_SEED;
355  const size_t byteSize = getByteSize();
356  if (byteSize > 0)
357  {
358  if (byteSize > 1)
359  {
360  auto lastIt = m_buffer.begin() + static_cast<int>(byteSize) - 1;
361  for (auto it = m_buffer.begin(); it != lastIt; ++it)
362  result = calcHashCode(result, *it);
363  }
364  result = ::zserio::calcHashCode(result, getMaskedLastByte());
365  }
366 
367  return result;
368 }
369 
370 template <typename ALLOC>
371 const uint8_t* BasicBitBuffer<ALLOC>::getBuffer() const
372 {
373  return m_buffer.data();
374 }
375 
376 template <typename ALLOC>
378 {
379  return m_buffer.data();
380 }
381 
382 template <typename ALLOC>
384 {
385  return m_bitSize;
386 }
387 
388 template <typename ALLOC>
390 {
391  return (m_bitSize + 7) / 8;
392 }
393 
394 template <typename ALLOC>
396 {
397  return m_buffer;
398 }
399 
400 template <typename ALLOC>
402 {
403  return Span<const uint8_t>(m_buffer);
404 }
405 
406 template <typename ALLOC>
408 {
409  return Span<uint8_t>(m_buffer);
410 }
411 
412 template <typename ALLOC>
414 {
415  const size_t roundedByteSize = m_bitSize / 8;
416  const uint8_t lastByteBits = static_cast<uint8_t>(m_bitSize - 8 * roundedByteSize);
417 
418  return (lastByteBits == 0)
419  ? m_buffer[roundedByteSize - 1]
420  : static_cast<uint8_t>(m_buffer[roundedByteSize] & (0xFFU << (8U - lastByteBits)));
421 }
422 
425 
434 template <typename ALLOC>
436 {
437  return exception << "BitBuffer([...], " << bitBuffer.getBitSize() << ")";
438 }
439 
440 } // namespace zserio
441 
442 #endif // ifndef ZSERIO_BIT_BUFFER_H_INC
BasicBitBuffer(vector< uint8_t, ALLOC > &&buffer)
Definition: BitBuffer.h:255
size_t getByteSize() const
Definition: BitBuffer.h:389
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:401
size_t getBitSize() const
Definition: BitBuffer.h:383
uint32_t hashCode() const
Definition: BitBuffer.h:352
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:377
BasicBitBuffer(Span< const uint8_t > buffer, const ALLOC &allocator=ALLOC())
Definition: BitBuffer.h:236
Span< uint8_t > getData()
Definition: BitBuffer.h:407
const uint8_t * getBuffer() const
Definition: BitBuffer.h:371
bool operator<(const BasicBitBuffer< ALLOC > &other) const
Definition: BitBuffer.h:317
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:395
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:435
std::enable_if< std::is_integral< T >::value &&(sizeof(T)<=4), uint32_t >::type calcHashCode(uint32_t seedValue, T value)
Definition: HashCodeUtil.h:43