GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/zserio/Array.h Lines: 302 303 99.7 %
Date: 2023-12-13 14:51:09 Branches: 4721 7669 61.6 %

Line Branch Exec Source
1
#ifndef ZSERIO_ARRAY_H_INC
2
#define ZSERIO_ARRAY_H_INC
3
4
#include <cstdlib>
5
#include <type_traits>
6
7
#include "zserio/AllocatorPropagatingCopy.h"
8
#include "zserio/ArrayTraits.h"
9
#include "zserio/BitSizeOfCalculator.h"
10
#include "zserio/BitStreamReader.h"
11
#include "zserio/BitStreamWriter.h"
12
#include "zserio/DeltaContext.h"
13
#include "zserio/Traits.h"
14
#include "zserio/UniquePtr.h"
15
#include "zserio/SizeConvertUtil.h"
16
17
namespace zserio
18
{
19
20
namespace detail
21
{
22
23
// array expressions for arrays which do not need expressions
24
struct DummyArrayExpressions
25
{};
26
27
// array owner for arrays which do not need the owner
28
struct DummyArrayOwner
29
{};
30
31
// helper trait to choose the owner type for an array from combination of ARRAY_TRAITS and ARRAY_EXPRESSIONS
32
template <typename ARRAY_TRAITS, typename ARRAY_EXPRESSIONS, typename = void>
33
struct array_owner_type
34
{
35
    using type = DummyArrayOwner;
36
};
37
38
template <typename ARRAY_TRAITS, typename ARRAY_EXPRESSIONS>
39
struct array_owner_type<ARRAY_TRAITS, ARRAY_EXPRESSIONS,
40
        typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value>::type>
41
{
42
    using type = typename ARRAY_TRAITS::OwnerType;
43
};
44
45
template <typename ARRAY_TRAITS, typename ARRAY_EXPRESSIONS>
46
struct array_owner_type<ARRAY_TRAITS, ARRAY_EXPRESSIONS,
47
        typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
48
                has_owner_type<ARRAY_EXPRESSIONS>::value>::type>
49
{
50
    using type = typename ARRAY_EXPRESSIONS::OwnerType;
51
};
52
53
// helper trait to choose packing context type for an array from an element type T
54
template <typename T, typename = void>
55
struct packing_context_type
56
{
57
    using type = DeltaContext;
58
};
59
60
template <typename T>
61
struct packing_context_type<T, typename std::enable_if<has_zserio_packing_context<T>::value>::type>
62
{
63
    using type = typename T::ZserioPackingContext;
64
};
65
66
// calls the initializeOffset static method on ARRAY_EXPRESSIONS if available
67
template <typename ARRAY_EXPRESSIONS, typename OWNER_TYPE,
68
        typename std::enable_if<has_initialize_offset<ARRAY_EXPRESSIONS>::value, int>::type = 0>
69
192
void initializeOffset(OWNER_TYPE& owner, size_t index, size_t bitPosition)
70
{
71
192
    ARRAY_EXPRESSIONS::initializeOffset(owner, index, bitPosition);
72
192
}
73
74
template <typename ARRAY_EXPRESSIONS, typename OWNER_TYPE,
75
        typename std::enable_if<!has_initialize_offset<ARRAY_EXPRESSIONS>::value, int>::type = 0>
76
4512
void initializeOffset(OWNER_TYPE&, size_t, size_t)
77
4512
{}
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
384
void checkOffset(const OWNER_TYPE& owner, size_t index, size_t bitPosition)
83
{
84
384
    ARRAY_EXPRESSIONS::checkOffset(owner, index, bitPosition);
85
384
}
86
87
template <typename ARRAY_EXPRESSIONS, typename OWNER_TYPE,
88
        typename std::enable_if<!has_check_offset<ARRAY_EXPRESSIONS>::value, int>::type = 0>
89
9024
void checkOffset(const OWNER_TYPE&, size_t, size_t)
90
9024
{}
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
1152
void packedArrayTraitsInitContext(const OWNER_TYPE& owner, PACKING_CONTEXT& context,
96
        typename PACKED_ARRAY_TRAITS::ElementType element)
97
{
98
1152
    PACKED_ARRAY_TRAITS::initContext(owner, context, element);
99
1152
}
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
10272
void packedArrayTraitsInitContext(const OWNER_TYPE&, PACKING_CONTEXT& context,
104
        typename PACKED_ARRAY_TRAITS::ElementType element)
105
{
106
10272
    PACKED_ARRAY_TRAITS::initContext(context, element);
107
10272
}
108
109
// calls the bitSizeOf method properly on array traits which have constant bit size
110
template <typename ARRAY_TRAITS, typename OWNER_TYPE,
111
        typename std::enable_if<
112
                ARRAY_TRAITS::IS_BITSIZEOF_CONSTANT && has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
113
230
size_t arrayTraitsConstBitSizeOf(const OWNER_TYPE& owner)
114
{
115
230
    return ARRAY_TRAITS::bitSizeOf(owner);
116
}
117
118
template <typename ARRAY_TRAITS, typename OWNER_TYPE,
119
        typename std::enable_if<
120
                ARRAY_TRAITS::IS_BITSIZEOF_CONSTANT && !has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
121
1018
size_t arrayTraitsConstBitSizeOf(const OWNER_TYPE&)
122
{
123
1018
    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
192
size_t arrayTraitsBitSizeOf(const OWNER_TYPE& owner, size_t bitPosition,
130
        const typename ARRAY_TRAITS::ElementType& element)
131
{
132
192
    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
2561
size_t arrayTraitsBitSizeOf(const OWNER_TYPE&, size_t bitPosition,
138
        const typename ARRAY_TRAITS::ElementType& element)
139
{
140
2561
    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
384
size_t packedArrayTraitsBitSizeOf(const OWNER_TYPE& owner, PACKING_CONTEXT& context,
147
        size_t bitPosition, const typename PACKED_ARRAY_TRAITS::ElementType& element)
148
{
149
384
    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
3424
size_t packedArrayTraitsBitSizeOf(const OWNER_TYPE&, PACKING_CONTEXT& context, size_t bitPosition,
155
        const typename PACKED_ARRAY_TRAITS::ElementType& element)
156
{
157
3424
    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
816
size_t arrayTraitsInitializeOffsets(OWNER_TYPE& owner, size_t bitPosition,
164
        typename ARRAY_TRAITS::ElementType& element)
165
{
166
816
    return ARRAY_TRAITS::initializeOffsets(owner, bitPosition, element);
167
}
168
169
template <typename ARRAY_TRAITS, typename OWNER_TYPE,
170
        typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
171
                !std::is_scalar<typename ARRAY_TRAITS::ElementType>::value, int>::type = 0>
172
352
size_t arrayTraitsInitializeOffsets(OWNER_TYPE&, size_t bitPosition,
173
        const typename ARRAY_TRAITS::ElementType& element)
174
{
175
352
    return ARRAY_TRAITS::initializeOffsets(bitPosition, element);
176
}
177
178
template <typename ARRAY_TRAITS, typename OWNER_TYPE,
179
        typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
180
                std::is_scalar<typename ARRAY_TRAITS::ElementType>::value, int>::type = 0>
181
4745
size_t arrayTraitsInitializeOffsets(OWNER_TYPE&, size_t bitPosition, typename ARRAY_TRAITS::ElementType element)
182
{
183
4745
    return ARRAY_TRAITS::initializeOffsets(bitPosition, element);
184
}
185
186
// calls the initializeOffsets method properly on packed array traits
187
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
188
        typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
189
384
size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE& owner, PACKING_CONTEXT& context,
190
        size_t bitPosition, typename PACKED_ARRAY_TRAITS::ElementType& element)
191
{
192
384
    return PACKED_ARRAY_TRAITS::initializeOffsets(owner, context, bitPosition, element);
193
}
194
195
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
196
        typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
197
                !std::is_scalar<typename PACKED_ARRAY_TRAITS::ElementType>::value, int>::type = 0>
198
96
size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE&, PACKING_CONTEXT& context,
199
        size_t bitPosition, const typename PACKED_ARRAY_TRAITS::ElementType& element)
200
{
201
96
    return PACKED_ARRAY_TRAITS::initializeOffsets(context, bitPosition, element);
202
}
203
204
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
205
        typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
206
                std::is_scalar<typename PACKED_ARRAY_TRAITS::ElementType>::value, int>::type = 0>
207
3328
size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE&, PACKING_CONTEXT& context,
208
        size_t bitPosition, typename PACKED_ARRAY_TRAITS::ElementType element)
209
{
210
3328
    return PACKED_ARRAY_TRAITS::initializeOffsets(context, bitPosition, element);
211
}
212
213
// calls the read method properly on array traits
214
template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
215
        typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value &&
216
                !has_allocator<ARRAY_TRAITS>::value, int>::type = 0>
217
624
void arrayTraitsRead(const OWNER_TYPE& owner, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
218
{
219


624
    rawArray.push_back(ARRAY_TRAITS::read(owner, in, index));
220
624
}
221
222
template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
223
        typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value &&
224
                has_allocator<ARRAY_TRAITS>::value, int>::type = 0>
225
192
void arrayTraitsRead(OWNER_TYPE& owner, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
226
{
227
192
    ARRAY_TRAITS::read(owner, rawArray, in, index);
228
192
}
229
230
template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
231
        typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
232
                !has_allocator<ARRAY_TRAITS>::value, int>::type = 0>
233
4841
void arrayTraitsRead(const OWNER_TYPE&, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
234
{
235


















4841
    rawArray.push_back(ARRAY_TRAITS::read(in, index));
236
4840
}
237
238
template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
239
        typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
240
                has_allocator<ARRAY_TRAITS>::value, int>::type = 0>
241
256
void arrayTraitsRead(const OWNER_TYPE&, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
242
{
243
256
    ARRAY_TRAITS::read(rawArray, in, index);
244
256
}
245
246
// calls the read method properly on packed array traits
247
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY, typename PACKING_CONTEXT,
248
        typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value &&
249
                has_allocator<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
250
192
void packedArrayTraitsRead(OWNER_TYPE& owner, RAW_ARRAY& rawArray, PACKING_CONTEXT& context,
251
        BitStreamReader& in, size_t index)
252
{
253
192
    PACKED_ARRAY_TRAITS::read(owner, rawArray, context, in, index);
254
192
}
255
256
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY, typename PACKING_CONTEXT,
257
        typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value &&
258
                !has_allocator<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
259
192
void packedArrayTraitsRead(const OWNER_TYPE& owner, RAW_ARRAY& rawArray, PACKING_CONTEXT& context,
260
        BitStreamReader& in, size_t index)
261
{
262
192
    rawArray.push_back(PACKED_ARRAY_TRAITS::read(owner, context, in, index));
263
192
}
264
265
// note: types which doesn't have owner and have allocator are never packed (e.g. string, bytes ...)
266
//       and thus such specialization is not needed
267
268
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY, typename PACKING_CONTEXT,
269
        typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
270
                !has_allocator<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
271
3424
void packedArrayTraitsRead(const OWNER_TYPE&, RAW_ARRAY& rawArray, PACKING_CONTEXT& context,
272
        BitStreamReader& in, size_t index)
273
{
274






3424
    rawArray.push_back(PACKED_ARRAY_TRAITS::read(context, in, index));
275
3424
}
276
277
// call the write method properly on array traits
278
template <typename ARRAY_TRAITS, typename OWNER_TYPE,
279
        typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
280
816
void arrayTraitsWrite(const OWNER_TYPE& owner,
281
        BitStreamWriter& out, const typename ARRAY_TRAITS::ElementType& element)
282
{
283
816
    ARRAY_TRAITS::write(owner, out, element);
284
816
}
285
286
template <typename ARRAY_TRAITS, typename OWNER_TYPE,
287
        typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
288
5097
void arrayTraitsWrite(const OWNER_TYPE&,
289
        BitStreamWriter& out, const typename ARRAY_TRAITS::ElementType& element)
290
{
291
5097
    ARRAY_TRAITS::write(out, element);
292
5097
}
293
294
// call the write method properly on packed array traits
295
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
296
        typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
297
384
void packedArrayTraitsWrite(const OWNER_TYPE& owner, PACKING_CONTEXT& context,
298
        BitStreamWriter& out, const typename PACKED_ARRAY_TRAITS::ElementType& element)
299
{
300
384
    PACKED_ARRAY_TRAITS::write(owner, context, out, element);
301
384
}
302
303
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
304
        typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
305
3424
void packedArrayTraitsWrite(const OWNER_TYPE&, PACKING_CONTEXT& context,
306
        BitStreamWriter& out, const typename PACKED_ARRAY_TRAITS::ElementType& element)
307
{
308
3424
    PACKED_ARRAY_TRAITS::write(context, out, element);
309
3424
}
310
311
} // namespace detail
312
313
/**
314
 * Array type enum which defined type of the underlying array.
315
 */
316
enum ArrayType
317
{
318
    NORMAL, /**< Normal zserio array which has size defined by the Zserio schema. */
319
    IMPLICIT, /**< Implicit zserio array which size is defined by number of remaining bits in the bit stream. */
320
    ALIGNED, /**< Aligned zserio array which is normal zserio array with indexed offsets. */
321
    AUTO, /**< Auto zserio array which has size stored in a hidden field before the array. */
322
    ALIGNED_AUTO /**< Aligned auto zserio array which is auto zserio array with indexed offsets. */
323
};
324
325
/**
326
 * Array wrapper for zserio arrays which are not explicitly packed but the element type is packable
327
 * and thus it can be packed if requested from a parent.
328
 */
329
/**
330
 * Array wrapper for zserio arrays which are never packed.
331
 */
332
template <typename RAW_ARRAY, typename ARRAY_TRAITS, ArrayType ARRAY_TYPE,
333
        typename ARRAY_EXPRESSIONS = detail::DummyArrayExpressions>
334
6710
class Array
335
{
336
public:
337
    /** Typedef for raw array type. */
338
    using RawArray = RAW_ARRAY;
339
340
    /** Typedef for array traits. */
341
    using ArrayTraits = ARRAY_TRAITS;
342
343
    /** Typedef for array expressions. */
344
    using ArrayExpressions = ARRAY_EXPRESSIONS;
345
346
    /**
347
     * Typedef for the array's owner type.
348
     *
349
     * Owner type is needed for proper expressions evaluation. If neither traits nor array need the owner
350
     * for expressions evaluation, detail::DummyArrayOwner is used and such array do not need the owner at all.
351
     */
352
    using OwnerType = typename detail::array_owner_type<ArrayTraits, ArrayExpressions>::type;
353
354
    /** Typedef for allocator type. */
355
    using allocator_type = typename RawArray::allocator_type;
356
357
    /**
358
     * Empty constructor.
359
     *
360
     * \param allocator Allocator to use for the raw array.
361
     */
362
10240
    explicit Array(const allocator_type& allocator = allocator_type()) :
363
10240
            m_rawArray(allocator)
364
10240
    {}
365
366
    /**
367
     * Constructor from l-value raw array.
368
     *
369
     * \param rawArray Raw array.
370
     */
371
3314
    explicit Array(const RawArray& rawArray) :
372
3314
            m_rawArray(rawArray)
373
3314
    {}
374
375
    /**
376
     * Constructor from r-value raw array.
377
     *
378
     * \param rawArray Raw array.
379
     */
380
44
    explicit Array(RawArray&& rawArray) :
381
44
            m_rawArray(std::move(rawArray))
382
44
    {}
383
384
    /**
385
     * Method generated by default.
386
     *
387
     * \{
388
     */
389
23684
    ~Array() = default;
390
3312
    Array(const Array& other) = default;
391
    Array& operator=(const Array& other) = default;
392
3398
    Array(Array&& other) = default;
393
    Array& operator=(Array&& other) = default;
394
    /**
395
     * \}
396
     */
397
398
    /**
399
     * Copy constructor which prevents initialization of parameterized elements.
400
     *
401
     * Note that elements will be initialized later by a parent compound.
402
     *
403
     * \param other Instance to construct from.
404
     */
405
    template <typename T = typename RAW_ARRAY::value_type,
406
            typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
407
64
    Array(NoInitT, const Array& other) :
408
            Array(std::allocator_traits<allocator_type>::select_on_container_copy_construction(
409
64
                    other.m_rawArray.get_allocator()))
410
    {
411


64
        m_rawArray.reserve(other.m_rawArray.size());
412


256
        for (const auto& value : other.m_rawArray)
413


192
            m_rawArray.emplace_back(NoInit, value);
414
64
    }
415
416
    /**
417
     * Assignment which prevents initialization of parameterized elements.
418
     *
419
     * Note that elements will be initialized later by a parent compound.
420
     *
421
     * \param other Instance to move-assign from.
422
     */
423
    template <typename T = typename RAW_ARRAY::value_type,
424
            typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
425
64
    Array& assign(NoInitT, const Array& other)
426
    {
427
128
        const RawArray rawArray(other.m_rawArray.get_allocator());
428


64
        m_rawArray = rawArray; // copy assign to get correct allocator propagation behaviour
429


64
        m_rawArray.reserve(other.m_rawArray.size());
430


256
        for (const auto& value : other.m_rawArray)
431


192
            m_rawArray.emplace_back(NoInit, value);
432
433
128
        return *this;
434
    }
435
436
    /**
437
     * Move constructors which prevents initialization of parameterized elements.
438
     *
439
     * Provided for convenience since vector move constructor doesn't call move constructors of its elements.
440
     *
441
     * \param other Instance to move-construct from.
442
     */
443
    template <typename T = typename RAW_ARRAY::value_type,
444
            typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
445
64
    Array(NoInitT, Array&& other) :
446
64
            Array(std::move(other))
447
    {
448
64
    }
449
450
    /**
451
     * Assignment which prevents initialization of parameterized elements.
452
     *
453
     * Provided for convenience since vector move assignment operator doesn't call move assignment operators
454
     * of its elements.
455
     *
456
     * \param other Instance to move-assign from.
457
     */
458
    template <typename T = typename RAW_ARRAY::value_type,
459
            typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
460
64
    Array& assign(NoInitT, Array&& other)
461
    {
462
64
        return operator=(std::move(other));
463
    }
464
465
    /**
466
     * Copy constructor which forces allocator propagating while copying the raw array.
467
     *
468
     * \param other Source array to copy.
469
     * \param allocator Allocator to propagate during copying.
470
     */
471
3312
    Array(PropagateAllocatorT, const Array& other, const allocator_type& allocator) :
472
3312
            m_rawArray(allocatorPropagatingCopy(other.m_rawArray, allocator))
473
3312
    {}
474
475
    /**
476
     * Copy constructor which prevents initialization and forces allocator propagating while copying
477
     * the raw array.
478
     *
479
     * \param other Source array to copy.
480
     * \param allocator Allocator to propagate during copying.
481
     */
482
    template <typename T = typename RAW_ARRAY::value_type,
483
            typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
484
64
    Array(PropagateAllocatorT, NoInitT, const Array& other, const allocator_type& allocator) :
485
64
            m_rawArray(allocatorPropagatingCopy(NoInit, other.m_rawArray, allocator))
486
64
    {}
487
488
    /**
489
     * Operator equality.
490
     *
491
     * \param other Array to compare.
492
     *
493
     * \return True when the underlying raw arrays have same contents, false otherwise.
494
     */
495
19872
    bool operator==(const Array& other) const
496
    {
497
19872
        return m_rawArray == other.m_rawArray;
498
    }
499
500
    /**
501
     * Operator less than.
502
     *
503
     * \param other Array to compare.
504
     *
505
     * \return True when the underlying raw array is less than the other underlying raw array.
506
     */
507
6624
    bool operator<(const Array& other) const
508
    {
509
6624
        return m_rawArray < other.m_rawArray;
510
    }
511
512
    /**
513
     * Hash code.
514
     *
515
     * \return Hash code calculated on the underlying raw array.
516
     */
517
1
    uint32_t hashCode() const
518
    {
519
1
        return calcHashCode(HASH_SEED, m_rawArray);
520
    }
521
522
    /**
523
     * Gets raw array.
524
     *
525
     * \return Constant reference to the raw array.
526
     */
527
20320
    const RawArray& getRawArray() const
528
    {
529
20320
        return m_rawArray;
530
    }
531
532
    /**
533
     * Gets raw array.
534
     *
535
     * \return Reference to the raw array.
536
     */
537
13908
    RawArray& getRawArray()
538
    {
539
13908
        return m_rawArray;
540
    }
541
542
    /**
543
     * Initializes array elements.
544
     *
545
     * \param owner Array owner.
546
     */
547
    template <typename ARRAY_EXPRESSIONS_ = ArrayExpressions,
548
            typename std::enable_if<has_initialize_element<ARRAY_EXPRESSIONS_>::value, int>::type = 0>
549
68
    void initializeElements(OwnerType& owner)
550
    {
551
68
        size_t index = 0;
552


263
        for (auto&& element : m_rawArray)
553
        {
554


195
            ArrayExpressions::initializeElement(owner, element, index);
555
195
            index++;
556
        }
557
68
    }
558
559
    /**
560
     * Calculates bit size of this array.
561
     *
562
     * Available for arrays which do not need the owner.
563
     *
564
     * \param bitPosition Current bit position.
565
     *
566
     * \return Bit size of the array.
567
     */
568
    template <typename OWNER_TYPE_ = OwnerType,
569
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
570
2113
    size_t bitSizeOf(size_t bitPosition) const
571
    {
572





























































































2113
        return bitSizeOfImpl(detail::DummyArrayOwner(), bitPosition);
573
    }
574
575
    /**
576
     * Calculates bit size of this array.
577
     *
578
     * Available for arrays which need the owner.
579
     *
580
     * \param owner Array owner.
581
     * \param bitPosition Current bit position.
582
     *
583
     * \return Bit size of the array.
584
     */
585
    template <typename OWNER_TYPE_ = OwnerType,
586
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
587
304
    size_t bitSizeOf(const OwnerType& owner, size_t bitPosition) const
588
    {
589
304
        return bitSizeOfImpl(owner, bitPosition);
590
    }
591
592
    /**
593
     * Initializes indexed offsets.
594
     *
595
     * Available for arrays which do not need the owner.
596
     *
597
     * \param bitPosition Current bit position.
598
     *
599
     * \return Updated bit position which points to the first bit after the array.
600
     */
601
    template <typename OWNER_TYPE_ = OwnerType,
602
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
603
2113
    size_t initializeOffsets(size_t bitPosition)
604
    {
605
        detail::DummyArrayOwner owner;
606





























































































2113
        return initializeOffsetsImpl(owner, bitPosition);
607
    }
608
609
    /**
610
     * Initializes indexed offsets.
611
     *
612
     * Available for arrays which need the owner.
613
     *
614
     * \param owner Array owner.
615
     * \param bitPosition Current bit position.
616
     *
617
     * \return Updated bit position which points to the first bit after the array.
618
     */
619
    template <typename OWNER_TYPE_ = OwnerType,
620
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
621
304
    size_t initializeOffsets(OwnerType& owner, size_t bitPosition)
622
    {
623
304
        return initializeOffsetsImpl(owner, bitPosition);
624
    }
625
626
    /**
627
     * Reads the array from the bit stream.
628
     *
629
     * Available for arrays which do not need the owner.
630
     *
631
     * \param in Bit stream reader to use for reading.
632
     * \param arrayLength Array length. Not needed for auto / implicit arrays.
633
     */
634
    template <typename OWNER_TYPE_ = OwnerType,
635
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
636
2113
    void read(BitStreamReader& in, size_t arrayLength = 0)
637
    {
638
        detail::DummyArrayOwner owner;
639





























































































2113
        readImpl(owner, in, arrayLength);
640
2112
    }
641
642
    /**
643
     * Reads the array from the bit stream.
644
     *
645
     * Available for arrays which need the owner.
646
     *
647
     * \param owner Array owner.
648
     * \param in Bit stream reader to use for reading.
649
     * \param arrayLength Array length. Not needed for auto / implicit arrays.
650
     */
651
    template <typename OWNER_TYPE_ = OwnerType,
652
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
653
304
    void read(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
654
    {
655
304
        readImpl(owner, in, arrayLength);
656
304
    }
657
658
    /**
659
     * Writes the array to the bit stream.
660
     *
661
     * Available for arrays which do not need the owner.
662
     *
663
     * \param out Bit stream write to use for writing.
664
     */
665
    template <typename OWNER_TYPE_ = OwnerType,
666
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
667
2113
    void write(BitStreamWriter& out) const
668
    {
669





























































































2113
        writeImpl(detail::DummyArrayOwner(), out);
670
2113
    }
671
672
    /**
673
     * Writes the array to the bit stream.
674
     *
675
     * Available for arrays which need the owner.
676
     *
677
     * \param owner Array owner.
678
     * \param out Bit stream write to use for writing.
679
     */
680
    template <typename OWNER_TYPE_ = OwnerType,
681
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
682
304
    void write(const OwnerType& owner, BitStreamWriter& out) const
683
    {
684
304
        writeImpl(owner, out);
685
304
    }
686
687
    /**
688
     * Returns length of the packed array stored in the bit stream in bits.
689
     *
690
     * Available for arrays which do not need the owner.
691
     *
692
     * \param bitPosition Current bit stream position.
693
     *
694
     * \return Length of the array stored in the bit stream in bits.
695
     */
696
    template <typename OWNER_TYPE_ = OwnerType,
697
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
698
800
    size_t bitSizeOfPacked(size_t bitPosition) const
699
    {
700
























800
        return bitSizeOfPackedImpl(detail::DummyArrayOwner(), bitPosition);
701
    }
702
703
    /**
704
     * Returns length of the packed array stored in the bit stream in bits.
705
     *
706
     * Available for arrays which need the owner.
707
     *
708
     * \param owner Array owner.
709
     * \param bitPosition Current bit stream position.
710
     *
711
     * \return Length of the array stored in the bit stream in bits.
712
     */
713
    template <typename OWNER_TYPE_ = OwnerType,
714
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
715
96
    size_t bitSizeOfPacked(const OwnerType& ownerType, size_t bitPosition) const
716
    {
717
96
        return bitSizeOfPackedImpl(ownerType, bitPosition);
718
    }
719
720
    /**
721
     * Initializes indexed offsets for the packed array.
722
     *
723
     * Available for arrays which do not need the owner.
724
     *
725
     * \param bitPosition Current bit stream position.
726
     *
727
     * \return Updated bit stream position which points to the first bit after the array.
728
     */
729
    template <typename OWNER_TYPE_ = OwnerType,
730
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
731
800
    size_t initializeOffsetsPacked(size_t bitPosition)
732
    {
733
        detail::DummyArrayOwner owner;
734
























800
        return initializeOffsetsPackedImpl(owner, bitPosition);
735
    }
736
737
    /**
738
     * Initializes indexed offsets for the packed array.
739
     *
740
     * Available for arrays which need the owner.
741
     *
742
     * \param owner Array owner.
743
     * \param bitPosition Current bit stream position.
744
     *
745
     * \return Updated bit stream position which points to the first bit after the array.
746
     */
747
    template <typename OWNER_TYPE_ = OwnerType,
748
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
749
96
    size_t initializeOffsetsPacked(OwnerType& owner, size_t bitPosition)
750
    {
751
96
        return initializeOffsetsPackedImpl(owner, bitPosition);
752
    }
753
754
    /**
755
     * Reads packed array from the bit stream.
756
     *
757
     * Available for arrays which do not need the owner.
758
     *
759
     * \param in Bit stream from which to read.
760
     * \param arrayLength Number of elements to read or 0 in case of auto arrays.
761
     */
762
    template <typename OWNER_TYPE_ = OwnerType,
763
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
764
800
    void readPacked(BitStreamReader& in, size_t arrayLength = 0)
765
    {
766
        detail::DummyArrayOwner owner;
767
























800
        readPackedImpl(owner, in, arrayLength);
768
800
    }
769
770
    /**
771
     * Reads packed array from the bit stream.
772
     *
773
     * Available for arrays which need the owner.
774
     *
775
     * \param owner Array owner.
776
     * \param in Bit stream from which to read.
777
     * \param arrayLength Number of elements to read or 0 in case of auto arrays.
778
     */
779
    template <typename OWNER_TYPE_ = OwnerType,
780
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
781
96
    void readPacked(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
782
    {
783
96
        readPackedImpl(owner, in, arrayLength);
784
96
    }
785
786
    /**
787
     * Writes packed array to the bit stream.
788
     *
789
     * Available for arrays which do not need the owner.
790
     *
791
     * \param out Bit stream where to write.
792
     */
793
    template <typename OWNER_TYPE_ = OwnerType,
794
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
795
800
    void writePacked(BitStreamWriter& out) const
796
    {
797
























800
        writePackedImpl(detail::DummyArrayOwner(), out);
798
800
    }
799
800
    /**
801
     * Writes packed array to the bit stream.
802
     *
803
     * Available for arrays which need the owner.
804
     *
805
     * \param owner Array owner.
806
     * \param out Bit stream where to write.
807
     */
808
    template <typename OWNER_TYPE_ = OwnerType,
809
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
810
96
    void writePacked(const OwnerType& owner, BitStreamWriter& out) const
811
    {
812
96
        writePackedImpl(owner, out);
813
96
    }
814
815
private:
816
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
817
            typename std::enable_if<
818
                    ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO, int>::type = 0>
819
3458
    static void addBitSizeOfArrayLength(size_t&, size_t)
820
3458
    {}
821
822
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
823
            typename std::enable_if<
824
                    ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
825
3168
    static void addBitSizeOfArrayLength(size_t& bitPosition, size_t arrayLength)
826
    {
827
3168
        bitPosition += bitSizeOfVarSize(convertSizeToUInt32(arrayLength));
828
3168
    }
829
830
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
831
            typename std::enable_if<
832
                    ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO, int>::type = 0>
833
3281
    static void alignBitPosition(size_t&)
834
3281
    {}
835
836
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
837
            typename std::enable_if<
838
                    ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
839
3280
    static void alignBitPosition(size_t& bitPosition)
840
    {
841
3280
        bitPosition = alignTo(8, bitPosition);
842
3280
    }
843
844
    template <typename IO, typename OWNER_TYPE, ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
845
            typename std::enable_if<
846
                    ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO, int>::type = 0>
847
10034
    static void alignAndCheckOffset(IO&, OWNER_TYPE&, size_t)
848
10034
    {}
849
850
    template <typename IO, typename OWNER_TYPE, ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
851
            typename std::enable_if<
852
                    ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
853
9408
    static void alignAndCheckOffset(IO& io, OWNER_TYPE& owner, size_t index)
854
    {
855
9408
        io.alignTo(8);
856
9408
        detail::checkOffset<ArrayExpressions>(owner, index, io.getBitPosition() / 8);
857
9408
    }
858
859
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
860
            typename std::enable_if<
861
                    ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO, int>::type = 0>
862
5017
    static void initializeOffset(OwnerType&, size_t, size_t&)
863
5017
    {}
864
865
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
866
            typename std::enable_if<
867
                    ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
868
4704
    static void initializeOffset(OwnerType& owner, size_t index, size_t& bitPosition)
869
    {
870
4704
        bitPosition = alignTo(8, bitPosition);
871
4704
        detail::initializeOffset<ArrayExpressions>(owner, index, bitPosition / 8);
872
4704
    }
873
874
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
875
            typename std::enable_if<
876
                    ARRAY_TYPE_ != ArrayType::AUTO &&
877
                    ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO &&
878
                    ARRAY_TYPE_ != ArrayType::IMPLICIT, int>::type = 0>
879
1585
    static size_t readArrayLength(OwnerType&, BitStreamReader&, size_t arrayLength)
880
    {
881
1585
        return arrayLength;
882
    }
883
884
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
885
            typename std::enable_if<
886
                    ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
887
1584
    static size_t readArrayLength(OwnerType&, BitStreamReader& in, size_t)
888
    {
889
1584
        return in.readVarSize();
890
    }
891
892
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
893
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::IMPLICIT, int>::type = 0>
894
144
    static size_t readArrayLength(OwnerType& owner, BitStreamReader& in, size_t)
895
    {
896
        static_assert(ARRAY_TYPE != ArrayType::IMPLICIT || ArrayTraits::IS_BITSIZEOF_CONSTANT,
897
                "Implicit array elements must have constant bit size!");
898
899
144
        const size_t remainingBits = in.getBufferBitSize() - in.getBitPosition();
900
144
        return remainingBits / detail::arrayTraitsConstBitSizeOf<ArrayTraits>(owner);
901
    }
902
903
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
904
            typename std::enable_if<
905
                    ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO, int>::type = 0>
906
1729
    static void writeArrayLength(BitStreamWriter&, size_t)
907
1729
    {}
908
909
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
910
            typename std::enable_if<
911
                    ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
912
1584
    static void writeArrayLength(BitStreamWriter& out, size_t arrayLength)
913
    {
914
1584
        out.writeVarSize(convertSizeToUInt32(arrayLength));
915
1584
    }
916
917
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
918
            typename std::enable_if<
919
                    ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO, int>::type = 0>
920
584
    static size_t constBitSizeOfElements(size_t, size_t arrayLength, size_t elementBitSize)
921
    {
922
584
        return arrayLength * elementBitSize;
923
    }
924
925
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
926
            typename std::enable_if<
927
                    ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
928
480
    static size_t constBitSizeOfElements(size_t bitPosition, size_t arrayLength, size_t elementBitSize)
929
    {
930
480
        size_t endBitPosition = alignTo(8, bitPosition);
931
480
        endBitPosition += elementBitSize + (arrayLength - 1) * alignTo(8, elementBitSize);
932
933
480
        return endBitPosition - bitPosition;
934
    }
935
936
    template <typename ARRAY_TRAITS_ = ArrayTraits,
937
            typename std::enable_if<ARRAY_TRAITS_::IS_BITSIZEOF_CONSTANT, int>::type = 0>
938
1424
    size_t bitSizeOfImpl(const OwnerType& owner, size_t bitPosition) const
939
    {
940
1424
        size_t endBitPosition = bitPosition;
941
942
1424
        const size_t arrayLength = m_rawArray.size();
943






























1424
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
944
945











































































1424
        if (arrayLength > 0)
946
        {
947

































































1064
            const size_t elementBitSize = detail::arrayTraitsConstBitSizeOf<ArrayTraits>(owner);
948
1064
            endBitPosition += constBitSizeOfElements(endBitPosition, arrayLength, elementBitSize);
949
        }
950
951
1424
        return endBitPosition - bitPosition;
952
    }
953
954
    template <typename ARRAY_TRAITS_ = ArrayTraits,
955
            typename std::enable_if<!ARRAY_TRAITS_::IS_BITSIZEOF_CONSTANT, int>::type = 0>
956
993
    size_t bitSizeOfImpl(const OwnerType& owner, size_t bitPosition) const
957
    {
958
993
        size_t endBitPosition = bitPosition;
959
960
993
        const size_t arrayLength = m_rawArray.size();
961

















993
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
962
963
































3746
        for (size_t index = 0; index < arrayLength; ++index)
964
        {
965
2753
            alignBitPosition(endBitPosition);
966
































2753
            endBitPosition += detail::arrayTraitsBitSizeOf<ArrayTraits>(
967
2753
                    owner, endBitPosition, m_rawArray[index]);
968
        }
969
970
993
        return endBitPosition - bitPosition;
971
    }
972
973
2417
    size_t initializeOffsetsImpl(OwnerType& owner, size_t bitPosition)
974
    {
975
2417
        size_t endBitPosition = bitPosition;
976
977
2417
        const size_t arrayLength = m_rawArray.size();
978















































2417
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
979
980











































































































8330
        for (size_t index = 0; index < arrayLength; ++index)
981
        {
982





































5913
            initializeOffset(owner, index, endBitPosition);
983

































































































5913
            endBitPosition = detail::arrayTraitsInitializeOffsets<ArrayTraits>(
984
5913
                    owner, endBitPosition, m_rawArray[index]);
985
        }
986
987
2417
        return endBitPosition;
988
    }
989
990
2417
    void readImpl(OwnerType& owner, BitStreamReader& in, size_t arrayLength)
991
    {
992
2417
        size_t readLength = readArrayLength(owner, in, arrayLength);
993
994
2417
        m_rawArray.clear();
995
2417
        m_rawArray.reserve(readLength);
996











































































































8329
        for (size_t index = 0; index < readLength; ++index)
997
        {
998
5913
            alignAndCheckOffset(in, owner, index);
999
5913
            detail::arrayTraitsRead<ArrayTraits>(owner, m_rawArray, in, index);
1000
        }
1001
2416
    }
1002
1003
2417
    void writeImpl(const OwnerType& owner, BitStreamWriter& out) const
1004
    {
1005
2417
        const size_t arrayLength = m_rawArray.size();
1006
2417
        writeArrayLength(out, arrayLength);
1007
1008











































































































8330
        for (size_t index = 0; index < arrayLength; ++index)
1009
        {
1010
5913
            alignAndCheckOffset(out, owner, index);
1011


5913
            detail::arrayTraitsWrite<ArrayTraits>(owner, out, m_rawArray[index]);
1012
        }
1013
2417
    }
1014
1015
    using PackingContext = typename detail::packing_context_type<typename RawArray::value_type>::type;
1016
1017
896
    size_t bitSizeOfPackedImpl(const OwnerType& owner, size_t bitPosition) const
1018
    {
1019
        static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1020
1021
896
        size_t endBitPosition = bitPosition;
1022
1023
896
        const size_t arrayLength = m_rawArray.size();
1024















896
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
1025
1026






























896
        if (arrayLength > 0)
1027
        {
1028
832
            PackingContext context;
1029
1030






























4640
            for (size_t index = 0; index < arrayLength; ++index)
1031
            {
1032
































3808
                detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1033
3808
                        owner, context, m_rawArray[index]);
1034
            }
1035
1036






























4640
            for (size_t index = 0; index < arrayLength; ++index)
1037
            {
1038
3808
                alignBitPosition(endBitPosition);
1039






























3808
                endBitPosition += detail::packedArrayTraitsBitSizeOf<PackedArrayTraits<ArrayTraits>>(
1040
3808
                        owner, context, endBitPosition, m_rawArray[index]);
1041
            }
1042
        }
1043
1044
896
        return endBitPosition - bitPosition;
1045
    }
1046
1047
896
    size_t initializeOffsetsPackedImpl(OwnerType& owner, size_t bitPosition)
1048
    {
1049
        static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1050
1051
896
        size_t endBitPosition = bitPosition;
1052
1053
896
        const size_t arrayLength = m_rawArray.size();
1054















896
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
1055
1056






























896
        if (arrayLength > 0)
1057
        {
1058
832
            PackingContext context;
1059
1060






























4640
            for (size_t index = 0; index < arrayLength; ++index)
1061
            {
1062
































3808
                detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1063
3808
                        owner, context, m_rawArray[index]);
1064
            }
1065
1066






























4640
            for (size_t index = 0; index < arrayLength; ++index)
1067
            {
1068












3808
                initializeOffset(owner, index, endBitPosition);
1069






























3808
                endBitPosition = detail::packedArrayTraitsInitializeOffsets<PackedArrayTraits<ArrayTraits>>(
1070
3808
                        owner, context, endBitPosition, m_rawArray[index]);
1071
            }
1072
        }
1073
1074
896
        return endBitPosition;
1075
    }
1076
1077
896
    void readPackedImpl(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
1078
    {
1079
        static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1080
1081
896
        size_t readLength = readArrayLength(owner, in, arrayLength);
1082
1083
896
        m_rawArray.clear();
1084
1085






























896
        if (readLength > 0)
1086
        {
1087






























832
            m_rawArray.reserve(readLength);
1088
1089
832
            PackingContext context;
1090
1091






























4640
            for (size_t index = 0; index < readLength; ++index)
1092
            {
1093















3808
                alignAndCheckOffset(in, owner, index);
1094






























3808
                detail::packedArrayTraitsRead<PackedArrayTraits<ArrayTraits>>(
1095
                        owner, m_rawArray, context, in, index);
1096
            }
1097
        }
1098
896
    }
1099
1100
896
    void writePackedImpl(const OwnerType& owner, BitStreamWriter& out) const
1101
    {
1102
        static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1103
1104
896
        const size_t arrayLength = m_rawArray.size();
1105
896
        writeArrayLength(out, arrayLength);
1106
1107






























896
        if (arrayLength > 0)
1108
        {
1109
832
            PackingContext context;
1110
1111






























4640
            for (size_t index = 0; index < arrayLength; ++index)
1112
            {
1113
































3808
                detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1114
3808
                        owner, context, m_rawArray[index]);
1115
            }
1116
1117






























4640
            for (size_t index = 0; index < arrayLength; ++index)
1118
            {
1119















3808
                alignAndCheckOffset(out, owner, index);
1120






























3808
                detail::packedArrayTraitsWrite<PackedArrayTraits<ArrayTraits>>(
1121
3808
                        owner, context, out, m_rawArray[index]);
1122
            }
1123
        }
1124
896
    }
1125
1126
    RawArray m_rawArray;
1127
};
1128
1129
/**
1130
 * Helper for creating an optional array within templated field constructor, where the raw array can be
1131
 * actually the NullOpt.
1132
 */
1133
template <typename ARRAY, typename RAW_ARRAY>
1134
1
ARRAY createOptionalArray(RAW_ARRAY&& rawArray)
1135
{
1136
1
    return ARRAY(std::forward<RAW_ARRAY>(rawArray));
1137
}
1138
1139
/**
1140
 * Overload for NullOpt.
1141
 */
1142
template <typename ARRAY>
1143
14
NullOptType createOptionalArray(NullOptType)
1144
{
1145
14
    return NullOpt;
1146
}
1147
1148
} // namespace zserio
1149
1150
#endif // ZSERIO_ARRAY_H_INC