Zserio C++17 runtime library 1.3.0
Built for Zserio 2.20.0
Loading...
Searching...
No Matches
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
12namespace zserio
13{
14
15namespace detail
16{
17
18// calculates bit length on delta provided as an absolute number
19inline 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
32template <typename T>
33uint8_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
44template <typename T>
45int64_t calcUncheckedDelta(T lhs, uint64_t rhs)
46{
47 return static_cast<int64_t>(static_cast<uint64_t>(lhs) - rhs);
48}
49
58class DeltaContext
59{
60public:
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
210private:
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
307template <typename T, typename = void>
308struct packing_context_type
309{
310 using type = DeltaContext;
311};
312
313template <typename T>
314struct 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
320template <typename T, typename V = void>
321using packing_context_type_t = typename packing_context_type<T, V>::type;
322
323template <typename T>
324void initContext(typename ObjectTraits<T>::PackingContext& packingContext, const View<T>& view)
325{
326 ObjectTraits<T>::initContext(packingContext, view);
327}
328
329template <typename T>
330BitSize bitSizeOf(
331 typename ObjectTraits<T>::PackingContext& packingContext, const View<T>& view, BitSize bitPosition)
332{
333 return ObjectTraits<T>::bitSizeOf(packingContext, view, bitPosition);
334}
335
336template <typename T>
337BitSize 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
350template <typename T>
351void write(
352 typename ObjectTraits<T>::PackingContext& packingContext, BitStreamWriter& writer, const View<T>& view)
353{
354 ObjectTraits<T>::write(packingContext, writer, view);
355}
356
357template <typename T, typename... ARGS>
358void 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
364inline void initContext(DeltaContext& deltaContext, Bool value)
365{
366 deltaContext.init(value);
367}
368
369inline BitSize bitSizeOf(DeltaContext& deltaContext, Bool value, BitSize = 0)
370{
371 return deltaContext.bitSizeOf(value);
372}
373
374inline void write(DeltaContext& deltaContext, BitStreamWriter& writer, Bool value)
375{
376 deltaContext.write(writer, value);
377}
378
379inline void read(DeltaContext& deltaContext, BitStreamReader& reader, Bool& value)
380{
381 deltaContext.read(reader, value);
382}
383
384template <BitSize BIT_SIZE, bool IS_SIGNED>
385void initContext(DeltaContext& deltaContext, FixedIntWrapper<BIT_SIZE, IS_SIGNED> value)
386{
387 deltaContext.init(value);
388}
389
390template <BitSize BIT_SIZE, bool IS_SIGNED>
391BitSize bitSizeOf(DeltaContext& deltaContext, FixedIntWrapper<BIT_SIZE, IS_SIGNED> value, BitSize = 0)
392{
393 return deltaContext.bitSizeOf(value);
394}
395
396template <BitSize BIT_SIZE, bool IS_SIGNED>
397void write(DeltaContext& deltaContext, BitStreamWriter& writer, FixedIntWrapper<BIT_SIZE, IS_SIGNED> value)
398{
399 deltaContext.write(writer, value);
400}
401
402template <BitSize BIT_SIZE, bool IS_SIGNED>
403void read(DeltaContext& deltaContext, BitStreamReader& reader, FixedIntWrapper<BIT_SIZE, IS_SIGNED>& value)
404{
405 deltaContext.read(reader, value);
406}
407
408template <typename T, VarIntType VAR_TYPE>
409void initContext(DeltaContext& deltaContext, VarIntWrapper<T, VAR_TYPE> value)
410{
411 deltaContext.init(value);
412}
413
414template <typename T, VarIntType VAR_TYPE>
415BitSize bitSizeOf(DeltaContext& deltaContext, VarIntWrapper<T, VAR_TYPE> value, BitSize = 0)
416{
417 return deltaContext.bitSizeOf(value);
418}
419
420template <typename T, VarIntType VAR_TYPE>
421void write(DeltaContext& deltaContext, BitStreamWriter& writer, VarIntWrapper<T, VAR_TYPE> value)
422{
423 deltaContext.write(writer, value);
424}
425
426template <typename T, VarIntType VAR_TYPE>
427void read(DeltaContext& deltaContext, BitStreamReader& reader, VarIntWrapper<T, VAR_TYPE>& value)
428{
429 deltaContext.read(reader, value);
430}
431
432template <typename T>
433void initContext(DeltaContext& deltaContext, View<DynIntWrapper<T>> view)
434{
435 deltaContext.init(view);
436}
437
438template <typename T>
439BitSize bitSizeOf(DeltaContext& deltaContext, View<DynIntWrapper<T>> view, BitSize = 0)
440{
441 return deltaContext.bitSizeOf(view);
442}
443
444template <typename T>
445void write(DeltaContext& deltaContext, BitStreamWriter& writer, View<DynIntWrapper<T>> view)
446{
447 deltaContext.write(writer, view);
448}
449
450template <typename T>
451void 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
458template <typename T>
459void initContext(DeltaContext&, const View<T>&)
460{}
461
462template <typename T>
463BitSize bitSizeOf(DeltaContext&, const View<T>& value, BitSize bitPosition)
464{
465 return bitSizeOf(value, bitPosition);
466}
467
468template <typename T>
469void write(DeltaContext&, BitStreamWriter& writer, const View<T>& value)
470{
471 write(writer, value);
472}
473
474template <typename T, typename... ARGS, std::enable_if_t<is_complete_v<View<T>>, int> = 0>
475void 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
482template <typename VALUE_TYPE, FloatType FLOAT_TYPE>
483void initContext(DeltaContext&, FloatWrapper<VALUE_TYPE, FLOAT_TYPE>)
484{}
485
486template <typename VALUE_TYPE, FloatType FLOAT_TYPE>
487BitSize bitSizeOf(DeltaContext&, FloatWrapper<VALUE_TYPE, FLOAT_TYPE> value, BitSize bitPosition)
488{
489 return bitSizeOf(value, bitPosition);
490}
491
492template <typename VALUE_TYPE, FloatType FLOAT_TYPE>
493void write(DeltaContext&, BitStreamReader& writer, FloatWrapper<VALUE_TYPE, FLOAT_TYPE> value)
494{
495 write(writer, value);
496}
497
498template <typename VALUE_TYPE, FloatType FLOAT_TYPE>
499void read(DeltaContext&, BitStreamReader& reader, FloatWrapper<VALUE_TYPE, FLOAT_TYPE>& value)
500{
501 read(reader, value);
502}
503
504inline void initContext(DeltaContext&, BytesView)
505{}
506
507inline BitSize bitSizeOf(DeltaContext&, BytesView value, BitSize bitPosition)
508{
509 return bitSizeOf(value, bitPosition);
510}
511
512inline void write(DeltaContext&, BitStreamWriter& writer, BytesView value)
513{
514 write(writer, value);
515}
516
517template <typename ALLOC>
518void read(DeltaContext&, BitStreamReader& reader, BasicBytes<ALLOC>& value)
519{
520 read(reader, value);
521}
522
523inline void initContext(DeltaContext&, std::string_view)
524{}
525
526inline BitSize bitSizeOf(DeltaContext&, std::string_view value, BitSize bitPosition)
527{
528 return bitSizeOf(value, bitPosition);
529}
530
531inline void write(DeltaContext&, BitStreamWriter& writer, std::string_view value)
532{
533 write(writer, value);
534}
535
536template <typename ALLOC>
537void read(DeltaContext&, BitStreamReader& reader, zserio::BasicString<ALLOC>& value)
538{
539 read(reader, value);
540}
541
542template <typename ALLOC>
543void initContext(DeltaContext&, const BasicBitBufferView<ALLOC>&)
544{}
545
546template <typename ALLOC>
547BitSize bitSizeOf(DeltaContext&, const BasicBitBufferView<ALLOC>& value, BitSize bitPosition)
548{
549 return bitSizeOf(value, bitPosition);
550}
551
552template <typename ALLOC>
553void write(DeltaContext&, BitStreamWriter& writer, const BasicBitBufferView<ALLOC>& value)
554{
555 write(writer, value);
556}
557
558template <typename ALLOC>
559void 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
Span< const uint8_t > BytesView
Definition Bytes.h:30
detail::BoolWrapper Bool
Definition Types.h:732
unsigned int BitSize
Definition BitSize.h:8