Zserio C++17 runtime library  0.5.0
Built for Zserio 2.17.0
DeltaContext.h
Go to the documentation of this file.
1 #ifndef ZSERIO_DELTA_CONTEXT_H_INC
2 #define ZSERIO_DELTA_CONTEXT_H_INC
3 
4 #include <cstdint>
5 #include <type_traits>
6 
9 #include "zserio/Traits.h"
10 #include "zserio/View.h"
11 
12 namespace zserio
13 {
14 
15 namespace detail
16 {
17 
18 // calculates bit length on delta provided as an absolute number
19 inline uint8_t absDeltaBitLength(uint64_t absDelta)
20 {
21  uint8_t result = 0;
22  while (absDelta > 0)
23  {
24  result++;
25  absDelta >>= 1U;
26  }
27 
28  return result;
29 }
30 
31 // calculates bit length, emulates Python bit_length to keep same logic
32 template <typename T>
33 uint8_t calcBitLength(T lhs, T rhs)
34 {
35  const uint64_t absDelta = lhs > rhs
36  ? static_cast<uint64_t>(lhs) - static_cast<uint64_t>(rhs)
37  : static_cast<uint64_t>(rhs) - static_cast<uint64_t>(lhs);
38 
39  return absDeltaBitLength(absDelta);
40 }
41 
42 // calculates delta, doesn't check for possible int64_t overflow since it's used only in cases where it's
43 // already known that overflow cannot occur
44 template <typename T>
45 int64_t calcUncheckedDelta(T lhs, uint64_t rhs)
46 {
47  return static_cast<int64_t>(static_cast<uint64_t>(lhs) - rhs);
48 }
49 
58 class DeltaContext
59 {
60 public:
65  DeltaContext() = default;
66  ~DeltaContext() = default;
67 
68  DeltaContext(DeltaContext&& other) = default;
69  DeltaContext& operator=(DeltaContext&& other) = default;
70  DeltaContext(const DeltaContext& other) = default;
71  DeltaContext& operator=(const DeltaContext& other) = default;
81  template <typename T>
82  void init(T element)
83  {
84  m_numElements++;
85  m_unpackedBitSize += detail::bitSizeOf(element);
86 
87  if (!isFlagSet(INIT_STARTED_FLAG))
88  {
89  setFlag(INIT_STARTED_FLAG);
90  m_previousElement = static_cast<uint64_t>(element);
91  m_firstElementBitSize = static_cast<uint8_t>(m_unpackedBitSize);
92  }
93  else
94  {
95  if (m_maxBitNumber <= MAX_BIT_NUMBER_LIMIT)
96  {
97  setFlag(IS_PACKED_FLAG);
98  const auto previousElement = static_cast<typename T::ValueType>(m_previousElement);
99  const uint8_t maxBitNumber =
100  detail::calcBitLength(static_cast<typename T::ValueType>(element), previousElement);
101  if (maxBitNumber > m_maxBitNumber)
102  {
103  m_maxBitNumber = maxBitNumber;
104  if (m_maxBitNumber > MAX_BIT_NUMBER_LIMIT)
105  {
106  resetFlag(IS_PACKED_FLAG);
107  }
108  }
109  m_previousElement = static_cast<uint64_t>(element);
110  }
111  }
112  }
113 
121  template <typename T>
122  BitSize bitSizeOf(T element)
123  {
124  if (!isFlagSet(PROCESSING_STARTED_FLAG))
125  {
126  setFlag(PROCESSING_STARTED_FLAG);
127  finishInit();
128 
129  return bitSizeOfDescriptor() + detail::bitSizeOf(element);
130  }
131  else if (!isFlagSet(IS_PACKED_FLAG))
132  {
133  return detail::bitSizeOf(element);
134  }
135  else
136  {
137  return static_cast<BitSize>(m_maxBitNumber + (m_maxBitNumber > 0 ? 1 : 0));
138  }
139  }
140 
148  template <typename T, typename... ARGS>
149  void read(BitStreamReader& reader, T& element, ARGS&&... args)
150  {
151  if (!isFlagSet(PROCESSING_STARTED_FLAG))
152  {
153  setFlag(PROCESSING_STARTED_FLAG);
154  readDescriptor(reader);
155 
156  readUnpacked(reader, element, std::forward<ARGS>(args)...);
157  }
158  else if (!isFlagSet(IS_PACKED_FLAG))
159  {
160  readUnpacked(reader, element, std::forward<ARGS>(args)...);
161  }
162  else
163  {
164  if (m_maxBitNumber > 0)
165  {
166  const int64_t delta = reader.readSignedBits64(m_maxBitNumber + 1);
167  const T readElement =
168  static_cast<typename T::ValueType>(m_previousElement + static_cast<uint64_t>(delta));
169  m_previousElement = static_cast<uint64_t>(readElement);
170  }
171 
172  element = static_cast<typename T::ValueType>(m_previousElement);
173  }
174  }
175 
182  template <typename T>
183  void write(BitStreamWriter& writer, T element)
184  {
185  if (!isFlagSet(PROCESSING_STARTED_FLAG))
186  {
187  setFlag(PROCESSING_STARTED_FLAG);
188  finishInit();
189  writeDescriptor(writer);
190 
191  writeUnpacked(writer, element);
192  }
193  else if (!isFlagSet(IS_PACKED_FLAG))
194  {
195  writeUnpacked(writer, element);
196  }
197  else
198  {
199  if (m_maxBitNumber > 0)
200  {
201  // it's already checked in the init phase that the delta will fit into int64_t
202  const int64_t delta = detail::calcUncheckedDelta(
203  static_cast<typename T::ValueType>(element), m_previousElement);
204  writer.writeSignedBits64(delta, m_maxBitNumber + 1);
205  m_previousElement = static_cast<uint64_t>(element);
206  }
207  }
208  }
209 
210 private:
211  void finishInit()
212  {
213  if (isFlagSet(IS_PACKED_FLAG))
214  {
215  const BitSize deltaBitSize = static_cast<BitSize>(m_maxBitNumber + (m_maxBitNumber > 0 ? 1 : 0));
216  const BitSize packedBitSizeWithDescriptor = 1 + MAX_BIT_NUMBER_BITS + // descriptor
217  m_firstElementBitSize + (m_numElements - 1) * deltaBitSize;
218  const BitSize unpackedBitSizeWithDescriptor = static_cast<BitSize>(1 + m_unpackedBitSize);
219  if (packedBitSizeWithDescriptor >= unpackedBitSizeWithDescriptor)
220  {
221  resetFlag(IS_PACKED_FLAG);
222  }
223  }
224  }
225 
226  BitSize bitSizeOfDescriptor() const
227  {
228  if (isFlagSet(IS_PACKED_FLAG))
229  {
230  return 1 + MAX_BIT_NUMBER_BITS;
231  }
232  else
233  {
234  return 1;
235  }
236  }
237 
238  void readDescriptor(BitStreamReader& in)
239  {
240  if (in.readBool())
241  {
242  setFlag(IS_PACKED_FLAG);
243  m_maxBitNumber = static_cast<uint8_t>(in.readUnsignedBits32(MAX_BIT_NUMBER_BITS));
244  }
245  else
246  {
247  resetFlag(IS_PACKED_FLAG);
248  }
249  }
250 
251  template <typename T, typename... ARGS>
252  void readUnpacked(BitStreamReader& reader, T& element, ARGS&&... args)
253  {
254  detail::read(reader, element, std::forward<ARGS>(args)...);
255  m_previousElement = static_cast<uint64_t>(element);
256  }
257 
258  void writeDescriptor(BitStreamWriter& writer) const
259  {
260  const bool isPacked = isFlagSet(IS_PACKED_FLAG);
261  writer.writeBool(isPacked);
262  if (isPacked)
263  {
264  writer.writeUnsignedBits32(m_maxBitNumber, MAX_BIT_NUMBER_BITS);
265  }
266  }
267 
268  template <typename T>
269  void writeUnpacked(BitStreamWriter& writer, T element)
270  {
271  m_previousElement = static_cast<uint64_t>(element);
272  detail::write(writer, element);
273  }
274 
275  void setFlag(uint8_t flagMask)
276  {
277  m_flags |= flagMask;
278  }
279 
280  void resetFlag(uint8_t flagMask)
281  {
282  m_flags &= static_cast<uint8_t>(~flagMask);
283  }
284 
285  bool isFlagSet(uint8_t flagMask) const
286  {
287  return ((m_flags & flagMask) != 0);
288  }
289 
290  static const uint8_t MAX_BIT_NUMBER_BITS = 6;
291  static const uint8_t MAX_BIT_NUMBER_LIMIT = 62;
292 
293  static const uint8_t INIT_STARTED_FLAG = 0x01;
294  static const uint8_t IS_PACKED_FLAG = 0x02;
295  static const uint8_t PROCESSING_STARTED_FLAG = 0x04;
296 
297  uint64_t m_previousElement = 0;
298  uint8_t m_maxBitNumber = 0;
299  uint8_t m_flags = 0x00;
300 
301  uint8_t m_firstElementBitSize = 0;
302  uint32_t m_numElements = 0;
303  size_t m_unpackedBitSize = 0;
304 };
305 
306 // helper trait to choose packing context type for an array from an element type T
307 template <typename T, typename = void>
308 struct packing_context_type
309 {
310  using type = DeltaContext;
311 };
312 
313 template <typename T>
314 struct packing_context_type<T,
315  std::enable_if_t<is_complete_v<typename ObjectTraits<std::decay_t<T>>::PackingContext>>>
316 {
317  using type = typename ObjectTraits<T>::PackingContext;
318 };
319 
320 template <typename T, typename V = void>
321 using packing_context_type_t = typename packing_context_type<T, V>::type;
322 
323 template <typename T>
324 void initContext(typename ObjectTraits<T>::PackingContext& packingContext, const View<T>& view)
325 {
326  ObjectTraits<T>::initContext(packingContext, view);
327 }
328 
329 template <typename T>
330 BitSize bitSizeOf(
331  typename ObjectTraits<T>::PackingContext& packingContext, const View<T>& view, BitSize bitPosition)
332 {
333  return ObjectTraits<T>::bitSizeOf(packingContext, view, bitPosition);
334 }
335 
336 template <typename T>
337 BitSize initializeOffsets(
338  typename ObjectTraits<T>::PackingContext& packingContext, const View<T>& view, BitSize bitPosition)
339 {
340  if constexpr (has_initialize_offsets_v<T>)
341  {
342  return ObjectTraits<T>::initializeOffsets(packingContext, view, bitPosition);
343  }
344  else
345  {
346  return ObjectTraits<T>::bitSizeOf(packingContext, view, bitPosition);
347  }
348 }
349 
350 template <typename T>
351 void write(
352  typename ObjectTraits<T>::PackingContext& packingContext, BitStreamWriter& writer, const View<T>& view)
353 {
354  ObjectTraits<T>::write(packingContext, writer, view);
355 }
356 
357 template <typename T, typename... ARGS>
358 void read(typename ObjectTraits<T>::PackingContext& packingContext, BitStreamReader& reader, T& data,
359  ARGS&&... args)
360 {
361  ObjectTraits<T>::read(packingContext, reader, data, std::forward<ARGS>(args)...);
362 }
363 
364 inline void initContext(DeltaContext& deltaContext, Bool value)
365 {
366  deltaContext.init(value);
367 }
368 
369 inline BitSize bitSizeOf(DeltaContext& deltaContext, Bool value, BitSize = 0)
370 {
371  return deltaContext.bitSizeOf(value);
372 }
373 
374 inline void write(DeltaContext& deltaContext, BitStreamWriter& writer, Bool value)
375 {
376  deltaContext.write(writer, value);
377 }
378 
379 inline void read(DeltaContext& deltaContext, BitStreamReader& reader, Bool& value)
380 {
381  deltaContext.read(reader, value);
382 }
383 
384 template <BitSize BIT_SIZE, bool IS_SIGNED>
385 void initContext(DeltaContext& deltaContext, FixedIntWrapper<BIT_SIZE, IS_SIGNED> value)
386 {
387  deltaContext.init(value);
388 }
389 
390 template <BitSize BIT_SIZE, bool IS_SIGNED>
391 BitSize bitSizeOf(DeltaContext& deltaContext, FixedIntWrapper<BIT_SIZE, IS_SIGNED> value, BitSize = 0)
392 {
393  return deltaContext.bitSizeOf(value);
394 }
395 
396 template <BitSize BIT_SIZE, bool IS_SIGNED>
397 void write(DeltaContext& deltaContext, BitStreamWriter& writer, FixedIntWrapper<BIT_SIZE, IS_SIGNED> value)
398 {
399  deltaContext.write(writer, value);
400 }
401 
402 template <BitSize BIT_SIZE, bool IS_SIGNED>
403 void read(DeltaContext& deltaContext, BitStreamReader& reader, FixedIntWrapper<BIT_SIZE, IS_SIGNED>& value)
404 {
405  deltaContext.read(reader, value);
406 }
407 
408 template <typename T, VarIntType VAR_TYPE>
409 void initContext(DeltaContext& deltaContext, VarIntWrapper<T, VAR_TYPE> value)
410 {
411  deltaContext.init(value);
412 }
413 
414 template <typename T, VarIntType VAR_TYPE>
415 BitSize bitSizeOf(DeltaContext& deltaContext, VarIntWrapper<T, VAR_TYPE> value, BitSize = 0)
416 {
417  return deltaContext.bitSizeOf(value);
418 }
419 
420 template <typename T, VarIntType VAR_TYPE>
421 void write(DeltaContext& deltaContext, BitStreamWriter& writer, VarIntWrapper<T, VAR_TYPE> value)
422 {
423  deltaContext.write(writer, value);
424 }
425 
426 template <typename T, VarIntType VAR_TYPE>
427 void read(DeltaContext& deltaContext, BitStreamReader& reader, VarIntWrapper<T, VAR_TYPE>& value)
428 {
429  deltaContext.read(reader, value);
430 }
431 
432 template <typename T>
433 void initContext(DeltaContext& deltaContext, View<DynIntWrapper<T>> view)
434 {
435  deltaContext.init(view);
436 }
437 
438 template <typename T>
439 BitSize bitSizeOf(DeltaContext& deltaContext, View<DynIntWrapper<T>> view, BitSize = 0)
440 {
441  return deltaContext.bitSizeOf(view);
442 }
443 
444 template <typename T>
445 void write(DeltaContext& deltaContext, BitStreamWriter& writer, View<DynIntWrapper<T>> view)
446 {
447  deltaContext.write(writer, view);
448 }
449 
450 template <typename T>
451 void read(DeltaContext& deltaContext, BitStreamReader& reader, DynIntWrapper<T>& value, uint8_t bitSize)
452 {
453  deltaContext.read(reader, value, bitSize);
454 }
455 
456 // overloads for unpackable compounds
457 
458 template <typename T>
459 void initContext(DeltaContext&, const View<T>&)
460 {}
461 
462 template <typename T>
463 BitSize bitSizeOf(DeltaContext&, const View<T>& value, BitSize bitPosition)
464 {
465  return bitSizeOf(value, bitPosition);
466 }
467 
468 template <typename T>
469 void write(DeltaContext&, BitStreamWriter& writer, const View<T>& value)
470 {
471  write(writer, value);
472 }
473 
474 template <typename T, typename... ARGS, std::enable_if_t<is_complete_v<View<T>>, int> = 0>
475 void read(DeltaContext&, BitStreamReader& reader, T& value, ARGS&&... args)
476 {
477  read(reader, value, std::forward<ARGS>(args)...);
478 }
479 
480 // overloads for unpackable types
481 
482 template <typename VALUE_TYPE, FloatType FLOAT_TYPE>
483 void initContext(DeltaContext&, FloatWrapper<VALUE_TYPE, FLOAT_TYPE>)
484 {}
485 
486 template <typename VALUE_TYPE, FloatType FLOAT_TYPE>
487 BitSize bitSizeOf(DeltaContext&, FloatWrapper<VALUE_TYPE, FLOAT_TYPE> value, BitSize bitPosition)
488 {
489  return bitSizeOf(value, bitPosition);
490 }
491 
492 template <typename VALUE_TYPE, FloatType FLOAT_TYPE>
493 void write(DeltaContext&, BitStreamReader& writer, FloatWrapper<VALUE_TYPE, FLOAT_TYPE> value)
494 {
495  write(writer, value);
496 }
497 
498 template <typename VALUE_TYPE, FloatType FLOAT_TYPE>
499 void read(DeltaContext&, BitStreamReader& reader, FloatWrapper<VALUE_TYPE, FLOAT_TYPE>& value)
500 {
501  read(reader, value);
502 }
503 
504 inline void initContext(DeltaContext&, BytesView)
505 {}
506 
507 inline BitSize bitSizeOf(DeltaContext&, BytesView value, BitSize bitPosition)
508 {
509  return bitSizeOf(value, bitPosition);
510 }
511 
512 inline void write(DeltaContext&, BitStreamWriter& writer, BytesView value)
513 {
514  write(writer, value);
515 }
516 
517 template <typename ALLOC>
518 void read(DeltaContext&, BitStreamReader& reader, BasicBytes<ALLOC>& value)
519 {
520  read(reader, value);
521 }
522 
523 inline void initContext(DeltaContext&, std::string_view)
524 {}
525 
526 inline BitSize bitSizeOf(DeltaContext&, std::string_view value, BitSize bitPosition)
527 {
528  return bitSizeOf(value, bitPosition);
529 }
530 
531 inline void write(DeltaContext&, BitStreamWriter& writer, std::string_view value)
532 {
533  write(writer, value);
534 }
535 
536 template <typename ALLOC>
537 void read(DeltaContext&, BitStreamReader& reader, zserio::BasicString<ALLOC>& value)
538 {
539  read(reader, value);
540 }
541 
542 template <typename ALLOC>
543 void initContext(DeltaContext&, const BasicBitBufferView<ALLOC>&)
544 {}
545 
546 template <typename ALLOC>
547 BitSize bitSizeOf(DeltaContext&, const BasicBitBufferView<ALLOC>& value, BitSize bitPosition)
548 {
549  return bitSizeOf(value, bitPosition);
550 }
551 
552 template <typename ALLOC>
553 void write(DeltaContext&, BitStreamWriter& writer, const BasicBitBufferView<ALLOC>& value)
554 {
555  write(writer, value);
556 }
557 
558 template <typename ALLOC>
559 void read(DeltaContext&, BitStreamReader& reader, BasicBitBuffer<ALLOC>& value)
560 {
561  read(reader, value);
562 }
563 
564 } // namespace detail
565 
566 } // namespace zserio
567 
568 #endif // ZSERIO_DELTA_CONTEXT_H_INC
Definition: BitBuffer.h:602
Span< const uint8_t > BytesView
Definition: Bytes.h:30
detail::BoolWrapper Bool
Definition: Types.h:732
unsigned int BitSize
Definition: BitSize.h:8
std::basic_string< char, std::char_traits< char >, ALLOC > BasicString
Definition: String.h:17
View(T, ARGS &&...) -> View< T >