Coverage Report

Created: 2023-12-13 14:58

src/zserio/Array.h
Line
Count
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
void initializeOffset(OWNER_TYPE& owner, size_t index, size_t bitPosition)
70
192
{
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
void initializeOffset(OWNER_TYPE&, size_t, size_t)
77
4.51k
{}
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
384
{
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
void checkOffset(const OWNER_TYPE&, size_t, size_t)
90
9.02k
{}
91
92
// call the initContext method properly on packed array traits
93
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
94
        typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
95
void packedArrayTraitsInitContext(const OWNER_TYPE& owner, PACKING_CONTEXT& context,
96
        typename PACKED_ARRAY_TRAITS::ElementType element)
97
1.15k
{
98
1.15k
    PACKED_ARRAY_TRAITS::initContext(owner, context, element);
99
1.15k
}
100
101
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
102
        typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
103
void packedArrayTraitsInitContext(const OWNER_TYPE&, PACKING_CONTEXT& context,
104
        typename PACKED_ARRAY_TRAITS::ElementType element)
105
10.2k
{
106
10.2k
    PACKED_ARRAY_TRAITS::initContext(context, element);
107
10.2k
}
108
109
// calls the bitSizeOf method properly on array traits which have constant bit size
110
template <typename ARRAY_TRAITS, typename OWNER_TYPE,
111
        typename std::enable_if<
112
                ARRAY_TRAITS::IS_BITSIZEOF_CONSTANT && has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
113
size_t arrayTraitsConstBitSizeOf(const OWNER_TYPE& owner)
114
230
{
115
230
    return ARRAY_TRAITS::bitSizeOf(owner);
116
230
}
117
118
template <typename ARRAY_TRAITS, typename OWNER_TYPE,
119
        typename std::enable_if<
120
                ARRAY_TRAITS::IS_BITSIZEOF_CONSTANT && !has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
121
size_t arrayTraitsConstBitSizeOf(const OWNER_TYPE&)
122
1.01k
{
123
1.01k
    return ARRAY_TRAITS::bitSizeOf();
124
1.01k
}
125
126
// calls the bitSizeOf method properly on array traits which haven't constant bit size
127
template <typename ARRAY_TRAITS, typename OWNER_TYPE,
128
        typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
129
size_t arrayTraitsBitSizeOf(const OWNER_TYPE& owner, size_t bitPosition,
130
        const typename ARRAY_TRAITS::ElementType& element)
131
192
{
132
192
    return ARRAY_TRAITS::bitSizeOf(owner, bitPosition, element);
133
192
}
134
135
template <typename ARRAY_TRAITS, typename OWNER_TYPE,
136
        typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
137
size_t arrayTraitsBitSizeOf(const OWNER_TYPE&, size_t bitPosition,
138
        const typename ARRAY_TRAITS::ElementType& element)
139
2.56k
{
140
2.56k
    return ARRAY_TRAITS::bitSizeOf(bitPosition, element);
141
2.56k
}
142
143
// calls the bitSizeOf method properly on packed array traits which haven't constant bit size
144
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
145
        typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
146
size_t packedArrayTraitsBitSizeOf(const OWNER_TYPE& owner, PACKING_CONTEXT& context,
147
        size_t bitPosition, const typename PACKED_ARRAY_TRAITS::ElementType& element)
148
384
{
149
384
    return PACKED_ARRAY_TRAITS::bitSizeOf(owner, context, bitPosition, element);
150
384
}
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
3.42k
{
157
3.42k
    return PACKED_ARRAY_TRAITS::bitSizeOf(context, bitPosition, element);
158
3.42k
}
159
160
// calls the initializeOffsets method properly on array traits
161
template <typename ARRAY_TRAITS, typename OWNER_TYPE,
162
        typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
163
size_t arrayTraitsInitializeOffsets(OWNER_TYPE& owner, size_t bitPosition,
164
        typename ARRAY_TRAITS::ElementType& element)
165
816
{
166
816
    return ARRAY_TRAITS::initializeOffsets(owner, bitPosition, element);
167
816
}
168
169
template <typename ARRAY_TRAITS, typename OWNER_TYPE,
170
        typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
171
                !std::is_scalar<typename ARRAY_TRAITS::ElementType>::value, int>::type = 0>
172
size_t arrayTraitsInitializeOffsets(OWNER_TYPE&, size_t bitPosition,
173
        const typename ARRAY_TRAITS::ElementType& element)
174
352
{
175
352
    return ARRAY_TRAITS::initializeOffsets(bitPosition, element);
176
352
}
177
178
template <typename ARRAY_TRAITS, typename OWNER_TYPE,
179
        typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
180
                std::is_scalar<typename ARRAY_TRAITS::ElementType>::value, int>::type = 0>
181
size_t arrayTraitsInitializeOffsets(OWNER_TYPE&, size_t bitPosition, typename ARRAY_TRAITS::ElementType element)
182
4.74k
{
183
4.74k
    return ARRAY_TRAITS::initializeOffsets(bitPosition, element);
184
4.74k
}
185
186
// calls the initializeOffsets method properly on packed array traits
187
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
188
        typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
189
size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE& owner, PACKING_CONTEXT& context,
190
        size_t bitPosition, typename PACKED_ARRAY_TRAITS::ElementType& element)
191
384
{
192
384
    return PACKED_ARRAY_TRAITS::initializeOffsets(owner, context, bitPosition, element);
193
384
}
194
195
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
196
        typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
197
                !std::is_scalar<typename PACKED_ARRAY_TRAITS::ElementType>::value, int>::type = 0>
198
size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE&, PACKING_CONTEXT& context,
199
        size_t bitPosition, const typename PACKED_ARRAY_TRAITS::ElementType& element)
200
96
{
201
96
    return PACKED_ARRAY_TRAITS::initializeOffsets(context, bitPosition, element);
202
96
}
203
204
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
205
        typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
206
                std::is_scalar<typename PACKED_ARRAY_TRAITS::ElementType>::value, int>::type = 0>
207
size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE&, PACKING_CONTEXT& context,
208
        size_t bitPosition, typename PACKED_ARRAY_TRAITS::ElementType element)
209
3.32k
{
210
3.32k
    return PACKED_ARRAY_TRAITS::initializeOffsets(context, bitPosition, element);
211
3.32k
}
212
213
// calls the read method properly on array traits
214
template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
215
        typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value &&
216
                !has_allocator<ARRAY_TRAITS>::value, int>::type = 0>
217
void arrayTraitsRead(const OWNER_TYPE& owner, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
218
624
{
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
void arrayTraitsRead(OWNER_TYPE& owner, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
226
192
{
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
void arrayTraitsRead(const OWNER_TYPE&, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
234
4.84k
{
235
4.84k
    rawArray.push_back(ARRAY_TRAITS::read(in, index));
236
4.84k
}
237
238
template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
239
        typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
240
                has_allocator<ARRAY_TRAITS>::value, int>::type = 0>
241
void arrayTraitsRead(const OWNER_TYPE&, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
242
256
{
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
void packedArrayTraitsRead(OWNER_TYPE& owner, RAW_ARRAY& rawArray, PACKING_CONTEXT& context,
251
        BitStreamReader& in, size_t index)
252
192
{
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
void packedArrayTraitsRead(const OWNER_TYPE& owner, RAW_ARRAY& rawArray, PACKING_CONTEXT& context,
260
        BitStreamReader& in, size_t index)
261
192
{
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
void packedArrayTraitsRead(const OWNER_TYPE&, RAW_ARRAY& rawArray, PACKING_CONTEXT& context,
272
        BitStreamReader& in, size_t index)
273
3.42k
{
274
3.42k
    rawArray.push_back(PACKED_ARRAY_TRAITS::read(context, in, index));
275
3.42k
}
276
277
// call the write method properly on array traits
278
template <typename ARRAY_TRAITS, typename OWNER_TYPE,
279
        typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
280
void arrayTraitsWrite(const OWNER_TYPE& owner,
281
        BitStreamWriter& out, const typename ARRAY_TRAITS::ElementType& element)
282
816
{
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
void arrayTraitsWrite(const OWNER_TYPE&,
289
        BitStreamWriter& out, const typename ARRAY_TRAITS::ElementType& element)
290
5.09k
{
291
5.09k
    ARRAY_TRAITS::write(out, element);
292
5.09k
}
293
294
// call the write method properly on packed array traits
295
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
296
        typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
297
void packedArrayTraitsWrite(const OWNER_TYPE& owner, PACKING_CONTEXT& context,
298
        BitStreamWriter& out, const typename PACKED_ARRAY_TRAITS::ElementType& element)
299
384
{
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
void packedArrayTraitsWrite(const OWNER_TYPE&, PACKING_CONTEXT& context,
306
        BitStreamWriter& out, const typename PACKED_ARRAY_TRAITS::ElementType& element)
307
3.42k
{
308
3.42k
    PACKED_ARRAY_TRAITS::write(context, out, element);
309
3.42k
}
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
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
    explicit Array(const allocator_type& allocator = allocator_type()) :
363
            m_rawArray(allocator)
364
10.2k
    {}
365
366
    /**
367
     * Constructor from l-value raw array.
368
     *
369
     * \param rawArray Raw array.
370
     */
371
    explicit Array(const RawArray& rawArray) :
372
            m_rawArray(rawArray)
373
3.31k
    {}
374
375
    /**
376
     * Constructor from r-value raw array.
377
     *
378
     * \param rawArray Raw array.
379
     */
380
    explicit Array(RawArray&& rawArray) :
381
            m_rawArray(std::move(rawArray))
382
44
    {}
383
384
    /**
385
     * Method generated by default.
386
     *
387
     * \{
388
     */
389
23.6k
    ~Array() = default;
390
3.31k
    Array(const Array& other) = default;
391
3.31k
    Array& operator=(const Array& other) = default;
392
3.39k
    Array(Array&& other) = default;
393
3.39k
    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
    Array(NoInitT, const Array& other) :
408
            Array(std::allocator_traits<allocator_type>::select_on_container_copy_construction(
409
                    other.m_rawArray.get_allocator()))
410
64
    {
411
64
        m_rawArray.reserve(other.m_rawArray.size());
412
64
        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
    Array& assign(NoInitT, const Array& other)
426
64
    {
427
64
        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
64
        for (const auto& value : other.m_rawArray)
431
192
            m_rawArray.emplace_back(NoInit, value);
432
433
64
        return *this;
434
64
    }
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
    Array(NoInitT, Array&& other) :
446
            Array(std::move(other))
447
64
    {
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
    Array& assign(NoInitT, Array&& other)
461
64
    {
462
64
        return operator=(std::move(other));
463
64
    }
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
    Array(PropagateAllocatorT, const Array& other, const allocator_type& allocator) :
472
            m_rawArray(allocatorPropagatingCopy(other.m_rawArray, allocator))
473
3.31k
    {}
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
    Array(PropagateAllocatorT, NoInitT, const Array& other, const allocator_type& allocator) :
485
            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
    bool operator==(const Array& other) const
496
19.8k
    {
497
19.8k
        return m_rawArray == other.m_rawArray;
498
19.8k
    }
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
    bool operator<(const Array& other) const
508
6.62k
    {
509
6.62k
        return m_rawArray < other.m_rawArray;
510
6.62k
    }
511
512
    /**
513
     * Hash code.
514
     *
515
     * \return Hash code calculated on the underlying raw array.
516
     */
517
    uint32_t hashCode() const
518
1
    {
519
1
        return calcHashCode(HASH_SEED, m_rawArray);
520
1
    }
521
522
    /**
523
     * Gets raw array.
524
     *
525
     * \return Constant reference to the raw array.
526
     */
527
    const RawArray& getRawArray() const
528
20.3k
    {
529
20.3k
        return m_rawArray;
530
20.3k
    }
531
532
    /**
533
     * Gets raw array.
534
     *
535
     * \return Reference to the raw array.
536
     */
537
    RawArray& getRawArray()
538
13.9k
    {
539
13.9k
        return m_rawArray;
540
13.9k
    }
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
    void initializeElements(OwnerType& owner)
550
68
    {
551
68
        size_t index = 0;
552
68
        for (auto&& element : m_rawArray)
553
195
        {
554
195
            ArrayExpressions::initializeElement(owner, element, index);
555
195
            index++;
556
195
        }
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
    size_t bitSizeOf(size_t bitPosition) const
571
2.11k
    {
572
2.11k
        return bitSizeOfImpl(detail::DummyArrayOwner(), bitPosition);
573
2.11k
    }
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
    size_t bitSizeOf(const OwnerType& owner, size_t bitPosition) const
588
304
    {
589
304
        return bitSizeOfImpl(owner, bitPosition);
590
304
    }
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
    size_t initializeOffsets(size_t bitPosition)
604
2.11k
    {
605
2.11k
        detail::DummyArrayOwner owner;
606
2.11k
        return initializeOffsetsImpl(owner, bitPosition);
607
2.11k
    }
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
    size_t initializeOffsets(OwnerType& owner, size_t bitPosition)
622
304
    {
623
304
        return initializeOffsetsImpl(owner, bitPosition);
624
304
    }
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
    void read(BitStreamReader& in, size_t arrayLength = 0)
637
2.11k
    {
638
2.11k
        detail::DummyArrayOwner owner;
639
2.11k
        readImpl(owner, in, arrayLength);
640
2.11k
    }
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
    void read(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
654
304
    {
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
    void write(BitStreamWriter& out) const
668
2.11k
    {
669
2.11k
        writeImpl(detail::DummyArrayOwner(), out);
670
2.11k
    }
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
    void write(const OwnerType& owner, BitStreamWriter& out) const
683
304
    {
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
    size_t bitSizeOfPacked(size_t bitPosition) const
699
800
    {
700
800
        return bitSizeOfPackedImpl(detail::DummyArrayOwner(), bitPosition);
701
800
    }
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
    size_t bitSizeOfPacked(const OwnerType& ownerType, size_t bitPosition) const
716
96
    {
717
96
        return bitSizeOfPackedImpl(ownerType, bitPosition);
718
96
    }
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
    size_t initializeOffsetsPacked(size_t bitPosition)
732
800
    {
733
800
        detail::DummyArrayOwner owner;
734
800
        return initializeOffsetsPackedImpl(owner, bitPosition);
735
800
    }
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
    size_t initializeOffsetsPacked(OwnerType& owner, size_t bitPosition)
750
96
    {
751
96
        return initializeOffsetsPackedImpl(owner, bitPosition);
752
96
    }
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
    void readPacked(BitStreamReader& in, size_t arrayLength = 0)
765
800
    {
766
800
        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
    void readPacked(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
782
96
    {
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
    void writePacked(BitStreamWriter& out) const
796
800
    {
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
    void writePacked(const OwnerType& owner, BitStreamWriter& out) const
811
96
    {
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
    static void addBitSizeOfArrayLength(size_t&, size_t)
820
3.45k
    {}
821
822
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
823
            typename std::enable_if<
824
                    ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
825
    static void addBitSizeOfArrayLength(size_t& bitPosition, size_t arrayLength)
826
3.16k
    {
827
3.16k
        bitPosition += bitSizeOfVarSize(convertSizeToUInt32(arrayLength));
828
3.16k
    }
829
830
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
831
            typename std::enable_if<
832
                    ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO, int>::type = 0>
833
    static void alignBitPosition(size_t&)
834
3.28k
    {}
835
836
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
837
            typename std::enable_if<
838
                    ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
839
    static void alignBitPosition(size_t& bitPosition)
840
3.28k
    {
841
3.28k
        bitPosition = alignTo(8, bitPosition);
842
3.28k
    }
843
844
    template <typename IO, typename OWNER_TYPE, ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
845
            typename std::enable_if<
846
                    ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO, int>::type = 0>
847
    static void alignAndCheckOffset(IO&, OWNER_TYPE&, size_t)
848
10.0k
    {}
849
850
    template <typename IO, typename OWNER_TYPE, ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
851
            typename std::enable_if<
852
                    ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
853
    static void alignAndCheckOffset(IO& io, OWNER_TYPE& owner, size_t index)
854
9.40k
    {
855
9.40k
        io.alignTo(8);
856
9.40k
        detail::checkOffset<ArrayExpressions>(owner, index, io.getBitPosition() / 8);
857
9.40k
    }
858
859
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
860
            typename std::enable_if<
861
                    ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO, int>::type = 0>
862
    static void initializeOffset(OwnerType&, size_t, size_t&)
863
5.01k
    {}
864
865
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
866
            typename std::enable_if<
867
                    ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
868
    static void initializeOffset(OwnerType& owner, size_t index, size_t& bitPosition)
869
4.70k
    {
870
4.70k
        bitPosition = alignTo(8, bitPosition);
871
4.70k
        detail::initializeOffset<ArrayExpressions>(owner, index, bitPosition / 8);
872
4.70k
    }
873
874
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
875
            typename std::enable_if<
876
                    ARRAY_TYPE_ != ArrayType::AUTO &&
877
                    ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO &&
878
                    ARRAY_TYPE_ != ArrayType::IMPLICIT, int>::type = 0>
879
    static size_t readArrayLength(OwnerType&, BitStreamReader&, size_t arrayLength)
880
1.58k
    {
881
1.58k
        return arrayLength;
882
1.58k
    }
883
884
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
885
            typename std::enable_if<
886
                    ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
887
    static size_t readArrayLength(OwnerType&, BitStreamReader& in, size_t)
888
1.58k
    {
889
1.58k
        return in.readVarSize();
890
1.58k
    }
891
892
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
893
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::IMPLICIT, int>::type = 0>
894
    static size_t readArrayLength(OwnerType& owner, BitStreamReader& in, size_t)
895
144
    {
896
144
        static_assert(ARRAY_TYPE != ArrayType::IMPLICIT || ArrayTraits::IS_BITSIZEOF_CONSTANT,
897
144
                "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
144
    }
902
903
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
904
            typename std::enable_if<
905
                    ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO, int>::type = 0>
906
    static void writeArrayLength(BitStreamWriter&, size_t)
907
1.72k
    {}
908
909
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
910
            typename std::enable_if<
911
                    ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
912
    static void writeArrayLength(BitStreamWriter& out, size_t arrayLength)
913
1.58k
    {
914
1.58k
        out.writeVarSize(convertSizeToUInt32(arrayLength));
915
1.58k
    }
916
917
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
918
            typename std::enable_if<
919
                    ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO, int>::type = 0>
920
    static size_t constBitSizeOfElements(size_t, size_t arrayLength, size_t elementBitSize)
921
584
    {
922
584
        return arrayLength * elementBitSize;
923
584
    }
924
925
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
926
            typename std::enable_if<
927
                    ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO, int>::type = 0>
928
    static size_t constBitSizeOfElements(size_t bitPosition, size_t arrayLength, size_t elementBitSize)
929
480
    {
930
480
        size_t endBitPosition = alignTo(8, bitPosition);
931
480
        endBitPosition += elementBitSize + (arrayLength - 1) * alignTo(8, elementBitSize);
932
933
480
        return endBitPosition - bitPosition;
934
480
    }
935
936
    template <typename ARRAY_TRAITS_ = ArrayTraits,
937
            typename std::enable_if<ARRAY_TRAITS_::IS_BITSIZEOF_CONSTANT, int>::type = 0>
938
    size_t bitSizeOfImpl(const OwnerType& owner, size_t bitPosition) const
939
1.42k
    {
940
1.42k
        size_t endBitPosition = bitPosition;
941
942
1.42k
        const size_t arrayLength = m_rawArray.size();
943
1.42k
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
944
945
1.42k
        if (arrayLength > 0)
946
1.06k
        {
947
1.06k
            const size_t elementBitSize = detail::arrayTraitsConstBitSizeOf<ArrayTraits>(owner);
948
1.06k
            endBitPosition += constBitSizeOfElements(endBitPosition, arrayLength, elementBitSize);
949
1.06k
        }
950
951
1.42k
        return endBitPosition - bitPosition;
952
1.42k
    }
953
954
    template <typename ARRAY_TRAITS_ = ArrayTraits,
955
            typename std::enable_if<!ARRAY_TRAITS_::IS_BITSIZEOF_CONSTANT, int>::type = 0>
956
    size_t bitSizeOfImpl(const OwnerType& owner, size_t bitPosition) const
957
993
    {
958
993
        size_t endBitPosition = bitPosition;
959
960
993
        const size_t arrayLength = m_rawArray.size();
961
993
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
962
963
3.74k
        for (size_t index = 0; index < arrayLength; 
++index2.75k
)
964
2.75k
        {
965
2.75k
            alignBitPosition(endBitPosition);
966
2.75k
            endBitPosition += detail::arrayTraitsBitSizeOf<ArrayTraits>(
967
2.75k
                    owner, endBitPosition, m_rawArray[index]);
968
2.75k
        }
969
970
993
        return endBitPosition - bitPosition;
971
993
    }
972
973
    size_t initializeOffsetsImpl(OwnerType& owner, size_t bitPosition)
974
2.41k
    {
975
2.41k
        size_t endBitPosition = bitPosition;
976
977
2.41k
        const size_t arrayLength = m_rawArray.size();
978
2.41k
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
979
980
8.33k
        for (size_t index = 0; index < arrayLength; 
++index5.91k
)
981
5.91k
        {
982
5.91k
            initializeOffset(owner, index, endBitPosition);
983
5.91k
            endBitPosition = detail::arrayTraitsInitializeOffsets<ArrayTraits>(
984
5.91k
                    owner, endBitPosition, m_rawArray[index]);
985
5.91k
        }
986
987
2.41k
        return endBitPosition;
988
2.41k
    }
989
990
    void readImpl(OwnerType& owner, BitStreamReader& in, size_t arrayLength)
991
2.41k
    {
992
2.41k
        size_t readLength = readArrayLength(owner, in, arrayLength);
993
994
2.41k
        m_rawArray.clear();
995
2.41k
        m_rawArray.reserve(readLength);
996
8.33k
        for (size_t index = 0; index < readLength; 
++index5.91k
)
997
5.91k
        {
998
5.91k
            alignAndCheckOffset(in, owner, index);
999
5.91k
            detail::arrayTraitsRead<ArrayTraits>(owner, m_rawArray, in, index);
1000
5.91k
        }
1001
2.41k
    }
1002
1003
    void writeImpl(const OwnerType& owner, BitStreamWriter& out) const
1004
2.41k
    {
1005
2.41k
        const size_t arrayLength = m_rawArray.size();
1006
2.41k
        writeArrayLength(out, arrayLength);
1007
1008
8.33k
        for (size_t index = 0; index < arrayLength; 
++index5.91k
)
1009
5.91k
        {
1010
5.91k
            alignAndCheckOffset(out, owner, index);
1011
5.91k
            detail::arrayTraitsWrite<ArrayTraits>(owner, out, m_rawArray[index]);
1012
5.91k
        }
1013
2.41k
    }
1014
1015
    using PackingContext = typename detail::packing_context_type<typename RawArray::value_type>::type;
1016
1017
    size_t bitSizeOfPackedImpl(const OwnerType& owner, size_t bitPosition) const
1018
896
    {
1019
896
        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
832
        {
1028
832
            PackingContext context;
1029
1030
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1031
3.80k
            {
1032
3.80k
                detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1033
3.80k
                        owner, context, m_rawArray[index]);
1034
3.80k
            }
1035
1036
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1037
3.80k
            {
1038
3.80k
                alignBitPosition(endBitPosition);
1039
3.80k
                endBitPosition += detail::packedArrayTraitsBitSizeOf<PackedArrayTraits<ArrayTraits>>(
1040
3.80k
                        owner, context, endBitPosition, m_rawArray[index]);
1041
3.80k
            }
1042
832
        }
1043
1044
896
        return endBitPosition - bitPosition;
1045
896
    }
1046
1047
    size_t initializeOffsetsPackedImpl(OwnerType& owner, size_t bitPosition)
1048
896
    {
1049
896
        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
832
        {
1058
832
            PackingContext context;
1059
1060
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1061
3.80k
            {
1062
3.80k
                detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1063
3.80k
                        owner, context, m_rawArray[index]);
1064
3.80k
            }
1065
1066
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1067
3.80k
            {
1068
3.80k
                initializeOffset(owner, index, endBitPosition);
1069
3.80k
                endBitPosition = detail::packedArrayTraitsInitializeOffsets<PackedArrayTraits<ArrayTraits>>(
1070
3.80k
                        owner, context, endBitPosition, m_rawArray[index]);
1071
3.80k
            }
1072
832
        }
1073
1074
896
        return endBitPosition;
1075
896
    }
1076
1077
    void readPackedImpl(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
1078
896
    {
1079
896
        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
832
        {
1087
832
            m_rawArray.reserve(readLength);
1088
1089
832
            PackingContext context;
1090
1091
4.64k
            for (size_t index = 0; index < readLength; 
++index3.80k
)
1092
3.80k
            {
1093
3.80k
                alignAndCheckOffset(in, owner, index);
1094
3.80k
                detail::packedArrayTraitsRead<PackedArrayTraits<ArrayTraits>>(
1095
3.80k
                        owner, m_rawArray, context, in, index);
1096
3.80k
            }
1097
832
        }
1098
896
    }
1099
1100
    void writePackedImpl(const OwnerType& owner, BitStreamWriter& out) const
1101
896
    {
1102
896
        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
832
        {
1109
832
            PackingContext context;
1110
1111
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1112
3.80k
            {
1113
3.80k
                detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1114
3.80k
                        owner, context, m_rawArray[index]);
1115
3.80k
            }
1116
1117
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1118
3.80k
            {
1119
3.80k
                alignAndCheckOffset(out, owner, index);
1120
3.80k
                detail::packedArrayTraitsWrite<PackedArrayTraits<ArrayTraits>>(
1121
3.80k
                        owner, context, out, m_rawArray[index]);
1122
3.80k
            }
1123
832
        }
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
ARRAY createOptionalArray(RAW_ARRAY&& rawArray)
1135
1
{
1136
1
    return ARRAY(std::forward<RAW_ARRAY>(rawArray));
1137
1
}
1138
1139
/**
1140
 * Overload for NullOpt.
1141
 */
1142
template <typename ARRAY>
1143
NullOptType createOptionalArray(NullOptType)
1144
14
{
1145
14
    return NullOpt;
1146
14
}
1147
1148
} // namespace zserio
1149
1150
#endif // ZSERIO_ARRAY_H_INC