Zserio C++ runtime library  1.0.1
Built for Zserio 2.14.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, 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  m_rawArray.emplace_back(NoInit, value);
421  }
422 
430  template <typename T = typename RAW_ARRAY::value_type,
431  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
432  Array& assign(NoInitT, const Array& other)
433  {
434  const RawArray rawArray(other.m_rawArray.get_allocator());
435  m_rawArray = rawArray; // copy assign to get correct allocator propagation behaviour
436  m_rawArray.reserve(other.m_rawArray.size());
437  for (const auto& value : other.m_rawArray)
438  m_rawArray.emplace_back(NoInit, value);
439 
440  return *this;
441  }
442 
450  template <typename T = typename RAW_ARRAY::value_type,
451  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
452  Array(NoInitT, Array&& other) :
453  Array(std::move(other))
454  {}
455 
464  template <typename T = typename RAW_ARRAY::value_type,
465  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
467  {
468  return operator=(std::move(other));
469  }
470 
477  Array(PropagateAllocatorT, const Array& other, const allocator_type& allocator) :
478  m_rawArray(allocatorPropagatingCopy(other.m_rawArray, allocator))
479  {}
480 
488  template <typename T = typename RAW_ARRAY::value_type,
489  typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
490  Array(PropagateAllocatorT, NoInitT, const Array& other, const allocator_type& allocator) :
491  m_rawArray(allocatorPropagatingCopy(NoInit, other.m_rawArray, allocator))
492  {}
493 
501  bool operator==(const Array& other) const
502  {
503  return m_rawArray == other.m_rawArray;
504  }
505 
513  bool operator<(const Array& other) const
514  {
515  return m_rawArray < other.m_rawArray;
516  }
517 
523  uint32_t hashCode() const
524  {
525  return calcHashCode(HASH_SEED, m_rawArray);
526  }
527 
533  const RawArray& getRawArray() const
534  {
535  return m_rawArray;
536  }
537 
544  {
545  return m_rawArray;
546  }
547 
553  template <typename ARRAY_EXPRESSIONS_ = ArrayExpressions,
554  typename std::enable_if<has_initialize_element<ARRAY_EXPRESSIONS_>::value, int>::type = 0>
556  {
557  size_t index = 0;
558  for (auto&& element : m_rawArray)
559  {
560  ArrayExpressions::initializeElement(owner, element, index);
561  index++;
562  }
563  }
564 
574  template <typename OWNER_TYPE_ = OwnerType,
575  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
576  size_t bitSizeOf(size_t bitPosition) const
577  {
578  return bitSizeOfImpl(detail::DummyArrayOwner(), bitPosition);
579  }
580 
591  template <typename OWNER_TYPE_ = OwnerType,
592  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
593  size_t bitSizeOf(const OwnerType& owner, size_t bitPosition) const
594  {
595  return bitSizeOfImpl(owner, bitPosition);
596  }
597 
607  template <typename OWNER_TYPE_ = OwnerType,
608  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
609  size_t initializeOffsets(size_t bitPosition)
610  {
611  detail::DummyArrayOwner owner;
612  return initializeOffsetsImpl(owner, bitPosition);
613  }
614 
625  template <typename OWNER_TYPE_ = OwnerType,
626  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
627  size_t initializeOffsets(OwnerType& owner, size_t bitPosition)
628  {
629  return initializeOffsetsImpl(owner, bitPosition);
630  }
631 
640  template <typename OWNER_TYPE_ = OwnerType,
641  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
642  void read(BitStreamReader& in, size_t arrayLength = 0)
643  {
644  detail::DummyArrayOwner owner;
645  readImpl(owner, in, arrayLength);
646  }
647 
657  template <typename OWNER_TYPE_ = OwnerType,
658  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
659  void read(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
660  {
661  readImpl(owner, in, arrayLength);
662  }
663 
671  template <typename OWNER_TYPE_ = OwnerType,
672  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
673  void write(BitStreamWriter& out) const
674  {
675  writeImpl(detail::DummyArrayOwner(), out);
676  }
677 
686  template <typename OWNER_TYPE_ = OwnerType,
687  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
688  void write(const OwnerType& owner, BitStreamWriter& out) const
689  {
690  writeImpl(owner, out);
691  }
692 
702  template <typename OWNER_TYPE_ = OwnerType,
703  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
704  size_t bitSizeOfPacked(size_t bitPosition) const
705  {
706  return bitSizeOfPackedImpl(detail::DummyArrayOwner(), bitPosition);
707  }
708 
719  template <typename OWNER_TYPE_ = OwnerType,
720  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
721  size_t bitSizeOfPacked(const OwnerType& ownerType, size_t bitPosition) const
722  {
723  return bitSizeOfPackedImpl(ownerType, bitPosition);
724  }
725 
735  template <typename OWNER_TYPE_ = OwnerType,
736  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
737  size_t initializeOffsetsPacked(size_t bitPosition)
738  {
739  detail::DummyArrayOwner owner;
740  return initializeOffsetsPackedImpl(owner, bitPosition);
741  }
742 
753  template <typename OWNER_TYPE_ = OwnerType,
754  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
755  size_t initializeOffsetsPacked(OwnerType& owner, size_t bitPosition)
756  {
757  return initializeOffsetsPackedImpl(owner, bitPosition);
758  }
759 
768  template <typename OWNER_TYPE_ = OwnerType,
769  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
770  void readPacked(BitStreamReader& in, size_t arrayLength = 0)
771  {
772  detail::DummyArrayOwner owner;
773  readPackedImpl(owner, in, arrayLength);
774  }
775 
785  template <typename OWNER_TYPE_ = OwnerType,
786  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
787  void readPacked(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
788  {
789  readPackedImpl(owner, in, arrayLength);
790  }
791 
799  template <typename OWNER_TYPE_ = OwnerType,
800  typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
801  void writePacked(BitStreamWriter& out) const
802  {
803  writePackedImpl(detail::DummyArrayOwner(), out);
804  }
805 
814  template <typename OWNER_TYPE_ = OwnerType,
815  typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
816  void writePacked(const OwnerType& owner, BitStreamWriter& out) const
817  {
818  writePackedImpl(owner, out);
819  }
820 
821 private:
822  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
823  typename std::enable_if<ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
824  int>::type = 0>
825  static void addBitSizeOfArrayLength(size_t&, size_t)
826  {}
827 
828  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
829  typename std::enable_if<ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
830  int>::type = 0>
831  static void addBitSizeOfArrayLength(size_t& bitPosition, size_t arrayLength)
832  {
833  bitPosition += bitSizeOfVarSize(convertSizeToUInt32(arrayLength));
834  }
835 
836  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
837  typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
838  int>::type = 0>
839  static void alignBitPosition(size_t&)
840  {}
841 
842  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
843  typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
844  int>::type = 0>
845  static void alignBitPosition(size_t& bitPosition)
846  {
847  bitPosition = alignTo(8, bitPosition);
848  }
849 
850  template <typename IO, typename OWNER_TYPE, ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
851  typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
852  int>::type = 0>
853  static void alignAndCheckOffset(IO&, OWNER_TYPE&, size_t)
854  {}
855 
856  template <typename IO, typename OWNER_TYPE, ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
857  typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
858  int>::type = 0>
859  static void alignAndCheckOffset(IO& io, OWNER_TYPE& owner, size_t index)
860  {
861  io.alignTo(8);
862  detail::checkOffset<ArrayExpressions>(owner, index, io.getBitPosition() / 8);
863  }
864 
865  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
866  typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
867  int>::type = 0>
868  static void initializeOffset(OwnerType&, size_t, size_t&)
869  {}
870 
871  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
872  typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
873  int>::type = 0>
874  static void initializeOffset(OwnerType& owner, size_t index, size_t& bitPosition)
875  {
876  bitPosition = alignTo(8, bitPosition);
877  detail::initializeOffset<ArrayExpressions>(owner, index, bitPosition / 8);
878  }
879 
880  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
881  typename std::enable_if<ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO &&
882  ARRAY_TYPE_ != ArrayType::IMPLICIT,
883  int>::type = 0>
884  static size_t readArrayLength(OwnerType&, BitStreamReader&, size_t arrayLength)
885  {
886  return arrayLength;
887  }
888 
889  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
890  typename std::enable_if<ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
891  int>::type = 0>
892  static size_t readArrayLength(OwnerType&, BitStreamReader& in, size_t)
893  {
894  return in.readVarSize();
895  }
896 
897  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
898  typename std::enable_if<ARRAY_TYPE_ == ArrayType::IMPLICIT, int>::type = 0>
899  static size_t readArrayLength(OwnerType& owner, BitStreamReader& in, size_t)
900  {
901  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT || ArrayTraits::IS_BITSIZEOF_CONSTANT,
902  "Implicit array elements must have constant bit size!");
903 
904  const size_t remainingBits = in.getBufferBitSize() - in.getBitPosition();
905  return remainingBits / detail::arrayTraitsConstBitSizeOf<ArrayTraits>(owner);
906  }
907 
908  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
909  typename std::enable_if<ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
910  int>::type = 0>
911  static void writeArrayLength(BitStreamWriter&, size_t)
912  {}
913 
914  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
915  typename std::enable_if<ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
916  int>::type = 0>
917  static void writeArrayLength(BitStreamWriter& out, size_t arrayLength)
918  {
919  out.writeVarSize(convertSizeToUInt32(arrayLength));
920  }
921 
922  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
923  typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
924  int>::type = 0>
925  static size_t constBitSizeOfElements(size_t, size_t arrayLength, size_t elementBitSize)
926  {
927  return arrayLength * elementBitSize;
928  }
929 
930  template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
931  typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
932  int>::type = 0>
933  static size_t constBitSizeOfElements(size_t bitPosition, size_t arrayLength, size_t elementBitSize)
934  {
935  size_t endBitPosition = alignTo(8, bitPosition);
936  endBitPosition += elementBitSize + (arrayLength - 1) * alignTo(8, elementBitSize);
937 
938  return endBitPosition - bitPosition;
939  }
940 
941  template <typename ARRAY_TRAITS_ = ArrayTraits,
942  typename std::enable_if<ARRAY_TRAITS_::IS_BITSIZEOF_CONSTANT, int>::type = 0>
943  size_t bitSizeOfImpl(const OwnerType& owner, size_t bitPosition) const
944  {
945  size_t endBitPosition = bitPosition;
946 
947  const size_t arrayLength = m_rawArray.size();
948  addBitSizeOfArrayLength(endBitPosition, arrayLength);
949 
950  if (arrayLength > 0)
951  {
952  const size_t elementBitSize = detail::arrayTraitsConstBitSizeOf<ArrayTraits>(owner);
953  endBitPosition += constBitSizeOfElements(endBitPosition, arrayLength, elementBitSize);
954  }
955 
956  return endBitPosition - bitPosition;
957  }
958 
959  template <typename ARRAY_TRAITS_ = ArrayTraits,
960  typename std::enable_if<!ARRAY_TRAITS_::IS_BITSIZEOF_CONSTANT, int>::type = 0>
961  size_t bitSizeOfImpl(const OwnerType& owner, size_t bitPosition) const
962  {
963  size_t endBitPosition = bitPosition;
964 
965  const size_t arrayLength = m_rawArray.size();
966  addBitSizeOfArrayLength(endBitPosition, arrayLength);
967 
968  for (size_t index = 0; index < arrayLength; ++index)
969  {
970  alignBitPosition(endBitPosition);
971  endBitPosition +=
972  detail::arrayTraitsBitSizeOf<ArrayTraits>(owner, endBitPosition, m_rawArray[index]);
973  }
974 
975  return endBitPosition - bitPosition;
976  }
977 
978  size_t initializeOffsetsImpl(OwnerType& owner, size_t bitPosition)
979  {
980  size_t endBitPosition = bitPosition;
981 
982  const size_t arrayLength = m_rawArray.size();
983  addBitSizeOfArrayLength(endBitPosition, arrayLength);
984 
985  for (size_t index = 0; index < arrayLength; ++index)
986  {
987  initializeOffset(owner, index, endBitPosition);
988  endBitPosition =
989  detail::arrayTraitsInitializeOffsets<ArrayTraits>(owner, endBitPosition, m_rawArray[index]);
990  }
991 
992  return endBitPosition;
993  }
994 
995  void readImpl(OwnerType& owner, BitStreamReader& in, size_t arrayLength)
996  {
997  size_t readLength = readArrayLength(owner, in, arrayLength);
998 
999  m_rawArray.clear();
1000  m_rawArray.reserve(readLength);
1001  for (size_t index = 0; index < readLength; ++index)
1002  {
1003  alignAndCheckOffset(in, owner, index);
1004  detail::arrayTraitsRead<ArrayTraits>(owner, m_rawArray, in, index);
1005  }
1006  }
1007 
1008  void writeImpl(const OwnerType& owner, BitStreamWriter& out) const
1009  {
1010  const size_t arrayLength = m_rawArray.size();
1011  writeArrayLength(out, arrayLength);
1012 
1013  for (size_t index = 0; index < arrayLength; ++index)
1014  {
1015  alignAndCheckOffset(out, owner, index);
1016  detail::arrayTraitsWrite<ArrayTraits>(owner, out, m_rawArray[index]);
1017  }
1018  }
1019 
1020  using PackingContext = typename detail::packing_context_type<typename RawArray::value_type>::type;
1021 
1022  size_t bitSizeOfPackedImpl(const OwnerType& owner, size_t bitPosition) const
1023  {
1024  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1025 
1026  size_t endBitPosition = bitPosition;
1027 
1028  const size_t arrayLength = m_rawArray.size();
1029  addBitSizeOfArrayLength(endBitPosition, arrayLength);
1030 
1031  if (arrayLength > 0)
1032  {
1033  PackingContext context;
1034 
1035  for (size_t index = 0; index < arrayLength; ++index)
1036  {
1037  detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1038  owner, context, m_rawArray[index]);
1039  }
1040 
1041  for (size_t index = 0; index < arrayLength; ++index)
1042  {
1043  alignBitPosition(endBitPosition);
1044  endBitPosition += detail::packedArrayTraitsBitSizeOf<PackedArrayTraits<ArrayTraits>>(
1045  owner, context, endBitPosition, m_rawArray[index]);
1046  }
1047  }
1048 
1049  return endBitPosition - bitPosition;
1050  }
1051 
1052  size_t initializeOffsetsPackedImpl(OwnerType& owner, size_t bitPosition)
1053  {
1054  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1055 
1056  size_t endBitPosition = bitPosition;
1057 
1058  const size_t arrayLength = m_rawArray.size();
1059  addBitSizeOfArrayLength(endBitPosition, arrayLength);
1060 
1061  if (arrayLength > 0)
1062  {
1063  PackingContext context;
1064 
1065  for (size_t index = 0; index < arrayLength; ++index)
1066  {
1067  detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1068  owner, context, m_rawArray[index]);
1069  }
1070 
1071  for (size_t index = 0; index < arrayLength; ++index)
1072  {
1073  initializeOffset(owner, index, endBitPosition);
1074  endBitPosition = detail::packedArrayTraitsInitializeOffsets<PackedArrayTraits<ArrayTraits>>(
1075  owner, context, endBitPosition, m_rawArray[index]);
1076  }
1077  }
1078 
1079  return endBitPosition;
1080  }
1081 
1082  void readPackedImpl(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
1083  {
1084  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1085 
1086  size_t readLength = readArrayLength(owner, in, arrayLength);
1087 
1088  m_rawArray.clear();
1089 
1090  if (readLength > 0)
1091  {
1092  m_rawArray.reserve(readLength);
1093 
1094  PackingContext context;
1095 
1096  for (size_t index = 0; index < readLength; ++index)
1097  {
1098  alignAndCheckOffset(in, owner, index);
1099  detail::packedArrayTraitsRead<PackedArrayTraits<ArrayTraits>>(
1100  owner, m_rawArray, context, in, index);
1101  }
1102  }
1103  }
1104 
1105  void writePackedImpl(const OwnerType& owner, BitStreamWriter& out) const
1106  {
1107  static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1108 
1109  const size_t arrayLength = m_rawArray.size();
1110  writeArrayLength(out, arrayLength);
1111 
1112  if (arrayLength > 0)
1113  {
1114  PackingContext context;
1115 
1116  for (size_t index = 0; index < arrayLength; ++index)
1117  {
1118  detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1119  owner, context, m_rawArray[index]);
1120  }
1121 
1122  for (size_t index = 0; index < arrayLength; ++index)
1123  {
1124  alignAndCheckOffset(out, owner, index);
1125  detail::packedArrayTraitsWrite<PackedArrayTraits<ArrayTraits>>(
1126  owner, context, out, m_rawArray[index]);
1127  }
1128  }
1129  }
1130 
1131  RawArray m_rawArray;
1132 };
1133 
1138 template <typename ARRAY, typename RAW_ARRAY>
1139 ARRAY createOptionalArray(RAW_ARRAY&& rawArray)
1140 {
1141  return ARRAY(std::forward<RAW_ARRAY>(rawArray));
1142 }
1143 
1147 template <typename ARRAY>
1149 {
1150  return NullOpt;
1151 }
1152 
1153 } // namespace zserio
1154 
1155 #endif // ZSERIO_ARRAY_H_INC
size_t bitSizeOf(const OwnerType &owner, size_t bitPosition) const
Definition: Array.h:593
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:501
~Array()=default
void readPacked(BitStreamReader &in, size_t arrayLength=0)
Definition: Array.h:770
Array & operator=(Array &&other)=default
size_t initializeOffsetsPacked(OwnerType &owner, size_t bitPosition)
Definition: Array.h:755
RAW_ARRAY RawArray
Definition: Array.h:345
Array & assign(NoInitT, const Array &other)
Definition: Array.h:432
RawArray & getRawArray()
Definition: Array.h:543
void write(BitStreamWriter &out) const
Definition: Array.h:673
void read(OwnerType &owner, BitStreamReader &in, size_t arrayLength=0)
Definition: Array.h:659
Array & operator=(const Array &other)=default
size_t bitSizeOfPacked(size_t bitPosition) const
Definition: Array.h:704
size_t initializeOffsets(OwnerType &owner, size_t bitPosition)
Definition: Array.h:627
void readPacked(OwnerType &owner, BitStreamReader &in, size_t arrayLength=0)
Definition: Array.h:787
void read(BitStreamReader &in, size_t arrayLength=0)
Definition: Array.h:642
typename detail::array_owner_type< ArrayTraits, ArrayExpressions >::type OwnerType
Definition: Array.h:359
size_t initializeOffsets(size_t bitPosition)
Definition: Array.h:609
void writePacked(BitStreamWriter &out) const
Definition: Array.h:801
uint32_t hashCode() const
Definition: Array.h:523
Array(RawArray &&rawArray)
Definition: Array.h:387
bool operator<(const Array &other) const
Definition: Array.h:513
Array(PropagateAllocatorT, const Array &other, const allocator_type &allocator)
Definition: Array.h:477
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:576
Array(Array &&other)=default
Array(PropagateAllocatorT, NoInitT, const Array &other, const allocator_type &allocator)
Definition: Array.h:490
void initializeElements(OwnerType &owner)
Definition: Array.h:555
const RawArray & getRawArray() const
Definition: Array.h:533
Array & assign(NoInitT, Array &&other)
Definition: Array.h:466
void write(const OwnerType &owner, BitStreamWriter &out) const
Definition: Array.h:688
Array(NoInitT, Array &&other)
Definition: Array.h:452
size_t initializeOffsetsPacked(size_t bitPosition)
Definition: Array.h:737
Array(const RawArray &rawArray)
Definition: Array.h:378
size_t bitSizeOfPacked(const OwnerType &ownerType, size_t bitPosition) const
Definition: Array.h:721
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:816
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:1139
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)