Zserio C++ runtime library  1.1.0
Built for Zserio 2.15.0
Array.h
Go to the documentation of this file.
1 #ifndef ZSERIO_ARRAY_H_INC
2 #define ZSERIO_ARRAY_H_INC
3 
4 #include <cstdlib>
5 #include <type_traits>
6 
8 #include "zserio/ArrayTraits.h"
10 #include "zserio/BitStreamReader.h"
11 #include "zserio/BitStreamWriter.h"
12 #include "zserio/DeltaContext.h"
13 #include "zserio/SizeConvertUtil.h"
14 #include "zserio/Traits.h"
15 #include "zserio/UniquePtr.h"
16 
17 namespace zserio
18 {
19 
20 namespace detail
21 {
22 
23 // array expressions for arrays which do not need expressions
24 struct DummyArrayExpressions
25 {};
26 
27 // array owner for arrays which do not need the owner
28 struct DummyArrayOwner
29 {};
30 
31 // helper trait to choose the owner type for an array from combination of ARRAY_TRAITS and ARRAY_EXPRESSIONS
32 template <typename ARRAY_TRAITS, typename ARRAY_EXPRESSIONS, typename = void>
33 struct array_owner_type
34 {
35  using type = DummyArrayOwner;
36 };
37 
38 template <typename ARRAY_TRAITS, typename ARRAY_EXPRESSIONS>
39 struct array_owner_type<ARRAY_TRAITS, ARRAY_EXPRESSIONS,
40  typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value>::type>
41 {
42  using type = typename ARRAY_TRAITS::OwnerType;
43 };
44 
45 template <typename ARRAY_TRAITS, typename ARRAY_EXPRESSIONS>
46 struct array_owner_type<ARRAY_TRAITS, ARRAY_EXPRESSIONS,
47  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
48  has_owner_type<ARRAY_EXPRESSIONS>::value>::type>
49 {
50  using type = typename ARRAY_EXPRESSIONS::OwnerType;
51 };
52 
53 // helper trait to choose packing context type for an array from an element type T
54 template <typename T, typename = void>
55 struct packing_context_type
56 {
57  using type = DeltaContext;
58 };
59 
60 template <typename T>
61 struct packing_context_type<T, typename std::enable_if<has_zserio_packing_context<T>::value>::type>
62 {
63  using type = typename T::ZserioPackingContext;
64 };
65 
66 // calls the initializeOffset static method on ARRAY_EXPRESSIONS if available
67 template <typename ARRAY_EXPRESSIONS, typename OWNER_TYPE,
68  typename std::enable_if<has_initialize_offset<ARRAY_EXPRESSIONS>::value, int>::type = 0>
69 void initializeOffset(OWNER_TYPE& owner, size_t index, size_t bitPosition)
70 {
71  ARRAY_EXPRESSIONS::initializeOffset(owner, index, bitPosition);
72 }
73 
74 template <typename ARRAY_EXPRESSIONS, typename OWNER_TYPE,
75  typename std::enable_if<!has_initialize_offset<ARRAY_EXPRESSIONS>::value, int>::type = 0>
76 void initializeOffset(OWNER_TYPE&, size_t, size_t)
77 {}
78 
79 // calls the checkOffset static method on ARRAY_EXPRESSIONS if available
80 template <typename ARRAY_EXPRESSIONS, typename OWNER_TYPE,
81  typename std::enable_if<has_check_offset<ARRAY_EXPRESSIONS>::value, int>::type = 0>
82 void checkOffset(const OWNER_TYPE& owner, size_t index, size_t bitPosition)
83 {
84  ARRAY_EXPRESSIONS::checkOffset(owner, index, bitPosition);
85 }
86 
87 template <typename ARRAY_EXPRESSIONS, typename OWNER_TYPE,
88  typename std::enable_if<!has_check_offset<ARRAY_EXPRESSIONS>::value, int>::type = 0>
89 void checkOffset(const OWNER_TYPE&, size_t, size_t)
90 {}
91 
92 // call the initContext method properly on packed array traits
93 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
94  typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value &&
95  !std::is_scalar<typename PACKED_ARRAY_TRAITS::ElementType>::value,
96  int>::type = 0>
97 void packedArrayTraitsInitContext(const OWNER_TYPE& owner, PACKING_CONTEXT& context,
98  const typename PACKED_ARRAY_TRAITS::ElementType& element)
99 {
100  PACKED_ARRAY_TRAITS::initContext(owner, context, element);
101 }
102 
103 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
104  typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value &&
105  std::is_scalar<typename PACKED_ARRAY_TRAITS::ElementType>::value,
106  int>::type = 0>
107 void packedArrayTraitsInitContext(
108  const OWNER_TYPE& owner, PACKING_CONTEXT& context, typename PACKED_ARRAY_TRAITS::ElementType element)
109 {
110  PACKED_ARRAY_TRAITS::initContext(owner, context, element);
111 }
112 
113 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
114  typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
115  !std::is_scalar<typename PACKED_ARRAY_TRAITS::ElementType>::value,
116  int>::type = 0>
117 void packedArrayTraitsInitContext(
118  const OWNER_TYPE&, PACKING_CONTEXT& context, const typename PACKED_ARRAY_TRAITS::ElementType& element)
119 {
120  PACKED_ARRAY_TRAITS::initContext(context, element);
121 }
122 
123 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
124  typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
125  std::is_scalar<typename PACKED_ARRAY_TRAITS::ElementType>::value,
126  int>::type = 0>
127 void packedArrayTraitsInitContext(
128  const OWNER_TYPE&, PACKING_CONTEXT& context, typename PACKED_ARRAY_TRAITS::ElementType element)
129 {
130  PACKED_ARRAY_TRAITS::initContext(context, element);
131 }
132 
133 // calls the bitSizeOf method properly on array traits which have constant bit size
134 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
135  typename std::enable_if<ARRAY_TRAITS::IS_BITSIZEOF_CONSTANT && has_owner_type<ARRAY_TRAITS>::value,
136  int>::type = 0>
137 size_t arrayTraitsConstBitSizeOf(const OWNER_TYPE& owner)
138 {
139  return ARRAY_TRAITS::bitSizeOf(owner);
140 }
141 
142 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
143  typename std::enable_if<ARRAY_TRAITS::IS_BITSIZEOF_CONSTANT && !has_owner_type<ARRAY_TRAITS>::value,
144  int>::type = 0>
145 size_t arrayTraitsConstBitSizeOf(const OWNER_TYPE&)
146 {
147  return ARRAY_TRAITS::bitSizeOf();
148 }
149 
150 // calls the bitSizeOf method properly on array traits which haven't constant bit size
151 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
152  typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
153 size_t arrayTraitsBitSizeOf(
154  const OWNER_TYPE& owner, size_t bitPosition, const typename ARRAY_TRAITS::ElementType& element)
155 {
156  return ARRAY_TRAITS::bitSizeOf(owner, bitPosition, element);
157 }
158 
159 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
160  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
161 size_t arrayTraitsBitSizeOf(
162  const OWNER_TYPE&, size_t bitPosition, const typename ARRAY_TRAITS::ElementType& element)
163 {
164  return ARRAY_TRAITS::bitSizeOf(bitPosition, element);
165 }
166 
167 // calls the bitSizeOf method properly on packed array traits which haven't constant bit size
168 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
169  typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
170 size_t packedArrayTraitsBitSizeOf(const OWNER_TYPE& owner, PACKING_CONTEXT& context, size_t bitPosition,
171  const typename PACKED_ARRAY_TRAITS::ElementType& element)
172 {
173  return PACKED_ARRAY_TRAITS::bitSizeOf(owner, context, bitPosition, element);
174 }
175 
176 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
177  typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
178 size_t packedArrayTraitsBitSizeOf(const OWNER_TYPE&, PACKING_CONTEXT& context, size_t bitPosition,
179  const typename PACKED_ARRAY_TRAITS::ElementType& element)
180 {
181  return PACKED_ARRAY_TRAITS::bitSizeOf(context, bitPosition, element);
182 }
183 
184 // calls the initializeOffsets method properly on array traits
185 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
186  typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
187 size_t arrayTraitsInitializeOffsets(
188  OWNER_TYPE& owner, size_t bitPosition, typename ARRAY_TRAITS::ElementType& element)
189 {
190  return ARRAY_TRAITS::initializeOffsets(owner, bitPosition, element);
191 }
192 
193 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
194  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
195  !std::is_scalar<typename ARRAY_TRAITS::ElementType>::value,
196  int>::type = 0>
197 size_t arrayTraitsInitializeOffsets(
198  OWNER_TYPE&, size_t bitPosition, const typename ARRAY_TRAITS::ElementType& element)
199 {
200  return ARRAY_TRAITS::initializeOffsets(bitPosition, element);
201 }
202 
203 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
204  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
205  std::is_scalar<typename ARRAY_TRAITS::ElementType>::value,
206  int>::type = 0>
207 size_t arrayTraitsInitializeOffsets(OWNER_TYPE&, size_t bitPosition, typename ARRAY_TRAITS::ElementType element)
208 {
209  return ARRAY_TRAITS::initializeOffsets(bitPosition, element);
210 }
211 
212 // calls the initializeOffsets method properly on packed array traits
213 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
214  typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
215 size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE& owner, PACKING_CONTEXT& context, size_t bitPosition,
216  typename PACKED_ARRAY_TRAITS::ElementType& element)
217 {
218  return PACKED_ARRAY_TRAITS::initializeOffsets(owner, context, bitPosition, element);
219 }
220 
221 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
222  typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
223  !std::is_scalar<typename PACKED_ARRAY_TRAITS::ElementType>::value,
224  int>::type = 0>
225 size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE&, PACKING_CONTEXT& context, size_t bitPosition,
226  const typename PACKED_ARRAY_TRAITS::ElementType& element)
227 {
228  return PACKED_ARRAY_TRAITS::initializeOffsets(context, bitPosition, element);
229 }
230 
231 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
232  typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
233  std::is_scalar<typename PACKED_ARRAY_TRAITS::ElementType>::value,
234  int>::type = 0>
235 size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE&, PACKING_CONTEXT& context, size_t bitPosition,
236  typename PACKED_ARRAY_TRAITS::ElementType element)
237 {
238  return PACKED_ARRAY_TRAITS::initializeOffsets(context, bitPosition, element);
239 }
240 
241 // calls the read method properly on array traits
242 template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
243  typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value && !has_allocator<ARRAY_TRAITS>::value,
244  int>::type = 0>
245 void arrayTraitsRead(const OWNER_TYPE& owner, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
246 {
247  rawArray.push_back(ARRAY_TRAITS::read(owner, in, index));
248 }
249 
250 template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
251  typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value && has_allocator<ARRAY_TRAITS>::value,
252  int>::type = 0>
253 void arrayTraitsRead(OWNER_TYPE& owner, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
254 {
255  ARRAY_TRAITS::read(owner, rawArray, in, index);
256 }
257 
258 template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
259  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value && !has_allocator<ARRAY_TRAITS>::value,
260  int>::type = 0>
261 void arrayTraitsRead(const OWNER_TYPE&, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
262 {
263  rawArray.push_back(ARRAY_TRAITS::read(in, index));
264 }
265 
266 template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
267  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value && has_allocator<ARRAY_TRAITS>::value,
268  int>::type = 0>
269 void arrayTraitsRead(const OWNER_TYPE&, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
270 {
271  ARRAY_TRAITS::read(rawArray, in, index);
272 }
273 
274 // calls the read method properly on packed array traits
275 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY, typename PACKING_CONTEXT,
276  typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value &&
277  has_allocator<PACKED_ARRAY_TRAITS>::value,
278  int>::type = 0>
279 void packedArrayTraitsRead(
280  OWNER_TYPE& owner, RAW_ARRAY& rawArray, PACKING_CONTEXT& context, BitStreamReader& in, size_t index)
281 {
282  PACKED_ARRAY_TRAITS::read(owner, rawArray, context, in, index);
283 }
284 
285 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY, typename PACKING_CONTEXT,
286  typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value &&
287  !has_allocator<PACKED_ARRAY_TRAITS>::value,
288  int>::type = 0>
289 void packedArrayTraitsRead(const OWNER_TYPE& owner, RAW_ARRAY& rawArray, PACKING_CONTEXT& context,
290  BitStreamReader& in, size_t index)
291 {
292  rawArray.push_back(PACKED_ARRAY_TRAITS::read(owner, context, in, index));
293 }
294 
295 // note: types which doesn't have owner and have allocator are never packed (e.g. string, bytes ...)
296 // and thus such specialization is not needed
297 
298 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY, typename PACKING_CONTEXT,
299  typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
300  !has_allocator<PACKED_ARRAY_TRAITS>::value,
301  int>::type = 0>
302 void packedArrayTraitsRead(
303  const OWNER_TYPE&, RAW_ARRAY& rawArray, PACKING_CONTEXT& context, BitStreamReader& in, size_t index)
304 {
305  rawArray.push_back(PACKED_ARRAY_TRAITS::read(context, in, index));
306 }
307 
308 // call the write method properly on array traits
309 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
310  typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
311 void arrayTraitsWrite(
312  const OWNER_TYPE& owner, BitStreamWriter& out, const typename ARRAY_TRAITS::ElementType& element)
313 {
314  ARRAY_TRAITS::write(owner, out, element);
315 }
316 
317 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
318  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
319 void arrayTraitsWrite(
320  const OWNER_TYPE&, BitStreamWriter& out, const typename ARRAY_TRAITS::ElementType& element)
321 {
322  ARRAY_TRAITS::write(out, element);
323 }
324 
325 // call the write method properly on packed array traits
326 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
327  typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
328 void packedArrayTraitsWrite(const OWNER_TYPE& owner, PACKING_CONTEXT& context, BitStreamWriter& out,
329  const typename PACKED_ARRAY_TRAITS::ElementType& element)
330 {
331  PACKED_ARRAY_TRAITS::write(owner, context, out, element);
332 }
333 
334 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
335  typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
336 void packedArrayTraitsWrite(const OWNER_TYPE&, PACKING_CONTEXT& context, BitStreamWriter& out,
337  const typename PACKED_ARRAY_TRAITS::ElementType& element)
338 {
339  PACKED_ARRAY_TRAITS::write(context, out, element);
340 }
341 
342 } // namespace detail
343 
348 {
353  ALIGNED_AUTO
354 };
355 
363 template <typename RAW_ARRAY, typename ARRAY_TRAITS, ArrayType ARRAY_TYPE,
364  typename ARRAY_EXPRESSIONS = detail::DummyArrayExpressions>
365 class Array
366 {
367 public:
369  using RawArray = RAW_ARRAY;
370 
372  using ArrayTraits = ARRAY_TRAITS;
373 
375  using ArrayExpressions = ARRAY_EXPRESSIONS;
376 
383  using OwnerType = typename detail::array_owner_type<ArrayTraits, ArrayExpressions>::type;
384 
386  using allocator_type = typename RawArray::allocator_type;
387 
393  explicit Array(const allocator_type& allocator = allocator_type()) :
394  m_rawArray(allocator)
395  {}
396 
402  explicit Array(const RawArray& rawArray) :
403  m_rawArray(rawArray)
404  {}
405 
411  explicit Array(RawArray&& rawArray) :
412  m_rawArray(std::move(rawArray))
413  {}
414 
420  ~Array() = default;
421  Array(const Array& other) = default;
422  Array& operator=(const Array& other) = default;
423  Array(Array&& other) = default;
424  Array& operator=(Array&& other) = default;
436  template <typename T = typename RAW_ARRAY::value_type,
437  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
438  Array(NoInitT, const Array& other) :
439  Array(std::allocator_traits<allocator_type>::select_on_container_copy_construction(
440  other.m_rawArray.get_allocator()))
441  {
442  m_rawArray.reserve(other.m_rawArray.size());
443  for (const auto& value : other.m_rawArray)
444  {
445  m_rawArray.emplace_back(NoInit, value);
446  }
447  }
448 
456  template <typename T = typename RAW_ARRAY::value_type,
457  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
458  Array& assign(NoInitT, const Array& other)
459  {
460  const RawArray rawArray(other.m_rawArray.get_allocator());
461  m_rawArray = rawArray; // copy assign to get correct allocator propagation behaviour
462  m_rawArray.reserve(other.m_rawArray.size());
463  for (const auto& value : other.m_rawArray)
464  {
465  m_rawArray.emplace_back(NoInit, value);
466  }
467 
468  return *this;
469  }
470 
478  template <typename T = typename RAW_ARRAY::value_type,
479  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
480  Array(NoInitT, Array&& other) :
481  Array(std::move(other))
482  {}
483 
492  template <typename T = typename RAW_ARRAY::value_type,
493  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
495  {
496  return operator=(std::move(other));
497  }
498 
505  Array(PropagateAllocatorT, const Array& other, const allocator_type& allocator) :
506  m_rawArray(allocatorPropagatingCopy(other.m_rawArray, allocator))
507  {}
508 
516  template <typename T = typename RAW_ARRAY::value_type,
517  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
518  Array(PropagateAllocatorT, NoInitT, const Array& other, const allocator_type& allocator) :
519  m_rawArray(allocatorPropagatingCopy(NoInit, other.m_rawArray, allocator))
520  {}
521 
529  bool operator==(const Array& other) const
530  {
531  return m_rawArray == other.m_rawArray;
532  }
533 
541  bool operator<(const Array& other) const
542  {
543  return m_rawArray < other.m_rawArray;
544  }
545 
551  uint32_t hashCode() const
552  {
553  return calcHashCode(HASH_SEED, m_rawArray);
554  }
555 
561  const RawArray& getRawArray() const
562  {
563  return m_rawArray;
564  }
565 
572  {
573  return m_rawArray;
574  }
575 
581  template <typename ARRAY_EXPRESSIONS_ = ArrayExpressions,
582  typename std::enable_if<has_initialize_element<ARRAY_EXPRESSIONS_>::value, int>::type = 0>
584  {
585  size_t index = 0;
586  for (auto&& element : m_rawArray)
587  {
588  ArrayExpressions::initializeElement(owner, element, index);
589  index++;
590  }
591  }
592 
602  template <typename OWNER_TYPE_ = OwnerType,
603  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
604  size_t bitSizeOf(size_t bitPosition) const
605  {
606  return bitSizeOfImpl(detail::DummyArrayOwner(), bitPosition);
607  }
608 
619  template <typename OWNER_TYPE_ = OwnerType,
620  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
621  size_t bitSizeOf(const OwnerType& owner, size_t bitPosition) const
622  {
623  return bitSizeOfImpl(owner, bitPosition);
624  }
625 
635  template <typename OWNER_TYPE_ = OwnerType,
636  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
637  size_t initializeOffsets(size_t bitPosition)
638  {
639  detail::DummyArrayOwner owner;
640  return initializeOffsetsImpl(owner, bitPosition);
641  }
642 
653  template <typename OWNER_TYPE_ = OwnerType,
654  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
655  size_t initializeOffsets(OwnerType& owner, size_t bitPosition)
656  {
657  return initializeOffsetsImpl(owner, bitPosition);
658  }
659 
668  template <typename OWNER_TYPE_ = OwnerType,
669  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
670  void read(BitStreamReader& in, size_t arrayLength = 0)
671  {
672  detail::DummyArrayOwner owner;
673  readImpl(owner, in, arrayLength);
674  }
675 
685  template <typename OWNER_TYPE_ = OwnerType,
686  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
687  void read(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
688  {
689  readImpl(owner, in, arrayLength);
690  }
691 
699  template <typename OWNER_TYPE_ = OwnerType,
700  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
701  void write(BitStreamWriter& out) const
702  {
703  writeImpl(detail::DummyArrayOwner(), out);
704  }
705 
714  template <typename OWNER_TYPE_ = OwnerType,
715  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
716  void write(const OwnerType& owner, BitStreamWriter& out) const
717  {
718  writeImpl(owner, out);
719  }
720 
730  template <typename OWNER_TYPE_ = OwnerType,
731  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
732  size_t bitSizeOfPacked(size_t bitPosition) const
733  {
734  return bitSizeOfPackedImpl(detail::DummyArrayOwner(), bitPosition);
735  }
736 
747  template <typename OWNER_TYPE_ = OwnerType,
748  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
749  size_t bitSizeOfPacked(const OwnerType& ownerType, size_t bitPosition) const
750  {
751  return bitSizeOfPackedImpl(ownerType, bitPosition);
752  }
753 
763  template <typename OWNER_TYPE_ = OwnerType,
764  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
765  size_t initializeOffsetsPacked(size_t bitPosition)
766  {
767  detail::DummyArrayOwner owner;
768  return initializeOffsetsPackedImpl(owner, bitPosition);
769  }
770 
781  template <typename OWNER_TYPE_ = OwnerType,
782  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
783  size_t initializeOffsetsPacked(OwnerType& owner, size_t bitPosition)
784  {
785  return initializeOffsetsPackedImpl(owner, bitPosition);
786  }
787 
796  template <typename OWNER_TYPE_ = OwnerType,
797  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
798  void readPacked(BitStreamReader& in, size_t arrayLength = 0)
799  {
800  detail::DummyArrayOwner owner;
801  readPackedImpl(owner, in, arrayLength);
802  }
803 
813  template <typename OWNER_TYPE_ = OwnerType,
814  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
815  void readPacked(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
816  {
817  readPackedImpl(owner, in, arrayLength);
818  }
819 
827  template <typename OWNER_TYPE_ = OwnerType,
828  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
829  void writePacked(BitStreamWriter& out) const
830  {
831  writePackedImpl(detail::DummyArrayOwner(), out);
832  }
833 
842  template <typename OWNER_TYPE_ = OwnerType,
843  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
844  void writePacked(const OwnerType& owner, BitStreamWriter& out) const
845  {
846  writePackedImpl(owner, out);
847  }
848 
849 private:
850  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
851  typename std::enable_if<ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
852  int>::type = 0>
853  static void addBitSizeOfArrayLength(size_t&, size_t)
854  {}
855 
856  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
857  typename std::enable_if<ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
858  int>::type = 0>
859  static void addBitSizeOfArrayLength(size_t& bitPosition, size_t arrayLength)
860  {
861  bitPosition += bitSizeOfVarSize(convertSizeToUInt32(arrayLength));
862  }
863 
864  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
865  typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
866  int>::type = 0>
867  static void alignBitPosition(size_t&)
868  {}
869 
870  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
871  typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
872  int>::type = 0>
873  static void alignBitPosition(size_t& bitPosition)
874  {
875  bitPosition = alignTo(8, bitPosition);
876  }
877 
878  template <typename IO, typename OWNER_TYPE, ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
879  typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
880  int>::type = 0>
881  static void alignAndCheckOffset(IO&, OWNER_TYPE&, size_t)
882  {}
883 
884  template <typename IO, typename OWNER_TYPE, ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
885  typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
886  int>::type = 0>
887  static void alignAndCheckOffset(IO& io, OWNER_TYPE& owner, size_t index)
888  {
889  io.alignTo(8);
890  detail::checkOffset<ArrayExpressions>(owner, index, io.getBitPosition() / 8);
891  }
892 
893  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
894  typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
895  int>::type = 0>
896  static void initializeOffset(OwnerType&, size_t, size_t&)
897  {}
898 
899  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
900  typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
901  int>::type = 0>
902  static void initializeOffset(OwnerType& owner, size_t index, size_t& bitPosition)
903  {
904  bitPosition = alignTo(8, bitPosition);
905  detail::initializeOffset<ArrayExpressions>(owner, index, bitPosition / 8);
906  }
907 
908  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
909  typename std::enable_if<ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO &&
910  ARRAY_TYPE_ != ArrayType::IMPLICIT,
911  int>::type = 0>
912  static size_t readArrayLength(OwnerType&, BitStreamReader&, size_t arrayLength)
913  {
914  return arrayLength;
915  }
916 
917  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
918  typename std::enable_if<ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
919  int>::type = 0>
920  static size_t readArrayLength(OwnerType&, BitStreamReader& in, size_t)
921  {
922  return in.readVarSize();
923  }
924 
925  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
926  typename std::enable_if<ARRAY_TYPE_ == ArrayType::IMPLICIT, int>::type = 0>
927  static size_t readArrayLength(OwnerType& owner, BitStreamReader& in, size_t)
928  {
929  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT || ArrayTraits::IS_BITSIZEOF_CONSTANT,
930  "Implicit array elements must have constant bit size!");
931 
932  const size_t remainingBits = in.getBufferBitSize() - in.getBitPosition();
933  return remainingBits / detail::arrayTraitsConstBitSizeOf<ArrayTraits>(owner);
934  }
935 
936  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
937  typename std::enable_if<ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
938  int>::type = 0>
939  static void writeArrayLength(BitStreamWriter&, size_t)
940  {}
941 
942  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
943  typename std::enable_if<ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
944  int>::type = 0>
945  static void writeArrayLength(BitStreamWriter& out, size_t arrayLength)
946  {
947  out.writeVarSize(convertSizeToUInt32(arrayLength));
948  }
949 
950  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
951  typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
952  int>::type = 0>
953  static size_t constBitSizeOfElements(size_t, size_t arrayLength, size_t elementBitSize)
954  {
955  return arrayLength * elementBitSize;
956  }
957 
958  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
959  typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
960  int>::type = 0>
961  static size_t constBitSizeOfElements(size_t bitPosition, size_t arrayLength, size_t elementBitSize)
962  {
963  size_t endBitPosition = alignTo(8, bitPosition);
964  endBitPosition += elementBitSize + (arrayLength - 1) * alignTo(8, elementBitSize);
965 
966  return endBitPosition - bitPosition;
967  }
968 
969  template <typename ARRAY_TRAITS_ = ArrayTraits,
970  typename std::enable_if<ARRAY_TRAITS_::IS_BITSIZEOF_CONSTANT, int>::type = 0>
971  size_t bitSizeOfImpl(const OwnerType& owner, size_t bitPosition) const
972  {
973  size_t endBitPosition = bitPosition;
974 
975  const size_t arrayLength = m_rawArray.size();
976  addBitSizeOfArrayLength(endBitPosition, arrayLength);
977 
978  if (arrayLength > 0)
979  {
980  const size_t elementBitSize = detail::arrayTraitsConstBitSizeOf<ArrayTraits>(owner);
981  endBitPosition += constBitSizeOfElements(endBitPosition, arrayLength, elementBitSize);
982  }
983 
984  return endBitPosition - bitPosition;
985  }
986 
987  template <typename ARRAY_TRAITS_ = ArrayTraits,
988  typename std::enable_if<!ARRAY_TRAITS_::IS_BITSIZEOF_CONSTANT, int>::type = 0>
989  size_t bitSizeOfImpl(const OwnerType& owner, size_t bitPosition) const
990  {
991  size_t endBitPosition = bitPosition;
992 
993  const size_t arrayLength = m_rawArray.size();
994  addBitSizeOfArrayLength(endBitPosition, arrayLength);
995 
996  for (size_t index = 0; index < arrayLength; ++index)
997  {
998  alignBitPosition(endBitPosition);
999  endBitPosition +=
1000  detail::arrayTraitsBitSizeOf<ArrayTraits>(owner, endBitPosition, m_rawArray[index]);
1001  }
1002 
1003  return endBitPosition - bitPosition;
1004  }
1005 
1006  size_t initializeOffsetsImpl(OwnerType& owner, size_t bitPosition)
1007  {
1008  size_t endBitPosition = bitPosition;
1009 
1010  const size_t arrayLength = m_rawArray.size();
1011  addBitSizeOfArrayLength(endBitPosition, arrayLength);
1012 
1013  for (size_t index = 0; index < arrayLength; ++index)
1014  {
1015  initializeOffset(owner, index, endBitPosition);
1016  endBitPosition =
1017  detail::arrayTraitsInitializeOffsets<ArrayTraits>(owner, endBitPosition, m_rawArray[index]);
1018  }
1019 
1020  return endBitPosition;
1021  }
1022 
1023  void readImpl(OwnerType& owner, BitStreamReader& in, size_t arrayLength)
1024  {
1025  size_t readLength = readArrayLength(owner, in, arrayLength);
1026 
1027  m_rawArray.clear();
1028  m_rawArray.reserve(readLength);
1029  for (size_t index = 0; index < readLength; ++index)
1030  {
1031  alignAndCheckOffset(in, owner, index);
1032  detail::arrayTraitsRead<ArrayTraits>(owner, m_rawArray, in, index);
1033  }
1034  }
1035 
1036  void writeImpl(const OwnerType& owner, BitStreamWriter& out) const
1037  {
1038  const size_t arrayLength = m_rawArray.size();
1039  writeArrayLength(out, arrayLength);
1040 
1041  for (size_t index = 0; index < arrayLength; ++index)
1042  {
1043  alignAndCheckOffset(out, owner, index);
1044  detail::arrayTraitsWrite<ArrayTraits>(owner, out, m_rawArray[index]);
1045  }
1046  }
1047 
1048  using PackingContext = typename detail::packing_context_type<typename RawArray::value_type>::type;
1049 
1050  size_t bitSizeOfPackedImpl(const OwnerType& owner, size_t bitPosition) const
1051  {
1052  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1053 
1054  size_t endBitPosition = bitPosition;
1055 
1056  const size_t arrayLength = m_rawArray.size();
1057  addBitSizeOfArrayLength(endBitPosition, arrayLength);
1058 
1059  if (arrayLength > 0)
1060  {
1061  PackingContext context;
1062 
1063  for (size_t index = 0; index < arrayLength; ++index)
1064  {
1065  detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1066  owner, context, m_rawArray[index]);
1067  }
1068 
1069  for (size_t index = 0; index < arrayLength; ++index)
1070  {
1071  alignBitPosition(endBitPosition);
1072  endBitPosition += detail::packedArrayTraitsBitSizeOf<PackedArrayTraits<ArrayTraits>>(
1073  owner, context, endBitPosition, m_rawArray[index]);
1074  }
1075  }
1076 
1077  return endBitPosition - bitPosition;
1078  }
1079 
1080  size_t initializeOffsetsPackedImpl(OwnerType& owner, size_t bitPosition)
1081  {
1082  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1083 
1084  size_t endBitPosition = bitPosition;
1085 
1086  const size_t arrayLength = m_rawArray.size();
1087  addBitSizeOfArrayLength(endBitPosition, arrayLength);
1088 
1089  if (arrayLength > 0)
1090  {
1091  PackingContext context;
1092 
1093  for (size_t index = 0; index < arrayLength; ++index)
1094  {
1095  detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1096  owner, context, m_rawArray[index]);
1097  }
1098 
1099  for (size_t index = 0; index < arrayLength; ++index)
1100  {
1101  initializeOffset(owner, index, endBitPosition);
1102  endBitPosition = detail::packedArrayTraitsInitializeOffsets<PackedArrayTraits<ArrayTraits>>(
1103  owner, context, endBitPosition, m_rawArray[index]);
1104  }
1105  }
1106 
1107  return endBitPosition;
1108  }
1109 
1110  void readPackedImpl(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
1111  {
1112  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1113 
1114  size_t readLength = readArrayLength(owner, in, arrayLength);
1115 
1116  m_rawArray.clear();
1117 
1118  if (readLength > 0)
1119  {
1120  m_rawArray.reserve(readLength);
1121 
1122  PackingContext context;
1123 
1124  for (size_t index = 0; index < readLength; ++index)
1125  {
1126  alignAndCheckOffset(in, owner, index);
1127  detail::packedArrayTraitsRead<PackedArrayTraits<ArrayTraits>>(
1128  owner, m_rawArray, context, in, index);
1129  }
1130  }
1131  }
1132 
1133  void writePackedImpl(const OwnerType& owner, BitStreamWriter& out) const
1134  {
1135  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1136 
1137  const size_t arrayLength = m_rawArray.size();
1138  writeArrayLength(out, arrayLength);
1139 
1140  if (arrayLength > 0)
1141  {
1142  PackingContext context;
1143 
1144  for (size_t index = 0; index < arrayLength; ++index)
1145  {
1146  detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1147  owner, context, m_rawArray[index]);
1148  }
1149 
1150  for (size_t index = 0; index < arrayLength; ++index)
1151  {
1152  alignAndCheckOffset(out, owner, index);
1153  detail::packedArrayTraitsWrite<PackedArrayTraits<ArrayTraits>>(
1154  owner, context, out, m_rawArray[index]);
1155  }
1156  }
1157  }
1158 
1159  RawArray m_rawArray;
1160 };
1161 
1166 template <typename ARRAY, typename RAW_ARRAY>
1167 ARRAY createOptionalArray(RAW_ARRAY&& rawArray)
1168 {
1169  return ARRAY(std::forward<RAW_ARRAY>(rawArray));
1170 }
1171 
1175 template <typename ARRAY>
1177 {
1178  return NullOpt;
1179 }
1180 
1181 } // namespace zserio
1182 
1183 #endif // ZSERIO_ARRAY_H_INC
size_t bitSizeOf(const OwnerType &owner, size_t bitPosition) const
Definition: Array.h:621
ARRAY_TRAITS ArrayTraits
Definition: Array.h:372
Array(NoInitT, const Array &other)
Definition: Array.h:438
bool operator==(const Array &other) const
Definition: Array.h:529
~Array()=default
void readPacked(BitStreamReader &in, size_t arrayLength=0)
Definition: Array.h:798
Array & operator=(Array &&other)=default
size_t initializeOffsetsPacked(OwnerType &owner, size_t bitPosition)
Definition: Array.h:783
RAW_ARRAY RawArray
Definition: Array.h:369
Array & assign(NoInitT, const Array &other)
Definition: Array.h:458
RawArray & getRawArray()
Definition: Array.h:571
void write(BitStreamWriter &out) const
Definition: Array.h:701
void read(OwnerType &owner, BitStreamReader &in, size_t arrayLength=0)
Definition: Array.h:687
Array & operator=(const Array &other)=default
size_t bitSizeOfPacked(size_t bitPosition) const
Definition: Array.h:732
size_t initializeOffsets(OwnerType &owner, size_t bitPosition)
Definition: Array.h:655
void readPacked(OwnerType &owner, BitStreamReader &in, size_t arrayLength=0)
Definition: Array.h:815
void read(BitStreamReader &in, size_t arrayLength=0)
Definition: Array.h:670
typename detail::array_owner_type< ArrayTraits, ArrayExpressions >::type OwnerType
Definition: Array.h:383
size_t initializeOffsets(size_t bitPosition)
Definition: Array.h:637
void writePacked(BitStreamWriter &out) const
Definition: Array.h:829
uint32_t hashCode() const
Definition: Array.h:551
Array(RawArray &&rawArray)
Definition: Array.h:411
bool operator<(const Array &other) const
Definition: Array.h:541
Array(PropagateAllocatorT, const Array &other, const allocator_type &allocator)
Definition: Array.h:505
ARRAY_EXPRESSIONS ArrayExpressions
Definition: Array.h:375
typename RawArray::allocator_type allocator_type
Definition: Array.h:386
size_t bitSizeOf(size_t bitPosition) const
Definition: Array.h:604
Array(Array &&other)=default
Array(PropagateAllocatorT, NoInitT, const Array &other, const allocator_type &allocator)
Definition: Array.h:518
void initializeElements(OwnerType &owner)
Definition: Array.h:583
const RawArray & getRawArray() const
Definition: Array.h:561
Array & assign(NoInitT, Array &&other)
Definition: Array.h:494
void write(const OwnerType &owner, BitStreamWriter &out) const
Definition: Array.h:716
Array(NoInitT, Array &&other)
Definition: Array.h:480
size_t initializeOffsetsPacked(size_t bitPosition)
Definition: Array.h:765
Array(const RawArray &rawArray)
Definition: Array.h:402
size_t bitSizeOfPacked(const OwnerType &ownerType, size_t bitPosition) const
Definition: Array.h:749
Array(const allocator_type &allocator=allocator_type())
Definition: Array.h:393
Array(const Array &other)=default
void writePacked(const OwnerType &owner, BitStreamWriter &out) const
Definition: Array.h:844
T read(BitStreamReader &in)
constexpr NoInitT NoInit
Definition: NoInit.h:18
void write(BitStreamWriter &out, T value)
ARRAY createOptionalArray(RAW_ARRAY &&rawArray)
Definition: Array.h:1167
T allocatorPropagatingCopy(const T &source, const ALLOC &allocator)
size_t alignTo(size_t alignmentValue, size_t bitPosition)
constexpr NullOptType NullOpt
size_t initializeOffsets(size_t bitPosition, T value)
size_t bitSizeOfVarSize(uint32_t value)
std::enable_if< std::is_integral< T >::value &&(sizeof(T)<=4), uint32_t >::type calcHashCode(uint32_t seedValue, T value)
Definition: HashCodeUtil.h:43
uint32_t convertSizeToUInt32(size_t value)
ArrayType
Definition: Array.h:348
@ ALIGNED_AUTO
Definition: Array.h:353
@ ALIGNED
Definition: Array.h:351
@ IMPLICIT
Definition: Array.h:350
@ NORMAL
Definition: Array.h:349
@ AUTO
Definition: Array.h:352
size_t bitSizeOf(T value)