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