Zserio C++ runtime library  1.0.0
Built for Zserio 2.13.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/Traits.h"
14 #include "zserio/UniquePtr.h"
15 #include "zserio/SizeConvertUtil.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, int>::type = 0>
95 void packedArrayTraitsInitContext(const OWNER_TYPE& owner, PACKING_CONTEXT& context,
96  typename PACKED_ARRAY_TRAITS::ElementType element)
97 {
98  PACKED_ARRAY_TRAITS::initContext(owner, context, element);
99 }
100 
101 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
102  typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
103 void packedArrayTraitsInitContext(const OWNER_TYPE&, PACKING_CONTEXT& context,
104  typename PACKED_ARRAY_TRAITS::ElementType element)
105 {
106  PACKED_ARRAY_TRAITS::initContext(context, element);
107 }
108 
109 // calls the bitSizeOf method properly on array traits which have constant bit size
110 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
111  typename std::enable_if<
112  ARRAY_TRAITS::IS_BITSIZEOF_CONSTANT && has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
113 size_t arrayTraitsConstBitSizeOf(const OWNER_TYPE& owner)
114 {
115  return ARRAY_TRAITS::bitSizeOf(owner);
116 }
117 
118 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
119  typename std::enable_if<
120  ARRAY_TRAITS::IS_BITSIZEOF_CONSTANT && !has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
121 size_t arrayTraitsConstBitSizeOf(const OWNER_TYPE&)
122 {
123  return ARRAY_TRAITS::bitSizeOf();
124 }
125 
126 // calls the bitSizeOf method properly on array traits which haven't constant bit size
127 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
128  typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
129 size_t arrayTraitsBitSizeOf(const OWNER_TYPE& owner, size_t bitPosition,
130  const typename ARRAY_TRAITS::ElementType& element)
131 {
132  return ARRAY_TRAITS::bitSizeOf(owner, bitPosition, element);
133 }
134 
135 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
136  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
137 size_t arrayTraitsBitSizeOf(const OWNER_TYPE&, size_t bitPosition,
138  const typename ARRAY_TRAITS::ElementType& element)
139 {
140  return ARRAY_TRAITS::bitSizeOf(bitPosition, element);
141 }
142 
143 // calls the bitSizeOf method properly on packed array traits which haven't constant bit size
144 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
145  typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
146 size_t packedArrayTraitsBitSizeOf(const OWNER_TYPE& owner, PACKING_CONTEXT& context,
147  size_t bitPosition, const typename PACKED_ARRAY_TRAITS::ElementType& element)
148 {
149  return PACKED_ARRAY_TRAITS::bitSizeOf(owner, context, bitPosition, element);
150 }
151 
152 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
153  typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
154 size_t packedArrayTraitsBitSizeOf(const OWNER_TYPE&, PACKING_CONTEXT& context, size_t bitPosition,
155  const typename PACKED_ARRAY_TRAITS::ElementType& element)
156 {
157  return PACKED_ARRAY_TRAITS::bitSizeOf(context, bitPosition, element);
158 }
159 
160 // calls the initializeOffsets method properly on array traits
161 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
162  typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
163 size_t arrayTraitsInitializeOffsets(OWNER_TYPE& owner, size_t bitPosition,
164  typename ARRAY_TRAITS::ElementType& element)
165 {
166  return ARRAY_TRAITS::initializeOffsets(owner, bitPosition, element);
167 }
168 
169 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
170  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
171  !std::is_scalar<typename ARRAY_TRAITS::ElementType>::value, int>::type = 0>
172 size_t arrayTraitsInitializeOffsets(OWNER_TYPE&, size_t bitPosition,
173  const typename ARRAY_TRAITS::ElementType& element)
174 {
175  return ARRAY_TRAITS::initializeOffsets(bitPosition, element);
176 }
177 
178 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
179  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
180  std::is_scalar<typename ARRAY_TRAITS::ElementType>::value, int>::type = 0>
181 size_t arrayTraitsInitializeOffsets(OWNER_TYPE&, size_t bitPosition, typename ARRAY_TRAITS::ElementType element)
182 {
183  return ARRAY_TRAITS::initializeOffsets(bitPosition, element);
184 }
185 
186 // calls the initializeOffsets method properly on packed array traits
187 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
188  typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
189 size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE& owner, PACKING_CONTEXT& context,
190  size_t bitPosition, typename PACKED_ARRAY_TRAITS::ElementType& element)
191 {
192  return PACKED_ARRAY_TRAITS::initializeOffsets(owner, context, bitPosition, element);
193 }
194 
195 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
196  typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
197  !std::is_scalar<typename PACKED_ARRAY_TRAITS::ElementType>::value, int>::type = 0>
198 size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE&, PACKING_CONTEXT& context,
199  size_t bitPosition, const typename PACKED_ARRAY_TRAITS::ElementType& element)
200 {
201  return PACKED_ARRAY_TRAITS::initializeOffsets(context, bitPosition, element);
202 }
203 
204 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
205  typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
206  std::is_scalar<typename PACKED_ARRAY_TRAITS::ElementType>::value, int>::type = 0>
207 size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE&, PACKING_CONTEXT& context,
208  size_t bitPosition, typename PACKED_ARRAY_TRAITS::ElementType element)
209 {
210  return PACKED_ARRAY_TRAITS::initializeOffsets(context, bitPosition, element);
211 }
212 
213 // calls the read method properly on array traits
214 template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
215  typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value &&
216  !has_allocator<ARRAY_TRAITS>::value, int>::type = 0>
217 void arrayTraitsRead(const OWNER_TYPE& owner, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
218 {
219  rawArray.push_back(ARRAY_TRAITS::read(owner, in, index));
220 }
221 
222 template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
223  typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value &&
224  has_allocator<ARRAY_TRAITS>::value, int>::type = 0>
225 void arrayTraitsRead(OWNER_TYPE& owner, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
226 {
227  ARRAY_TRAITS::read(owner, rawArray, in, index);
228 }
229 
230 template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
231  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
232  !has_allocator<ARRAY_TRAITS>::value, int>::type = 0>
233 void arrayTraitsRead(const OWNER_TYPE&, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
234 {
235  rawArray.push_back(ARRAY_TRAITS::read(in, index));
236 }
237 
238 template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
239  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
240  has_allocator<ARRAY_TRAITS>::value, int>::type = 0>
241 void arrayTraitsRead(const OWNER_TYPE&, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
242 {
243  ARRAY_TRAITS::read(rawArray, in, index);
244 }
245 
246 // calls the read method properly on packed array traits
247 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY, typename PACKING_CONTEXT,
248  typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value &&
249  has_allocator<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
250 void packedArrayTraitsRead(OWNER_TYPE& owner, RAW_ARRAY& rawArray, PACKING_CONTEXT& context,
251  BitStreamReader& in, size_t index)
252 {
253  PACKED_ARRAY_TRAITS::read(owner, rawArray, context, in, index);
254 }
255 
256 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY, typename PACKING_CONTEXT,
257  typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value &&
258  !has_allocator<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
259 void packedArrayTraitsRead(const OWNER_TYPE& owner, RAW_ARRAY& rawArray, PACKING_CONTEXT& context,
260  BitStreamReader& in, size_t index)
261 {
262  rawArray.push_back(PACKED_ARRAY_TRAITS::read(owner, context, in, index));
263 }
264 
265 // note: types which doesn't have owner and have allocator are never packed (e.g. string, bytes ...)
266 // and thus such specialization is not needed
267 
268 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY, typename PACKING_CONTEXT,
269  typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
270  !has_allocator<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
271 void packedArrayTraitsRead(const OWNER_TYPE&, RAW_ARRAY& rawArray, PACKING_CONTEXT& context,
272  BitStreamReader& in, size_t index)
273 {
274  rawArray.push_back(PACKED_ARRAY_TRAITS::read(context, in, index));
275 }
276 
277 // call the write method properly on array traits
278 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
279  typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
280 void arrayTraitsWrite(const OWNER_TYPE& owner,
281  BitStreamWriter& out, const typename ARRAY_TRAITS::ElementType& element)
282 {
283  ARRAY_TRAITS::write(owner, out, element);
284 }
285 
286 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
287  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
288 void arrayTraitsWrite(const OWNER_TYPE&,
289  BitStreamWriter& out, const typename ARRAY_TRAITS::ElementType& element)
290 {
291  ARRAY_TRAITS::write(out, element);
292 }
293 
294 // call the write method properly on packed array traits
295 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
296  typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
297 void packedArrayTraitsWrite(const OWNER_TYPE& owner, PACKING_CONTEXT& context,
298  BitStreamWriter& out, const typename PACKED_ARRAY_TRAITS::ElementType& element)
299 {
300  PACKED_ARRAY_TRAITS::write(owner, context, out, element);
301 }
302 
303 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
304  typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
305 void packedArrayTraitsWrite(const OWNER_TYPE&, PACKING_CONTEXT& context,
306  BitStreamWriter& out, const typename PACKED_ARRAY_TRAITS::ElementType& element)
307 {
308  PACKED_ARRAY_TRAITS::write(context, out, element);
309 }
310 
311 } // namespace detail
312 
317 {
323 };
324 
332 template <typename RAW_ARRAY, typename ARRAY_TRAITS, ArrayType ARRAY_TYPE,
333  typename ARRAY_EXPRESSIONS = detail::DummyArrayExpressions>
334 class Array
335 {
336 public:
338  using RawArray = RAW_ARRAY;
339 
341  using ArrayTraits = ARRAY_TRAITS;
342 
344  using ArrayExpressions = ARRAY_EXPRESSIONS;
345 
352  using OwnerType = typename detail::array_owner_type<ArrayTraits, ArrayExpressions>::type;
353 
355  using allocator_type = typename RawArray::allocator_type;
356 
362  explicit Array(const allocator_type& allocator = allocator_type()) :
363  m_rawArray(allocator)
364  {}
365 
371  explicit Array(const RawArray& rawArray) :
372  m_rawArray(rawArray)
373  {}
374 
380  explicit Array(RawArray&& rawArray) :
381  m_rawArray(std::move(rawArray))
382  {}
383 
389  ~Array() = default;
390  Array(const Array& other) = default;
391  Array& operator=(const Array& other) = default;
392  Array(Array&& other) = default;
393  Array& operator=(Array&& other) = default;
405  template <typename T = typename RAW_ARRAY::value_type,
406  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
407  Array(NoInitT, const Array& other) :
408  Array(std::allocator_traits<allocator_type>::select_on_container_copy_construction(
409  other.m_rawArray.get_allocator()))
410  {
411  m_rawArray.reserve(other.m_rawArray.size());
412  for (const auto& value : other.m_rawArray)
413  m_rawArray.emplace_back(NoInit, value);
414  }
415 
423  template <typename T = typename RAW_ARRAY::value_type,
424  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
425  Array& assign(NoInitT, const Array& other)
426  {
427  const RawArray rawArray(other.m_rawArray.get_allocator());
428  m_rawArray = rawArray; // copy assign to get correct allocator propagation behaviour
429  m_rawArray.reserve(other.m_rawArray.size());
430  for (const auto& value : other.m_rawArray)
431  m_rawArray.emplace_back(NoInit, value);
432 
433  return *this;
434  }
435 
443  template <typename T = typename RAW_ARRAY::value_type,
444  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
445  Array(NoInitT, Array&& other) :
446  Array(std::move(other))
447  {
448  }
449 
458  template <typename T = typename RAW_ARRAY::value_type,
459  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
461  {
462  return operator=(std::move(other));
463  }
464 
471  Array(PropagateAllocatorT, const Array& other, const allocator_type& allocator) :
472  m_rawArray(allocatorPropagatingCopy(other.m_rawArray, allocator))
473  {}
474 
482  template <typename T = typename RAW_ARRAY::value_type,
483  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
484  Array(PropagateAllocatorT, NoInitT, const Array& other, const allocator_type& allocator) :
485  m_rawArray(allocatorPropagatingCopy(NoInit, other.m_rawArray, allocator))
486  {}
487 
495  bool operator==(const Array& other) const
496  {
497  return m_rawArray == other.m_rawArray;
498  }
499 
507  bool operator<(const Array& other) const
508  {
509  return m_rawArray < other.m_rawArray;
510  }
511 
517  uint32_t hashCode() const
518  {
519  return calcHashCode(HASH_SEED, m_rawArray);
520  }
521 
527  const RawArray& getRawArray() const
528  {
529  return m_rawArray;
530  }
531 
538  {
539  return m_rawArray;
540  }
541 
547  template <typename ARRAY_EXPRESSIONS_ = ArrayExpressions,
548  typename std::enable_if<has_initialize_element<ARRAY_EXPRESSIONS_>::value, int>::type = 0>
550  {
551  size_t index = 0;
552  for (auto&& element : m_rawArray)
553  {
554  ArrayExpressions::initializeElement(owner, element, index);
555  index++;
556  }
557  }
558 
568  template <typename OWNER_TYPE_ = OwnerType,
569  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
570  size_t bitSizeOf(size_t bitPosition) const
571  {
572  return bitSizeOfImpl(detail::DummyArrayOwner(), bitPosition);
573  }
574 
585  template <typename OWNER_TYPE_ = OwnerType,
586  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
587  size_t bitSizeOf(const OwnerType& owner, size_t bitPosition) const
588  {
589  return bitSizeOfImpl(owner, bitPosition);
590  }
591 
601  template <typename OWNER_TYPE_ = OwnerType,
602  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
603  size_t initializeOffsets(size_t bitPosition)
604  {
605  detail::DummyArrayOwner owner;
606  return initializeOffsetsImpl(owner, 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 initializeOffsets(OwnerType& owner, size_t bitPosition)
622  {
623  return initializeOffsetsImpl(owner, bitPosition);
624  }
625 
634  template <typename OWNER_TYPE_ = OwnerType,
635  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
636  void read(BitStreamReader& in, size_t arrayLength = 0)
637  {
638  detail::DummyArrayOwner owner;
639  readImpl(owner, in, arrayLength);
640  }
641 
651  template <typename OWNER_TYPE_ = OwnerType,
652  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
653  void read(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
654  {
655  readImpl(owner, in, arrayLength);
656  }
657 
665  template <typename OWNER_TYPE_ = OwnerType,
666  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
667  void write(BitStreamWriter& out) const
668  {
669  writeImpl(detail::DummyArrayOwner(), out);
670  }
671 
680  template <typename OWNER_TYPE_ = OwnerType,
681  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
682  void write(const OwnerType& owner, BitStreamWriter& out) const
683  {
684  writeImpl(owner, out);
685  }
686 
696  template <typename OWNER_TYPE_ = OwnerType,
697  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
698  size_t bitSizeOfPacked(size_t bitPosition) const
699  {
700  return bitSizeOfPackedImpl(detail::DummyArrayOwner(), bitPosition);
701  }
702 
713  template <typename OWNER_TYPE_ = OwnerType,
714  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
715  size_t bitSizeOfPacked(const OwnerType& ownerType, size_t bitPosition) const
716  {
717  return bitSizeOfPackedImpl(ownerType, bitPosition);
718  }
719 
729  template <typename OWNER_TYPE_ = OwnerType,
730  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
731  size_t initializeOffsetsPacked(size_t bitPosition)
732  {
733  detail::DummyArrayOwner owner;
734  return initializeOffsetsPackedImpl(owner, 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 initializeOffsetsPacked(OwnerType& owner, size_t bitPosition)
750  {
751  return initializeOffsetsPackedImpl(owner, bitPosition);
752  }
753 
762  template <typename OWNER_TYPE_ = OwnerType,
763  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
764  void readPacked(BitStreamReader& in, size_t arrayLength = 0)
765  {
766  detail::DummyArrayOwner owner;
767  readPackedImpl(owner, in, arrayLength);
768  }
769 
779  template <typename OWNER_TYPE_ = OwnerType,
780  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
781  void readPacked(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
782  {
783  readPackedImpl(owner, in, arrayLength);
784  }
785 
793  template <typename OWNER_TYPE_ = OwnerType,
794  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
795  void writePacked(BitStreamWriter& out) const
796  {
797  writePackedImpl(detail::DummyArrayOwner(), out);
798  }
799 
808  template <typename OWNER_TYPE_ = OwnerType,
809  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
810  void writePacked(const OwnerType& owner, BitStreamWriter& out) const
811  {
812  writePackedImpl(owner, out);
813  }
814 
815 private:
816  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
817  typename std::enable_if<
818  ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO, int>::type = 0>
819  static void addBitSizeOfArrayLength(size_t&, size_t)
820  {}
821 
822  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
823  typename std::enable_if<
824  ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
825  static void addBitSizeOfArrayLength(size_t& bitPosition, size_t arrayLength)
826  {
827  bitPosition += bitSizeOfVarSize(convertSizeToUInt32(arrayLength));
828  }
829 
830  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
831  typename std::enable_if<
832  ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO, int>::type = 0>
833  static void alignBitPosition(size_t&)
834  {}
835 
836  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
837  typename std::enable_if<
838  ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
839  static void alignBitPosition(size_t& bitPosition)
840  {
841  bitPosition = alignTo(8, bitPosition);
842  }
843 
844  template <typename IO, typename OWNER_TYPE, ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
845  typename std::enable_if<
846  ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO, int>::type = 0>
847  static void alignAndCheckOffset(IO&, OWNER_TYPE&, size_t)
848  {}
849 
850  template <typename IO, typename OWNER_TYPE, ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
851  typename std::enable_if<
852  ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
853  static void alignAndCheckOffset(IO& io, OWNER_TYPE& owner, size_t index)
854  {
855  io.alignTo(8);
856  detail::checkOffset<ArrayExpressions>(owner, index, io.getBitPosition() / 8);
857  }
858 
859  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
860  typename std::enable_if<
861  ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO, int>::type = 0>
862  static void initializeOffset(OwnerType&, size_t, size_t&)
863  {}
864 
865  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
866  typename std::enable_if<
867  ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
868  static void initializeOffset(OwnerType& owner, size_t index, size_t& bitPosition)
869  {
870  bitPosition = alignTo(8, bitPosition);
871  detail::initializeOffset<ArrayExpressions>(owner, index, bitPosition / 8);
872  }
873 
874  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
875  typename std::enable_if<
876  ARRAY_TYPE_ != ArrayType::AUTO &&
877  ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO &&
878  ARRAY_TYPE_ != ArrayType::IMPLICIT, int>::type = 0>
879  static size_t readArrayLength(OwnerType&, BitStreamReader&, size_t arrayLength)
880  {
881  return arrayLength;
882  }
883 
884  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
885  typename std::enable_if<
886  ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
887  static size_t readArrayLength(OwnerType&, BitStreamReader& in, size_t)
888  {
889  return in.readVarSize();
890  }
891 
892  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
893  typename std::enable_if<ARRAY_TYPE_ == ArrayType::IMPLICIT, int>::type = 0>
894  static size_t readArrayLength(OwnerType& owner, BitStreamReader& in, size_t)
895  {
896  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT || ArrayTraits::IS_BITSIZEOF_CONSTANT,
897  "Implicit array elements must have constant bit size!");
898 
899  const size_t remainingBits = in.getBufferBitSize() - in.getBitPosition();
900  return remainingBits / detail::arrayTraitsConstBitSizeOf<ArrayTraits>(owner);
901  }
902 
903  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
904  typename std::enable_if<
905  ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO, int>::type = 0>
906  static void writeArrayLength(BitStreamWriter&, size_t)
907  {}
908 
909  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
910  typename std::enable_if<
911  ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
912  static void writeArrayLength(BitStreamWriter& out, size_t arrayLength)
913  {
914  out.writeVarSize(convertSizeToUInt32(arrayLength));
915  }
916 
917  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
918  typename std::enable_if<
919  ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO, int>::type = 0>
920  static size_t constBitSizeOfElements(size_t, size_t arrayLength, size_t elementBitSize)
921  {
922  return arrayLength * elementBitSize;
923  }
924 
925  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
926  typename std::enable_if<
927  ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
928  static size_t constBitSizeOfElements(size_t bitPosition, size_t arrayLength, size_t elementBitSize)
929  {
930  size_t endBitPosition = alignTo(8, bitPosition);
931  endBitPosition += elementBitSize + (arrayLength - 1) * alignTo(8, elementBitSize);
932 
933  return endBitPosition - bitPosition;
934  }
935 
936  template <typename ARRAY_TRAITS_ = ArrayTraits,
937  typename std::enable_if<ARRAY_TRAITS_::IS_BITSIZEOF_CONSTANT, int>::type = 0>
938  size_t bitSizeOfImpl(const OwnerType& owner, size_t bitPosition) const
939  {
940  size_t endBitPosition = bitPosition;
941 
942  const size_t arrayLength = m_rawArray.size();
943  addBitSizeOfArrayLength(endBitPosition, arrayLength);
944 
945  if (arrayLength > 0)
946  {
947  const size_t elementBitSize = detail::arrayTraitsConstBitSizeOf<ArrayTraits>(owner);
948  endBitPosition += constBitSizeOfElements(endBitPosition, arrayLength, elementBitSize);
949  }
950 
951  return endBitPosition - bitPosition;
952  }
953 
954  template <typename ARRAY_TRAITS_ = ArrayTraits,
955  typename std::enable_if<!ARRAY_TRAITS_::IS_BITSIZEOF_CONSTANT, int>::type = 0>
956  size_t bitSizeOfImpl(const OwnerType& owner, size_t bitPosition) const
957  {
958  size_t endBitPosition = bitPosition;
959 
960  const size_t arrayLength = m_rawArray.size();
961  addBitSizeOfArrayLength(endBitPosition, arrayLength);
962 
963  for (size_t index = 0; index < arrayLength; ++index)
964  {
965  alignBitPosition(endBitPosition);
966  endBitPosition += detail::arrayTraitsBitSizeOf<ArrayTraits>(
967  owner, endBitPosition, m_rawArray[index]);
968  }
969 
970  return endBitPosition - bitPosition;
971  }
972 
973  size_t initializeOffsetsImpl(OwnerType& owner, size_t bitPosition)
974  {
975  size_t endBitPosition = bitPosition;
976 
977  const size_t arrayLength = m_rawArray.size();
978  addBitSizeOfArrayLength(endBitPosition, arrayLength);
979 
980  for (size_t index = 0; index < arrayLength; ++index)
981  {
982  initializeOffset(owner, index, endBitPosition);
983  endBitPosition = detail::arrayTraitsInitializeOffsets<ArrayTraits>(
984  owner, endBitPosition, m_rawArray[index]);
985  }
986 
987  return endBitPosition;
988  }
989 
990  void readImpl(OwnerType& owner, BitStreamReader& in, size_t arrayLength)
991  {
992  size_t readLength = readArrayLength(owner, in, arrayLength);
993 
994  m_rawArray.clear();
995  m_rawArray.reserve(readLength);
996  for (size_t index = 0; index < readLength; ++index)
997  {
998  alignAndCheckOffset(in, owner, index);
999  detail::arrayTraitsRead<ArrayTraits>(owner, m_rawArray, in, index);
1000  }
1001  }
1002 
1003  void writeImpl(const OwnerType& owner, BitStreamWriter& out) const
1004  {
1005  const size_t arrayLength = m_rawArray.size();
1006  writeArrayLength(out, arrayLength);
1007 
1008  for (size_t index = 0; index < arrayLength; ++index)
1009  {
1010  alignAndCheckOffset(out, owner, index);
1011  detail::arrayTraitsWrite<ArrayTraits>(owner, out, m_rawArray[index]);
1012  }
1013  }
1014 
1016 
1017  size_t bitSizeOfPackedImpl(const OwnerType& owner, size_t bitPosition) const
1018  {
1019  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1020 
1021  size_t endBitPosition = bitPosition;
1022 
1023  const size_t arrayLength = m_rawArray.size();
1024  addBitSizeOfArrayLength(endBitPosition, arrayLength);
1025 
1026  if (arrayLength > 0)
1027  {
1028  PackingContext context;
1029 
1030  for (size_t index = 0; index < arrayLength; ++index)
1031  {
1032  detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1033  owner, context, m_rawArray[index]);
1034  }
1035 
1036  for (size_t index = 0; index < arrayLength; ++index)
1037  {
1038  alignBitPosition(endBitPosition);
1039  endBitPosition += detail::packedArrayTraitsBitSizeOf<PackedArrayTraits<ArrayTraits>>(
1040  owner, context, endBitPosition, m_rawArray[index]);
1041  }
1042  }
1043 
1044  return endBitPosition - bitPosition;
1045  }
1046 
1047  size_t initializeOffsetsPackedImpl(OwnerType& owner, size_t bitPosition)
1048  {
1049  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1050 
1051  size_t endBitPosition = bitPosition;
1052 
1053  const size_t arrayLength = m_rawArray.size();
1054  addBitSizeOfArrayLength(endBitPosition, arrayLength);
1055 
1056  if (arrayLength > 0)
1057  {
1058  PackingContext context;
1059 
1060  for (size_t index = 0; index < arrayLength; ++index)
1061  {
1062  detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1063  owner, context, m_rawArray[index]);
1064  }
1065 
1066  for (size_t index = 0; index < arrayLength; ++index)
1067  {
1068  initializeOffset(owner, index, endBitPosition);
1069  endBitPosition = detail::packedArrayTraitsInitializeOffsets<PackedArrayTraits<ArrayTraits>>(
1070  owner, context, endBitPosition, m_rawArray[index]);
1071  }
1072  }
1073 
1074  return endBitPosition;
1075  }
1076 
1077  void readPackedImpl(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
1078  {
1079  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1080 
1081  size_t readLength = readArrayLength(owner, in, arrayLength);
1082 
1083  m_rawArray.clear();
1084 
1085  if (readLength > 0)
1086  {
1087  m_rawArray.reserve(readLength);
1088 
1089  PackingContext context;
1090 
1091  for (size_t index = 0; index < readLength; ++index)
1092  {
1093  alignAndCheckOffset(in, owner, index);
1094  detail::packedArrayTraitsRead<PackedArrayTraits<ArrayTraits>>(
1095  owner, m_rawArray, context, in, index);
1096  }
1097  }
1098  }
1099 
1100  void writePackedImpl(const OwnerType& owner, BitStreamWriter& out) const
1101  {
1102  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1103 
1104  const size_t arrayLength = m_rawArray.size();
1105  writeArrayLength(out, arrayLength);
1106 
1107  if (arrayLength > 0)
1108  {
1109  PackingContext context;
1110 
1111  for (size_t index = 0; index < arrayLength; ++index)
1112  {
1113  detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1114  owner, context, m_rawArray[index]);
1115  }
1116 
1117  for (size_t index = 0; index < arrayLength; ++index)
1118  {
1119  alignAndCheckOffset(out, owner, index);
1120  detail::packedArrayTraitsWrite<PackedArrayTraits<ArrayTraits>>(
1121  owner, context, out, m_rawArray[index]);
1122  }
1123  }
1124  }
1125 
1126  RawArray m_rawArray;
1127 };
1128 
1133 template <typename ARRAY, typename RAW_ARRAY>
1134 ARRAY createOptionalArray(RAW_ARRAY&& rawArray)
1135 {
1136  return ARRAY(std::forward<RAW_ARRAY>(rawArray));
1137 }
1138 
1142 template <typename ARRAY>
1144 {
1145  return NullOpt;
1146 }
1147 
1148 } // namespace zserio
1149 
1150 #endif // ZSERIO_ARRAY_H_INC
size_t initializeOffsets(OwnerType &owner, size_t bitPosition)
Definition: Array.h:621
size_t alignTo(size_t alignmentValue, size_t bitPosition)
ArrayType
Definition: Array.h:316
Array(NoInitT, const Array &other)
Definition: Array.h:407
Array(const allocator_type &allocator=allocator_type())
Definition: Array.h:362
typename detail::array_owner_type< ArrayTraits, ArrayExpressions >::type OwnerType
Definition: Array.h:352
Array(const RawArray &rawArray)
Definition: Array.h:371
constexpr NoInitT NoInit
Definition: NoInit.h:18
bool operator<(const Array &other) const
Definition: Array.h:507
void write(const OwnerType &owner, BitStreamWriter &out) const
Definition: Array.h:682
Array & assign(NoInitT, Array &&other)
Definition: Array.h:460
size_t initializeOffsetsPacked(size_t bitPosition)
Definition: Array.h:731
Array(NoInitT, Array &&other)
Definition: Array.h:445
size_t initializeOffsets(size_t bitPosition)
Definition: Array.h:603
size_t bitSizeOf(const OwnerType &owner, size_t bitPosition) const
Definition: Array.h:587
void writeVarSize(uint32_t data)
T allocatorPropagatingCopy(const T &source, const ALLOC &allocator)
size_t bitSizeOfVarSize(uint32_t value)
uint32_t convertSizeToUInt32(size_t value)
ARRAY_TRAITS ArrayTraits
Definition: Array.h:341
T read(BitStreamReader &in)
void writePacked(const OwnerType &owner, BitStreamWriter &out) const
Definition: Array.h:810
size_t bitSizeOfPacked(const OwnerType &ownerType, size_t bitPosition) const
Definition: Array.h:715
size_t bitSizeOf(size_t bitPosition) const
Definition: Array.h:570
RAW_ARRAY RawArray
Definition: Array.h:338
void write(BitStreamWriter &out, T value)
BitPosType getBitPosition() const
size_t initializeOffsetsPacked(OwnerType &owner, size_t bitPosition)
Definition: Array.h:749
void readPacked(OwnerType &owner, BitStreamReader &in, size_t arrayLength=0)
Definition: Array.h:781
constexpr NullOptType NullOpt
void readPacked(BitStreamReader &in, size_t arrayLength=0)
Definition: Array.h:764
size_t bitSizeOfPacked(size_t bitPosition) const
Definition: Array.h:698
void writePacked(BitStreamWriter &out) const
Definition: Array.h:795
Array & assign(NoInitT, const Array &other)
Definition: Array.h:425
void read(OwnerType &owner, BitStreamReader &in, size_t arrayLength=0)
Definition: Array.h:653
typename RawArray::allocator_type allocator_type
Definition: Array.h:355
Array(PropagateAllocatorT, const Array &other, const allocator_type &allocator)
Definition: Array.h:471
size_t initializeOffsets(size_t bitPosition, T value)
bool operator==(const Array &other) const
Definition: Array.h:495
std::enable_if< std::is_integral< T >::value &&(sizeof(T)<=4), uint32_t >::type calcHashCode(uint32_t seedValue, T value)
Definition: HashCodeUtil.h:43
void write(BitStreamWriter &out) const
Definition: Array.h:667
uint32_t hashCode() const
Definition: Array.h:517
ARRAY createOptionalArray(RAW_ARRAY &&rawArray)
Definition: Array.h:1134
ARRAY_EXPRESSIONS ArrayExpressions
Definition: Array.h:344
size_t getBufferBitSize() const
const RawArray & getRawArray() const
Definition: Array.h:527
size_t bitSizeOf(T value)
Array(PropagateAllocatorT, NoInitT, const Array &other, const allocator_type &allocator)
Definition: Array.h:484
void initializeElements(OwnerType &owner)
Definition: Array.h:549
RawArray & getRawArray()
Definition: Array.h:537
void read(BitStreamReader &in, size_t arrayLength=0)
Definition: Array.h:636
Array(RawArray &&rawArray)
Definition: Array.h:380