Zserio C++ runtime library  1.1.0
Built for Zserio 2.15.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 <type_traits>
5 
8 #include "zserio/RebindAlloc.h"
9 #include "zserio/Traits.h"
10 #include "zserio/Types.h"
11 #include "zserio/UniquePtr.h"
12 #include "zserio/Vector.h"
13 
14 namespace zserio
15 {
16 
17 namespace detail
18 {
19 
20 // calculates bit length on delta provided as an absolute number
21 inline uint8_t absDeltaBitLength(uint64_t absDelta)
22 {
23  uint8_t result = 0;
24  while (absDelta > 0)
25  {
26  result++;
27  absDelta >>= 1U;
28  }
29 
30  return result;
31 }
32 
33 // calculates bit length, emulates Python bit_length to keep same logic
34 template <typename T>
35 uint8_t calcBitLength(T lhs, T rhs)
36 {
37  const uint64_t absDelta = lhs > rhs
38  ? static_cast<uint64_t>(lhs) - static_cast<uint64_t>(rhs)
39  : static_cast<uint64_t>(rhs) - static_cast<uint64_t>(lhs);
40 
41  return absDeltaBitLength(absDelta);
42 }
43 
44 // calculates delta, doesn't check for possible int64_t overflow since it's used only in cases where it's
45 // already known that overflow cannot occur
46 template <typename T>
47 int64_t calcUncheckedDelta(T lhs, uint64_t rhs)
48 {
49  return static_cast<int64_t>(static_cast<uint64_t>(lhs) - rhs);
50 }
51 
52 } // namespace detail
53 
63 {
64 public:
69  DeltaContext() = default;
70  ~DeltaContext() = default;
71 
72  DeltaContext(DeltaContext&& other) = default;
73  DeltaContext& operator=(DeltaContext&& other) = default;
74  DeltaContext(const DeltaContext& other) = default;
75  DeltaContext& operator=(const DeltaContext& other) = default;
86  template <typename ARRAY_TRAITS, typename OWNER_TYPE>
87  void init(const OWNER_TYPE& owner, typename ARRAY_TRAITS::ElementType element)
88  {
89  m_numElements++;
90  m_unpackedBitSize += bitSizeOfUnpacked<ARRAY_TRAITS>(owner, element);
91 
92  if (!isFlagSet(INIT_STARTED_FLAG))
93  {
94  setFlag(INIT_STARTED_FLAG);
95  m_previousElement = static_cast<uint64_t>(element);
96  m_firstElementBitSize = static_cast<uint8_t>(m_unpackedBitSize);
97  }
98  else
99  {
100  if (m_maxBitNumber <= MAX_BIT_NUMBER_LIMIT)
101  {
102  setFlag(IS_PACKED_FLAG);
103  const auto previousElement = static_cast<typename ARRAY_TRAITS::ElementType>(m_previousElement);
104  const uint8_t maxBitNumber = detail::calcBitLength(element, previousElement);
105  if (maxBitNumber > m_maxBitNumber)
106  {
107  m_maxBitNumber = maxBitNumber;
108  if (m_maxBitNumber > MAX_BIT_NUMBER_LIMIT)
109  {
110  resetFlag(IS_PACKED_FLAG);
111  }
112  }
113  m_previousElement = static_cast<uint64_t>(element);
114  }
115  }
116  }
117 
126  template <typename ARRAY_TRAITS, typename OWNER_TYPE>
127  size_t bitSizeOf(const OWNER_TYPE& owner, typename ARRAY_TRAITS::ElementType element)
128  {
129  if (!isFlagSet(PROCESSING_STARTED_FLAG))
130  {
131  setFlag(PROCESSING_STARTED_FLAG);
132  finishInit();
133 
134  return bitSizeOfDescriptor() + bitSizeOfUnpacked<ARRAY_TRAITS>(owner, element);
135  }
136  else if (!isFlagSet(IS_PACKED_FLAG))
137  {
138  return bitSizeOfUnpacked<ARRAY_TRAITS>(owner, element);
139  }
140  else
141  {
142  return static_cast<size_t>(m_maxBitNumber) + (m_maxBitNumber > 0 ? 1 : 0);
143  }
144  }
145 
154  template <typename ARRAY_TRAITS, typename OWNER_TYPE>
155  typename ARRAY_TRAITS::ElementType read(const OWNER_TYPE& owner, BitStreamReader& in)
156  {
157  if (!isFlagSet(PROCESSING_STARTED_FLAG))
158  {
159  setFlag(PROCESSING_STARTED_FLAG);
160  readDescriptor(in);
161 
162  return readUnpacked<ARRAY_TRAITS>(owner, in);
163  }
164  else if (!isFlagSet(IS_PACKED_FLAG))
165  {
166  return readUnpacked<ARRAY_TRAITS>(owner, in);
167  }
168  else
169  {
170  if (m_maxBitNumber > 0)
171  {
172  const int64_t delta = in.readSignedBits64(static_cast<uint8_t>(m_maxBitNumber + 1));
173  const typename ARRAY_TRAITS::ElementType element =
174  static_cast<typename ARRAY_TRAITS::ElementType>(
175  m_previousElement + static_cast<uint64_t>(delta));
176  m_previousElement = static_cast<uint64_t>(element);
177  }
178 
179  return static_cast<typename ARRAY_TRAITS::ElementType>(m_previousElement);
180  }
181  }
182 
190  template <typename ARRAY_TRAITS, typename OWNER_TYPE>
191  void write(const OWNER_TYPE& owner, BitStreamWriter& out, typename ARRAY_TRAITS::ElementType element)
192  {
193  if (!isFlagSet(PROCESSING_STARTED_FLAG))
194  {
195  setFlag(PROCESSING_STARTED_FLAG);
196  finishInit();
197  writeDescriptor(out);
198 
199  writeUnpacked<ARRAY_TRAITS>(owner, out, element);
200  }
201  else if (!isFlagSet(IS_PACKED_FLAG))
202  {
203  writeUnpacked<ARRAY_TRAITS>(owner, out, element);
204  }
205  else
206  {
207  if (m_maxBitNumber > 0)
208  {
209  // it's already checked in the init phase that the delta will fit into int64_t
210  const int64_t delta = detail::calcUncheckedDelta(element, m_previousElement);
211  out.writeSignedBits64(delta, static_cast<uint8_t>(m_maxBitNumber + 1));
212  m_previousElement = static_cast<uint64_t>(element);
213  }
214  }
215  }
216 
217  // overloads with dummy owner
218 
224  template <typename ARRAY_TRAITS>
225  void init(typename ARRAY_TRAITS::ElementType element)
226  {
227  init<ARRAY_TRAITS>(DummyOwner(), element);
228  }
229 
237  template <typename ARRAY_TRAITS>
238  size_t bitSizeOf(typename ARRAY_TRAITS::ElementType element)
239  {
240  return bitSizeOf<ARRAY_TRAITS>(DummyOwner(), element);
241  }
242 
250  template <typename ARRAY_TRAITS>
251  typename ARRAY_TRAITS::ElementType read(BitStreamReader& in)
252  {
253  return read<ARRAY_TRAITS>(DummyOwner(), in);
254  }
255 
262  template <typename ARRAY_TRAITS>
263  void write(BitStreamWriter& out, typename ARRAY_TRAITS::ElementType element)
264  {
265  write<ARRAY_TRAITS>(DummyOwner(), out, element);
266  }
267 
268 private:
269  struct DummyOwner
270  {};
271 
272  void finishInit()
273  {
274  if (isFlagSet(IS_PACKED_FLAG))
275  {
276  const size_t deltaBitSize = static_cast<size_t>(m_maxBitNumber) + (m_maxBitNumber > 0 ? 1 : 0);
277  const size_t packedBitSizeWithDescriptor = 1U + MAX_BIT_NUMBER_BITS + // descriptor
278  m_firstElementBitSize + (m_numElements - 1) * deltaBitSize;
279  const size_t unpackedBitSizeWithDescriptor = 1 + m_unpackedBitSize;
280  if (packedBitSizeWithDescriptor >= unpackedBitSizeWithDescriptor)
281  {
282  resetFlag(IS_PACKED_FLAG);
283  }
284  }
285  }
286 
287  size_t bitSizeOfDescriptor() const
288  {
289  if (isFlagSet(IS_PACKED_FLAG))
290  {
291  return 1 + MAX_BIT_NUMBER_BITS;
292  }
293  else
294  {
295  return 1;
296  }
297  }
298 
299  template <typename ARRAY_TRAITS,
300  typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
301  static size_t bitSizeOfUnpacked(
302  const typename ARRAY_TRAITS::OwnerType& owner, typename ARRAY_TRAITS::ElementType element)
303  {
304  return ARRAY_TRAITS::bitSizeOf(owner, element);
305  }
306 
307  template <typename ARRAY_TRAITS,
308  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
309  static size_t bitSizeOfUnpacked(const DummyOwner&, typename ARRAY_TRAITS::ElementType element)
310  {
311  return ARRAY_TRAITS::bitSizeOf(element);
312  }
313 
314  void readDescriptor(BitStreamReader& in)
315  {
316  if (in.readBool())
317  {
318  setFlag(IS_PACKED_FLAG);
319  m_maxBitNumber = static_cast<uint8_t>(in.readBits(MAX_BIT_NUMBER_BITS));
320  }
321  else
322  {
323  resetFlag(IS_PACKED_FLAG);
324  }
325  }
326 
327  template <typename ARRAY_TRAITS,
328  typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
329  typename ARRAY_TRAITS::ElementType readUnpacked(
330  const typename ARRAY_TRAITS::OwnerType& owner, BitStreamReader& in)
331  {
332  const auto element = ARRAY_TRAITS::read(owner, in);
333  m_previousElement = static_cast<uint64_t>(element);
334  return element;
335  }
336 
337  template <typename ARRAY_TRAITS,
338  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
339  typename ARRAY_TRAITS::ElementType readUnpacked(const DummyOwner&, BitStreamReader& in)
340  {
341  const auto element = ARRAY_TRAITS::read(in);
342  m_previousElement = static_cast<uint64_t>(element);
343  return element;
344  }
345 
346  void writeDescriptor(BitStreamWriter& out) const
347  {
348  const bool isPacked = isFlagSet(IS_PACKED_FLAG);
349  out.writeBool(isPacked);
350  if (isPacked)
351  {
352  out.writeBits(m_maxBitNumber, MAX_BIT_NUMBER_BITS);
353  }
354  }
355 
356  template <typename ARRAY_TRAITS,
357  typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
358  void writeUnpacked(const typename ARRAY_TRAITS::OwnerType& owner, BitStreamWriter& out,
359  typename ARRAY_TRAITS::ElementType element)
360  {
361  m_previousElement = static_cast<uint64_t>(element);
362  ARRAY_TRAITS::write(owner, out, element);
363  }
364 
365  template <typename ARRAY_TRAITS,
366  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
367  void writeUnpacked(const DummyOwner&, BitStreamWriter& out, typename ARRAY_TRAITS::ElementType element)
368  {
369  m_previousElement = static_cast<uint64_t>(element);
370  ARRAY_TRAITS::write(out, element);
371  }
372 
373  void setFlag(uint8_t flagMask)
374  {
375  m_flags |= flagMask;
376  }
377 
378  void resetFlag(uint8_t flagMask)
379  {
380  m_flags &= static_cast<uint8_t>(~flagMask);
381  }
382 
383  bool isFlagSet(uint8_t flagMask) const
384  {
385  return ((m_flags & flagMask) != 0);
386  }
387 
388  static const uint8_t MAX_BIT_NUMBER_BITS = 6;
389  static const uint8_t MAX_BIT_NUMBER_LIMIT = 62;
390 
391  static const uint8_t INIT_STARTED_FLAG = 0x01;
392  static const uint8_t IS_PACKED_FLAG = 0x02;
393  static const uint8_t PROCESSING_STARTED_FLAG = 0x04;
394 
395  uint64_t m_previousElement = 0;
396  uint8_t m_maxBitNumber = 0;
397  uint8_t m_flags = 0x00;
398 
399  uint8_t m_firstElementBitSize = 0;
400  uint32_t m_numElements = 0;
401  size_t m_unpackedBitSize = 0;
402 };
403 
404 } // namespace zserio
405 
406 #endif // ZSERIO_DELTA_CONTEXT_H_INC
int64_t readSignedBits64(uint8_t numBits=64)
void writeSignedBits64(int64_t data, uint8_t numBits=64)
void init(const OWNER_TYPE &owner, typename ARRAY_TRAITS::ElementType element)
Definition: DeltaContext.h:87
void write(const OWNER_TYPE &owner, BitStreamWriter &out, typename ARRAY_TRAITS::ElementType element)
Definition: DeltaContext.h:191
ARRAY_TRAITS::ElementType read(const OWNER_TYPE &owner, BitStreamReader &in)
Definition: DeltaContext.h:155
ARRAY_TRAITS::ElementType read(BitStreamReader &in)
Definition: DeltaContext.h:251
DeltaContext & operator=(const DeltaContext &other)=default
void init(typename ARRAY_TRAITS::ElementType element)
Definition: DeltaContext.h:225
size_t bitSizeOf(const OWNER_TYPE &owner, typename ARRAY_TRAITS::ElementType element)
Definition: DeltaContext.h:127
void write(BitStreamWriter &out, typename ARRAY_TRAITS::ElementType element)
Definition: DeltaContext.h:263
size_t bitSizeOf(typename ARRAY_TRAITS::ElementType element)
Definition: DeltaContext.h:238
DeltaContext(const DeltaContext &other)=default
DeltaContext & operator=(DeltaContext &&other)=default
DeltaContext(DeltaContext &&other)=default
T read(BitStreamReader &in)
void write(BitStreamWriter &out, T value)
size_t bitSizeOf(T value)