Zserio C++ runtime library  1.0.2
Built for Zserio 2.14.1
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, int>::type = 0>
95 void packedArrayTraitsInitContext(
96  const OWNER_TYPE& owner, PACKING_CONTEXT& context, 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(
104  const OWNER_TYPE&, PACKING_CONTEXT& context, 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<ARRAY_TRAITS::IS_BITSIZEOF_CONSTANT && has_owner_type<ARRAY_TRAITS>::value,
112  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<ARRAY_TRAITS::IS_BITSIZEOF_CONSTANT && !has_owner_type<ARRAY_TRAITS>::value,
120  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(
130  const OWNER_TYPE& owner, size_t bitPosition, 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(
138  const OWNER_TYPE&, size_t bitPosition, 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, size_t bitPosition,
147  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(
164  OWNER_TYPE& owner, size_t bitPosition, 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,
172  int>::type = 0>
173 size_t arrayTraitsInitializeOffsets(
174  OWNER_TYPE&, size_t bitPosition, const typename ARRAY_TRAITS::ElementType& element)
175 {
176  return ARRAY_TRAITS::initializeOffsets(bitPosition, element);
177 }
178 
179 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
180  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
181  std::is_scalar<typename ARRAY_TRAITS::ElementType>::value,
182  int>::type = 0>
183 size_t arrayTraitsInitializeOffsets(OWNER_TYPE&, size_t bitPosition, typename ARRAY_TRAITS::ElementType element)
184 {
185  return ARRAY_TRAITS::initializeOffsets(bitPosition, element);
186 }
187 
188 // calls the initializeOffsets method properly on packed array traits
189 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
190  typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
191 size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE& owner, PACKING_CONTEXT& context, size_t bitPosition,
192  typename PACKED_ARRAY_TRAITS::ElementType& element)
193 {
194  return PACKED_ARRAY_TRAITS::initializeOffsets(owner, context, bitPosition, element);
195 }
196 
197 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
198  typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
199  !std::is_scalar<typename PACKED_ARRAY_TRAITS::ElementType>::value,
200  int>::type = 0>
201 size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE&, PACKING_CONTEXT& context, size_t bitPosition,
202  const typename PACKED_ARRAY_TRAITS::ElementType& element)
203 {
204  return PACKED_ARRAY_TRAITS::initializeOffsets(context, bitPosition, element);
205 }
206 
207 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
208  typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
209  std::is_scalar<typename PACKED_ARRAY_TRAITS::ElementType>::value,
210  int>::type = 0>
211 size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE&, PACKING_CONTEXT& context, size_t bitPosition,
212  typename PACKED_ARRAY_TRAITS::ElementType element)
213 {
214  return PACKED_ARRAY_TRAITS::initializeOffsets(context, bitPosition, element);
215 }
216 
217 // calls the read method properly on array traits
218 template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
219  typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value && !has_allocator<ARRAY_TRAITS>::value,
220  int>::type = 0>
221 void arrayTraitsRead(const OWNER_TYPE& owner, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
222 {
223  rawArray.push_back(ARRAY_TRAITS::read(owner, in, index));
224 }
225 
226 template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
227  typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value && has_allocator<ARRAY_TRAITS>::value,
228  int>::type = 0>
229 void arrayTraitsRead(OWNER_TYPE& owner, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
230 {
231  ARRAY_TRAITS::read(owner, rawArray, in, index);
232 }
233 
234 template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
235  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value && !has_allocator<ARRAY_TRAITS>::value,
236  int>::type = 0>
237 void arrayTraitsRead(const OWNER_TYPE&, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
238 {
239  rawArray.push_back(ARRAY_TRAITS::read(in, index));
240 }
241 
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&, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
246 {
247  ARRAY_TRAITS::read(rawArray, in, index);
248 }
249 
250 // calls the read method properly on packed array traits
251 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY, typename PACKING_CONTEXT,
252  typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value &&
253  has_allocator<PACKED_ARRAY_TRAITS>::value,
254  int>::type = 0>
255 void packedArrayTraitsRead(
256  OWNER_TYPE& owner, RAW_ARRAY& rawArray, PACKING_CONTEXT& context, BitStreamReader& in, size_t index)
257 {
258  PACKED_ARRAY_TRAITS::read(owner, rawArray, context, in, index);
259 }
260 
261 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY, typename PACKING_CONTEXT,
262  typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value &&
263  !has_allocator<PACKED_ARRAY_TRAITS>::value,
264  int>::type = 0>
265 void packedArrayTraitsRead(const OWNER_TYPE& owner, RAW_ARRAY& rawArray, PACKING_CONTEXT& context,
266  BitStreamReader& in, size_t index)
267 {
268  rawArray.push_back(PACKED_ARRAY_TRAITS::read(owner, context, in, index));
269 }
270 
271 // note: types which doesn't have owner and have allocator are never packed (e.g. string, bytes ...)
272 // and thus such specialization is not needed
273 
274 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY, typename PACKING_CONTEXT,
275  typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
276  !has_allocator<PACKED_ARRAY_TRAITS>::value,
277  int>::type = 0>
278 void packedArrayTraitsRead(
279  const OWNER_TYPE&, RAW_ARRAY& rawArray, PACKING_CONTEXT& context, BitStreamReader& in, size_t index)
280 {
281  rawArray.push_back(PACKED_ARRAY_TRAITS::read(context, in, index));
282 }
283 
284 // call the write method properly on array traits
285 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
286  typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
287 void arrayTraitsWrite(
288  const OWNER_TYPE& owner, BitStreamWriter& out, const typename ARRAY_TRAITS::ElementType& element)
289 {
290  ARRAY_TRAITS::write(owner, out, element);
291 }
292 
293 template <typename ARRAY_TRAITS, typename OWNER_TYPE,
294  typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
295 void arrayTraitsWrite(
296  const OWNER_TYPE&, BitStreamWriter& out, const typename ARRAY_TRAITS::ElementType& element)
297 {
298  ARRAY_TRAITS::write(out, element);
299 }
300 
301 // call the write method properly on packed array traits
302 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
303  typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
304 void packedArrayTraitsWrite(const OWNER_TYPE& owner, PACKING_CONTEXT& context, BitStreamWriter& out,
305  const typename PACKED_ARRAY_TRAITS::ElementType& element)
306 {
307  PACKED_ARRAY_TRAITS::write(owner, context, out, element);
308 }
309 
310 template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
311  typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
312 void packedArrayTraitsWrite(const OWNER_TYPE&, PACKING_CONTEXT& context, BitStreamWriter& out,
313  const typename PACKED_ARRAY_TRAITS::ElementType& element)
314 {
315  PACKED_ARRAY_TRAITS::write(context, out, element);
316 }
317 
318 } // namespace detail
319 
324 {
329  ALIGNED_AUTO
330 };
331 
339 template <typename RAW_ARRAY, typename ARRAY_TRAITS, ArrayType ARRAY_TYPE,
340  typename ARRAY_EXPRESSIONS = detail::DummyArrayExpressions>
341 class Array
342 {
343 public:
345  using RawArray = RAW_ARRAY;
346 
348  using ArrayTraits = ARRAY_TRAITS;
349 
351  using ArrayExpressions = ARRAY_EXPRESSIONS;
352 
359  using OwnerType = typename detail::array_owner_type<ArrayTraits, ArrayExpressions>::type;
360 
362  using allocator_type = typename RawArray::allocator_type;
363 
369  explicit Array(const allocator_type& allocator = allocator_type()) :
370  m_rawArray(allocator)
371  {}
372 
378  explicit Array(const RawArray& rawArray) :
379  m_rawArray(rawArray)
380  {}
381 
387  explicit Array(RawArray&& rawArray) :
388  m_rawArray(std::move(rawArray))
389  {}
390 
396  ~Array() = default;
397  Array(const Array& other) = default;
398  Array& operator=(const Array& other) = default;
399  Array(Array&& other) = default;
400  Array& operator=(Array&& other) = default;
412  template <typename T = typename RAW_ARRAY::value_type,
413  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
414  Array(NoInitT, const Array& other) :
415  Array(std::allocator_traits<allocator_type>::select_on_container_copy_construction(
416  other.m_rawArray.get_allocator()))
417  {
418  m_rawArray.reserve(other.m_rawArray.size());
419  for (const auto& value : other.m_rawArray)
420  {
421  m_rawArray.emplace_back(NoInit, value);
422  }
423  }
424 
432  template <typename T = typename RAW_ARRAY::value_type,
433  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
434  Array& assign(NoInitT, const Array& other)
435  {
436  const RawArray rawArray(other.m_rawArray.get_allocator());
437  m_rawArray = rawArray; // copy assign to get correct allocator propagation behaviour
438  m_rawArray.reserve(other.m_rawArray.size());
439  for (const auto& value : other.m_rawArray)
440  {
441  m_rawArray.emplace_back(NoInit, value);
442  }
443 
444  return *this;
445  }
446 
454  template <typename T = typename RAW_ARRAY::value_type,
455  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
456  Array(NoInitT, Array&& other) :
457  Array(std::move(other))
458  {}
459 
468  template <typename T = typename RAW_ARRAY::value_type,
469  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
471  {
472  return operator=(std::move(other));
473  }
474 
481  Array(PropagateAllocatorT, const Array& other, const allocator_type& allocator) :
482  m_rawArray(allocatorPropagatingCopy(other.m_rawArray, allocator))
483  {}
484 
492  template <typename T = typename RAW_ARRAY::value_type,
493  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
494  Array(PropagateAllocatorT, NoInitT, const Array& other, const allocator_type& allocator) :
495  m_rawArray(allocatorPropagatingCopy(NoInit, other.m_rawArray, allocator))
496  {}
497 
505  bool operator==(const Array& other) const
506  {
507  return m_rawArray == other.m_rawArray;
508  }
509 
517  bool operator<(const Array& other) const
518  {
519  return m_rawArray < other.m_rawArray;
520  }
521 
527  uint32_t hashCode() const
528  {
529  return calcHashCode(HASH_SEED, m_rawArray);
530  }
531 
537  const RawArray& getRawArray() const
538  {
539  return m_rawArray;
540  }
541 
548  {
549  return m_rawArray;
550  }
551 
557  template <typename ARRAY_EXPRESSIONS_ = ArrayExpressions,
558  typename std::enable_if<has_initialize_element<ARRAY_EXPRESSIONS_>::value, int>::type = 0>
560  {
561  size_t index = 0;
562  for (auto&& element : m_rawArray)
563  {
564  ArrayExpressions::initializeElement(owner, element, index);
565  index++;
566  }
567  }
568 
578  template <typename OWNER_TYPE_ = OwnerType,
579  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
580  size_t bitSizeOf(size_t bitPosition) const
581  {
582  return bitSizeOfImpl(detail::DummyArrayOwner(), bitPosition);
583  }
584 
595  template <typename OWNER_TYPE_ = OwnerType,
596  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
597  size_t bitSizeOf(const OwnerType& owner, size_t bitPosition) const
598  {
599  return bitSizeOfImpl(owner, bitPosition);
600  }
601 
611  template <typename OWNER_TYPE_ = OwnerType,
612  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
613  size_t initializeOffsets(size_t bitPosition)
614  {
615  detail::DummyArrayOwner owner;
616  return initializeOffsetsImpl(owner, bitPosition);
617  }
618 
629  template <typename OWNER_TYPE_ = OwnerType,
630  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
631  size_t initializeOffsets(OwnerType& owner, size_t bitPosition)
632  {
633  return initializeOffsetsImpl(owner, bitPosition);
634  }
635 
644  template <typename OWNER_TYPE_ = OwnerType,
645  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
646  void read(BitStreamReader& in, size_t arrayLength = 0)
647  {
648  detail::DummyArrayOwner owner;
649  readImpl(owner, in, arrayLength);
650  }
651 
661  template <typename OWNER_TYPE_ = OwnerType,
662  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
663  void read(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
664  {
665  readImpl(owner, in, arrayLength);
666  }
667 
675  template <typename OWNER_TYPE_ = OwnerType,
676  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
677  void write(BitStreamWriter& out) const
678  {
679  writeImpl(detail::DummyArrayOwner(), out);
680  }
681 
690  template <typename OWNER_TYPE_ = OwnerType,
691  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
692  void write(const OwnerType& owner, BitStreamWriter& out) const
693  {
694  writeImpl(owner, out);
695  }
696 
706  template <typename OWNER_TYPE_ = OwnerType,
707  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
708  size_t bitSizeOfPacked(size_t bitPosition) const
709  {
710  return bitSizeOfPackedImpl(detail::DummyArrayOwner(), bitPosition);
711  }
712 
723  template <typename OWNER_TYPE_ = OwnerType,
724  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
725  size_t bitSizeOfPacked(const OwnerType& ownerType, size_t bitPosition) const
726  {
727  return bitSizeOfPackedImpl(ownerType, bitPosition);
728  }
729 
739  template <typename OWNER_TYPE_ = OwnerType,
740  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
741  size_t initializeOffsetsPacked(size_t bitPosition)
742  {
743  detail::DummyArrayOwner owner;
744  return initializeOffsetsPackedImpl(owner, bitPosition);
745  }
746 
757  template <typename OWNER_TYPE_ = OwnerType,
758  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
759  size_t initializeOffsetsPacked(OwnerType& owner, size_t bitPosition)
760  {
761  return initializeOffsetsPackedImpl(owner, bitPosition);
762  }
763 
772  template <typename OWNER_TYPE_ = OwnerType,
773  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
774  void readPacked(BitStreamReader& in, size_t arrayLength = 0)
775  {
776  detail::DummyArrayOwner owner;
777  readPackedImpl(owner, in, arrayLength);
778  }
779 
789  template <typename OWNER_TYPE_ = OwnerType,
790  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
791  void readPacked(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
792  {
793  readPackedImpl(owner, in, arrayLength);
794  }
795 
803  template <typename OWNER_TYPE_ = OwnerType,
804  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
805  void writePacked(BitStreamWriter& out) const
806  {
807  writePackedImpl(detail::DummyArrayOwner(), out);
808  }
809 
818  template <typename OWNER_TYPE_ = OwnerType,
819  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
820  void writePacked(const OwnerType& owner, BitStreamWriter& out) const
821  {
822  writePackedImpl(owner, out);
823  }
824 
825 private:
826  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
827  typename std::enable_if<ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
828  int>::type = 0>
829  static void addBitSizeOfArrayLength(size_t&, size_t)
830  {}
831 
832  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
833  typename std::enable_if<ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
834  int>::type = 0>
835  static void addBitSizeOfArrayLength(size_t& bitPosition, size_t arrayLength)
836  {
837  bitPosition += bitSizeOfVarSize(convertSizeToUInt32(arrayLength));
838  }
839 
840  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
841  typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
842  int>::type = 0>
843  static void alignBitPosition(size_t&)
844  {}
845 
846  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
847  typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
848  int>::type = 0>
849  static void alignBitPosition(size_t& bitPosition)
850  {
851  bitPosition = alignTo(8, bitPosition);
852  }
853 
854  template <typename IO, typename OWNER_TYPE, ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
855  typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
856  int>::type = 0>
857  static void alignAndCheckOffset(IO&, OWNER_TYPE&, size_t)
858  {}
859 
860  template <typename IO, typename OWNER_TYPE, ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
861  typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
862  int>::type = 0>
863  static void alignAndCheckOffset(IO& io, OWNER_TYPE& owner, size_t index)
864  {
865  io.alignTo(8);
866  detail::checkOffset<ArrayExpressions>(owner, index, io.getBitPosition() / 8);
867  }
868 
869  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
870  typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
871  int>::type = 0>
872  static void initializeOffset(OwnerType&, size_t, size_t&)
873  {}
874 
875  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
876  typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
877  int>::type = 0>
878  static void initializeOffset(OwnerType& owner, size_t index, size_t& bitPosition)
879  {
880  bitPosition = alignTo(8, bitPosition);
881  detail::initializeOffset<ArrayExpressions>(owner, index, bitPosition / 8);
882  }
883 
884  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
885  typename std::enable_if<ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO &&
886  ARRAY_TYPE_ != ArrayType::IMPLICIT,
887  int>::type = 0>
888  static size_t readArrayLength(OwnerType&, BitStreamReader&, size_t arrayLength)
889  {
890  return arrayLength;
891  }
892 
893  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
894  typename std::enable_if<ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
895  int>::type = 0>
896  static size_t readArrayLength(OwnerType&, BitStreamReader& in, size_t)
897  {
898  return in.readVarSize();
899  }
900 
901  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
902  typename std::enable_if<ARRAY_TYPE_ == ArrayType::IMPLICIT, int>::type = 0>
903  static size_t readArrayLength(OwnerType& owner, BitStreamReader& in, size_t)
904  {
905  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT || ArrayTraits::IS_BITSIZEOF_CONSTANT,
906  "Implicit array elements must have constant bit size!");
907 
908  const size_t remainingBits = in.getBufferBitSize() - in.getBitPosition();
909  return remainingBits / detail::arrayTraitsConstBitSizeOf<ArrayTraits>(owner);
910  }
911 
912  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
913  typename std::enable_if<ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
914  int>::type = 0>
915  static void writeArrayLength(BitStreamWriter&, size_t)
916  {}
917 
918  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
919  typename std::enable_if<ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
920  int>::type = 0>
921  static void writeArrayLength(BitStreamWriter& out, size_t arrayLength)
922  {
923  out.writeVarSize(convertSizeToUInt32(arrayLength));
924  }
925 
926  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
927  typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
928  int>::type = 0>
929  static size_t constBitSizeOfElements(size_t, size_t arrayLength, size_t elementBitSize)
930  {
931  return arrayLength * elementBitSize;
932  }
933 
934  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
935  typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
936  int>::type = 0>
937  static size_t constBitSizeOfElements(size_t bitPosition, size_t arrayLength, size_t elementBitSize)
938  {
939  size_t endBitPosition = alignTo(8, bitPosition);
940  endBitPosition += elementBitSize + (arrayLength - 1) * alignTo(8, elementBitSize);
941 
942  return endBitPosition - bitPosition;
943  }
944 
945  template <typename ARRAY_TRAITS_ = ArrayTraits,
946  typename std::enable_if<ARRAY_TRAITS_::IS_BITSIZEOF_CONSTANT, int>::type = 0>
947  size_t bitSizeOfImpl(const OwnerType& owner, size_t bitPosition) const
948  {
949  size_t endBitPosition = bitPosition;
950 
951  const size_t arrayLength = m_rawArray.size();
952  addBitSizeOfArrayLength(endBitPosition, arrayLength);
953 
954  if (arrayLength > 0)
955  {
956  const size_t elementBitSize = detail::arrayTraitsConstBitSizeOf<ArrayTraits>(owner);
957  endBitPosition += constBitSizeOfElements(endBitPosition, arrayLength, elementBitSize);
958  }
959 
960  return endBitPosition - bitPosition;
961  }
962 
963  template <typename ARRAY_TRAITS_ = ArrayTraits,
964  typename std::enable_if<!ARRAY_TRAITS_::IS_BITSIZEOF_CONSTANT, int>::type = 0>
965  size_t bitSizeOfImpl(const OwnerType& owner, size_t bitPosition) const
966  {
967  size_t endBitPosition = bitPosition;
968 
969  const size_t arrayLength = m_rawArray.size();
970  addBitSizeOfArrayLength(endBitPosition, arrayLength);
971 
972  for (size_t index = 0; index < arrayLength; ++index)
973  {
974  alignBitPosition(endBitPosition);
975  endBitPosition +=
976  detail::arrayTraitsBitSizeOf<ArrayTraits>(owner, endBitPosition, m_rawArray[index]);
977  }
978 
979  return endBitPosition - bitPosition;
980  }
981 
982  size_t initializeOffsetsImpl(OwnerType& owner, size_t bitPosition)
983  {
984  size_t endBitPosition = bitPosition;
985 
986  const size_t arrayLength = m_rawArray.size();
987  addBitSizeOfArrayLength(endBitPosition, arrayLength);
988 
989  for (size_t index = 0; index < arrayLength; ++index)
990  {
991  initializeOffset(owner, index, endBitPosition);
992  endBitPosition =
993  detail::arrayTraitsInitializeOffsets<ArrayTraits>(owner, endBitPosition, m_rawArray[index]);
994  }
995 
996  return endBitPosition;
997  }
998 
999  void readImpl(OwnerType& owner, BitStreamReader& in, size_t arrayLength)
1000  {
1001  size_t readLength = readArrayLength(owner, in, arrayLength);
1002 
1003  m_rawArray.clear();
1004  m_rawArray.reserve(readLength);
1005  for (size_t index = 0; index < readLength; ++index)
1006  {
1007  alignAndCheckOffset(in, owner, index);
1008  detail::arrayTraitsRead<ArrayTraits>(owner, m_rawArray, in, index);
1009  }
1010  }
1011 
1012  void writeImpl(const OwnerType& owner, BitStreamWriter& out) const
1013  {
1014  const size_t arrayLength = m_rawArray.size();
1015  writeArrayLength(out, arrayLength);
1016 
1017  for (size_t index = 0; index < arrayLength; ++index)
1018  {
1019  alignAndCheckOffset(out, owner, index);
1020  detail::arrayTraitsWrite<ArrayTraits>(owner, out, m_rawArray[index]);
1021  }
1022  }
1023 
1024  using PackingContext = typename detail::packing_context_type<typename RawArray::value_type>::type;
1025 
1026  size_t bitSizeOfPackedImpl(const OwnerType& owner, size_t bitPosition) const
1027  {
1028  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1029 
1030  size_t endBitPosition = bitPosition;
1031 
1032  const size_t arrayLength = m_rawArray.size();
1033  addBitSizeOfArrayLength(endBitPosition, arrayLength);
1034 
1035  if (arrayLength > 0)
1036  {
1037  PackingContext context;
1038 
1039  for (size_t index = 0; index < arrayLength; ++index)
1040  {
1041  detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1042  owner, context, m_rawArray[index]);
1043  }
1044 
1045  for (size_t index = 0; index < arrayLength; ++index)
1046  {
1047  alignBitPosition(endBitPosition);
1048  endBitPosition += detail::packedArrayTraitsBitSizeOf<PackedArrayTraits<ArrayTraits>>(
1049  owner, context, endBitPosition, m_rawArray[index]);
1050  }
1051  }
1052 
1053  return endBitPosition - bitPosition;
1054  }
1055 
1056  size_t initializeOffsetsPackedImpl(OwnerType& owner, size_t bitPosition)
1057  {
1058  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1059 
1060  size_t endBitPosition = bitPosition;
1061 
1062  const size_t arrayLength = m_rawArray.size();
1063  addBitSizeOfArrayLength(endBitPosition, arrayLength);
1064 
1065  if (arrayLength > 0)
1066  {
1067  PackingContext context;
1068 
1069  for (size_t index = 0; index < arrayLength; ++index)
1070  {
1071  detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1072  owner, context, m_rawArray[index]);
1073  }
1074 
1075  for (size_t index = 0; index < arrayLength; ++index)
1076  {
1077  initializeOffset(owner, index, endBitPosition);
1078  endBitPosition = detail::packedArrayTraitsInitializeOffsets<PackedArrayTraits<ArrayTraits>>(
1079  owner, context, endBitPosition, m_rawArray[index]);
1080  }
1081  }
1082 
1083  return endBitPosition;
1084  }
1085 
1086  void readPackedImpl(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
1087  {
1088  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1089 
1090  size_t readLength = readArrayLength(owner, in, arrayLength);
1091 
1092  m_rawArray.clear();
1093 
1094  if (readLength > 0)
1095  {
1096  m_rawArray.reserve(readLength);
1097 
1098  PackingContext context;
1099 
1100  for (size_t index = 0; index < readLength; ++index)
1101  {
1102  alignAndCheckOffset(in, owner, index);
1103  detail::packedArrayTraitsRead<PackedArrayTraits<ArrayTraits>>(
1104  owner, m_rawArray, context, in, index);
1105  }
1106  }
1107  }
1108 
1109  void writePackedImpl(const OwnerType& owner, BitStreamWriter& out) const
1110  {
1111  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1112 
1113  const size_t arrayLength = m_rawArray.size();
1114  writeArrayLength(out, arrayLength);
1115 
1116  if (arrayLength > 0)
1117  {
1118  PackingContext context;
1119 
1120  for (size_t index = 0; index < arrayLength; ++index)
1121  {
1122  detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1123  owner, context, m_rawArray[index]);
1124  }
1125 
1126  for (size_t index = 0; index < arrayLength; ++index)
1127  {
1128  alignAndCheckOffset(out, owner, index);
1129  detail::packedArrayTraitsWrite<PackedArrayTraits<ArrayTraits>>(
1130  owner, context, out, m_rawArray[index]);
1131  }
1132  }
1133  }
1134 
1135  RawArray m_rawArray;
1136 };
1137 
1142 template <typename ARRAY, typename RAW_ARRAY>
1143 ARRAY createOptionalArray(RAW_ARRAY&& rawArray)
1144 {
1145  return ARRAY(std::forward<RAW_ARRAY>(rawArray));
1146 }
1147 
1151 template <typename ARRAY>
1153 {
1154  return NullOpt;
1155 }
1156 
1157 } // namespace zserio
1158 
1159 #endif // ZSERIO_ARRAY_H_INC
size_t bitSizeOf(const OwnerType &owner, size_t bitPosition) const
Definition: Array.h:597
ARRAY_TRAITS ArrayTraits
Definition: Array.h:348
Array(NoInitT, const Array &other)
Definition: Array.h:414
bool operator==(const Array &other) const
Definition: Array.h:505
~Array()=default
void readPacked(BitStreamReader &in, size_t arrayLength=0)
Definition: Array.h:774
Array & operator=(Array &&other)=default
size_t initializeOffsetsPacked(OwnerType &owner, size_t bitPosition)
Definition: Array.h:759
RAW_ARRAY RawArray
Definition: Array.h:345
Array & assign(NoInitT, const Array &other)
Definition: Array.h:434
RawArray & getRawArray()
Definition: Array.h:547
void write(BitStreamWriter &out) const
Definition: Array.h:677
void read(OwnerType &owner, BitStreamReader &in, size_t arrayLength=0)
Definition: Array.h:663
Array & operator=(const Array &other)=default
size_t bitSizeOfPacked(size_t bitPosition) const
Definition: Array.h:708
size_t initializeOffsets(OwnerType &owner, size_t bitPosition)
Definition: Array.h:631
void readPacked(OwnerType &owner, BitStreamReader &in, size_t arrayLength=0)
Definition: Array.h:791
void read(BitStreamReader &in, size_t arrayLength=0)
Definition: Array.h:646
typename detail::array_owner_type< ArrayTraits, ArrayExpressions >::type OwnerType
Definition: Array.h:359
size_t initializeOffsets(size_t bitPosition)
Definition: Array.h:613
void writePacked(BitStreamWriter &out) const
Definition: Array.h:805
uint32_t hashCode() const
Definition: Array.h:527
Array(RawArray &&rawArray)
Definition: Array.h:387
bool operator<(const Array &other) const
Definition: Array.h:517
Array(PropagateAllocatorT, const Array &other, const allocator_type &allocator)
Definition: Array.h:481
ARRAY_EXPRESSIONS ArrayExpressions
Definition: Array.h:351
typename RawArray::allocator_type allocator_type
Definition: Array.h:362
size_t bitSizeOf(size_t bitPosition) const
Definition: Array.h:580
Array(Array &&other)=default
Array(PropagateAllocatorT, NoInitT, const Array &other, const allocator_type &allocator)
Definition: Array.h:494
void initializeElements(OwnerType &owner)
Definition: Array.h:559
const RawArray & getRawArray() const
Definition: Array.h:537
Array & assign(NoInitT, Array &&other)
Definition: Array.h:470
void write(const OwnerType &owner, BitStreamWriter &out) const
Definition: Array.h:692
Array(NoInitT, Array &&other)
Definition: Array.h:456
size_t initializeOffsetsPacked(size_t bitPosition)
Definition: Array.h:741
Array(const RawArray &rawArray)
Definition: Array.h:378
size_t bitSizeOfPacked(const OwnerType &ownerType, size_t bitPosition) const
Definition: Array.h:725
Array(const allocator_type &allocator=allocator_type())
Definition: Array.h:369
Array(const Array &other)=default
void writePacked(const OwnerType &owner, BitStreamWriter &out) const
Definition: Array.h:820
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:1143
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:324
@ ALIGNED_AUTO
Definition: Array.h:329
@ ALIGNED
Definition: Array.h:327
@ IMPLICIT
Definition: Array.h:326
@ NORMAL
Definition: Array.h:325
@ AUTO
Definition: Array.h:328
size_t bitSizeOf(T value)