Coverage Report

Created: 2024-04-30 09:35

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/SizeConvertUtil.h"
14
#include "zserio/Traits.h"
15
#include "zserio/UniquePtr.h"
16
17
namespace zserio
18
{
19
20
namespace detail
21
{
22
23
// array expressions for arrays which do not need expressions
24
struct DummyArrayExpressions
25
{};
26
27
// array owner for arrays which do not need the owner
28
struct DummyArrayOwner
29
{};
30
31
// helper trait to choose the owner type for an array from combination of ARRAY_TRAITS and ARRAY_EXPRESSIONS
32
template <typename ARRAY_TRAITS, typename ARRAY_EXPRESSIONS, typename = void>
33
struct array_owner_type
34
{
35
    using type = DummyArrayOwner;
36
};
37
38
template <typename ARRAY_TRAITS, typename ARRAY_EXPRESSIONS>
39
struct array_owner_type<ARRAY_TRAITS, ARRAY_EXPRESSIONS,
40
        typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value>::type>
41
{
42
    using type = typename ARRAY_TRAITS::OwnerType;
43
};
44
45
template <typename ARRAY_TRAITS, typename ARRAY_EXPRESSIONS>
46
struct array_owner_type<ARRAY_TRAITS, ARRAY_EXPRESSIONS,
47
        typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
48
                has_owner_type<ARRAY_EXPRESSIONS>::value>::type>
49
{
50
    using type = typename ARRAY_EXPRESSIONS::OwnerType;
51
};
52
53
// helper trait to choose packing context type for an array from an element type T
54
template <typename T, typename = void>
55
struct packing_context_type
56
{
57
    using type = DeltaContext;
58
};
59
60
template <typename T>
61
struct packing_context_type<T, typename std::enable_if<has_zserio_packing_context<T>::value>::type>
62
{
63
    using type = typename T::ZserioPackingContext;
64
};
65
66
// calls the initializeOffset static method on ARRAY_EXPRESSIONS if available
67
template <typename ARRAY_EXPRESSIONS, typename OWNER_TYPE,
68
        typename std::enable_if<has_initialize_offset<ARRAY_EXPRESSIONS>::value, int>::type = 0>
69
void initializeOffset(OWNER_TYPE& owner, size_t index, size_t bitPosition)
70
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(
96
        const OWNER_TYPE& owner, PACKING_CONTEXT& context, 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(
104
        const OWNER_TYPE&, PACKING_CONTEXT& context, 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<ARRAY_TRAITS::IS_BITSIZEOF_CONSTANT && has_owner_type<ARRAY_TRAITS>::value,
112
                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<ARRAY_TRAITS::IS_BITSIZEOF_CONSTANT && !has_owner_type<ARRAY_TRAITS>::value,
120
                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(
130
        const OWNER_TYPE& owner, size_t bitPosition, 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(
138
        const OWNER_TYPE&, size_t bitPosition, 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, size_t bitPosition,
147
        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(
164
        OWNER_TYPE& owner, size_t bitPosition, 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,
172
                int>::type = 0>
173
size_t arrayTraitsInitializeOffsets(
174
        OWNER_TYPE&, size_t bitPosition, const typename ARRAY_TRAITS::ElementType& element)
175
352
{
176
352
    return ARRAY_TRAITS::initializeOffsets(bitPosition, element);
177
352
}
178
179
template <typename ARRAY_TRAITS, typename OWNER_TYPE,
180
        typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value &&
181
                        std::is_scalar<typename ARRAY_TRAITS::ElementType>::value,
182
                int>::type = 0>
183
size_t arrayTraitsInitializeOffsets(OWNER_TYPE&, size_t bitPosition, typename ARRAY_TRAITS::ElementType element)
184
4.74k
{
185
4.74k
    return ARRAY_TRAITS::initializeOffsets(bitPosition, element);
186
4.74k
}
187
188
// calls the initializeOffsets method properly on packed array traits
189
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
190
        typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
191
size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE& owner, PACKING_CONTEXT& context, size_t bitPosition,
192
        typename PACKED_ARRAY_TRAITS::ElementType& element)
193
384
{
194
384
    return PACKED_ARRAY_TRAITS::initializeOffsets(owner, context, bitPosition, element);
195
384
}
196
197
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
198
        typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
199
                        !std::is_scalar<typename PACKED_ARRAY_TRAITS::ElementType>::value,
200
                int>::type = 0>
201
size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE&, PACKING_CONTEXT& context, size_t bitPosition,
202
        const typename PACKED_ARRAY_TRAITS::ElementType& element)
203
96
{
204
96
    return PACKED_ARRAY_TRAITS::initializeOffsets(context, bitPosition, element);
205
96
}
206
207
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
208
        typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
209
                        std::is_scalar<typename PACKED_ARRAY_TRAITS::ElementType>::value,
210
                int>::type = 0>
211
size_t packedArrayTraitsInitializeOffsets(OWNER_TYPE&, PACKING_CONTEXT& context, size_t bitPosition,
212
        typename PACKED_ARRAY_TRAITS::ElementType element)
213
3.32k
{
214
3.32k
    return PACKED_ARRAY_TRAITS::initializeOffsets(context, bitPosition, element);
215
3.32k
}
216
217
// calls the read method properly on array traits
218
template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
219
        typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value && !has_allocator<ARRAY_TRAITS>::value,
220
                int>::type = 0>
221
void arrayTraitsRead(const OWNER_TYPE& owner, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
222
624
{
223
624
    rawArray.push_back(ARRAY_TRAITS::read(owner, in, index));
224
624
}
225
226
template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
227
        typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value && has_allocator<ARRAY_TRAITS>::value,
228
                int>::type = 0>
229
void arrayTraitsRead(OWNER_TYPE& owner, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
230
192
{
231
192
    ARRAY_TRAITS::read(owner, rawArray, in, index);
232
192
}
233
234
template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
235
        typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value && !has_allocator<ARRAY_TRAITS>::value,
236
                int>::type = 0>
237
void arrayTraitsRead(const OWNER_TYPE&, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
238
4.84k
{
239
4.84k
    rawArray.push_back(ARRAY_TRAITS::read(in, index));
240
4.84k
}
241
242
template <typename ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY,
243
        typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value && has_allocator<ARRAY_TRAITS>::value,
244
                int>::type = 0>
245
void arrayTraitsRead(const OWNER_TYPE&, RAW_ARRAY& rawArray, BitStreamReader& in, size_t index)
246
256
{
247
256
    ARRAY_TRAITS::read(rawArray, in, index);
248
256
}
249
250
// calls the read method properly on packed array traits
251
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY, typename PACKING_CONTEXT,
252
        typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value &&
253
                        has_allocator<PACKED_ARRAY_TRAITS>::value,
254
                int>::type = 0>
255
void packedArrayTraitsRead(
256
        OWNER_TYPE& owner, RAW_ARRAY& rawArray, PACKING_CONTEXT& context, BitStreamReader& in, size_t index)
257
192
{
258
192
    PACKED_ARRAY_TRAITS::read(owner, rawArray, context, in, index);
259
192
}
260
261
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY, typename PACKING_CONTEXT,
262
        typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value &&
263
                        !has_allocator<PACKED_ARRAY_TRAITS>::value,
264
                int>::type = 0>
265
void packedArrayTraitsRead(const OWNER_TYPE& owner, RAW_ARRAY& rawArray, PACKING_CONTEXT& context,
266
        BitStreamReader& in, size_t index)
267
192
{
268
192
    rawArray.push_back(PACKED_ARRAY_TRAITS::read(owner, context, in, index));
269
192
}
270
271
// note: types which doesn't have owner and have allocator are never packed (e.g. string, bytes ...)
272
//       and thus such specialization is not needed
273
274
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename RAW_ARRAY, typename PACKING_CONTEXT,
275
        typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value &&
276
                        !has_allocator<PACKED_ARRAY_TRAITS>::value,
277
                int>::type = 0>
278
void packedArrayTraitsRead(
279
        const OWNER_TYPE&, RAW_ARRAY& rawArray, PACKING_CONTEXT& context, BitStreamReader& in, size_t index)
280
3.42k
{
281
3.42k
    rawArray.push_back(PACKED_ARRAY_TRAITS::read(context, in, index));
282
3.42k
}
283
284
// call the write method properly on array traits
285
template <typename ARRAY_TRAITS, typename OWNER_TYPE,
286
        typename std::enable_if<has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
287
void arrayTraitsWrite(
288
        const OWNER_TYPE& owner, BitStreamWriter& out, const typename ARRAY_TRAITS::ElementType& element)
289
816
{
290
816
    ARRAY_TRAITS::write(owner, out, element);
291
816
}
292
293
template <typename ARRAY_TRAITS, typename OWNER_TYPE,
294
        typename std::enable_if<!has_owner_type<ARRAY_TRAITS>::value, int>::type = 0>
295
void arrayTraitsWrite(
296
        const OWNER_TYPE&, BitStreamWriter& out, const typename ARRAY_TRAITS::ElementType& element)
297
5.09k
{
298
5.09k
    ARRAY_TRAITS::write(out, element);
299
5.09k
}
300
301
// call the write method properly on packed array traits
302
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
303
        typename std::enable_if<has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
304
void packedArrayTraitsWrite(const OWNER_TYPE& owner, PACKING_CONTEXT& context, BitStreamWriter& out,
305
        const typename PACKED_ARRAY_TRAITS::ElementType& element)
306
384
{
307
384
    PACKED_ARRAY_TRAITS::write(owner, context, out, element);
308
384
}
309
310
template <typename PACKED_ARRAY_TRAITS, typename OWNER_TYPE, typename PACKING_CONTEXT,
311
        typename std::enable_if<!has_owner_type<PACKED_ARRAY_TRAITS>::value, int>::type = 0>
312
void packedArrayTraitsWrite(const OWNER_TYPE&, PACKING_CONTEXT& context, BitStreamWriter& out,
313
        const typename PACKED_ARRAY_TRAITS::ElementType& element)
314
3.42k
{
315
3.42k
    PACKED_ARRAY_TRAITS::write(context, out, element);
316
3.42k
}
317
318
} // namespace detail
319
320
/**
321
 * Array type enum which defined type of the underlying array.
322
 */
323
enum ArrayType
324
{
325
    NORMAL, /**< Normal zserio array which has size defined by the Zserio schema. */
326
    IMPLICIT, /**< Implicit zserio array which size is defined by number of remaining bits in the bit stream. */
327
    ALIGNED, /**< Aligned zserio array which is normal zserio array with indexed offsets. */
328
    AUTO, /**< Auto zserio array which has size stored in a hidden field before the array. */
329
    ALIGNED_AUTO /**< Aligned auto zserio array which is auto zserio array with indexed offsets. */
330
};
331
332
/**
333
 * Array wrapper for zserio arrays which are not explicitly packed but the element type is packable
334
 * and thus it can be packed if requested from a parent.
335
 */
336
/**
337
 * Array wrapper for zserio arrays which are never packed.
338
 */
339
template <typename RAW_ARRAY, typename ARRAY_TRAITS, ArrayType ARRAY_TYPE,
340
        typename ARRAY_EXPRESSIONS = detail::DummyArrayExpressions>
341
class Array
342
{
343
public:
344
    /** Typedef for raw array type. */
345
    using RawArray = RAW_ARRAY;
346
347
    /** Typedef for array traits. */
348
    using ArrayTraits = ARRAY_TRAITS;
349
350
    /** Typedef for array expressions. */
351
    using ArrayExpressions = ARRAY_EXPRESSIONS;
352
353
    /**
354
     * Typedef for the array's owner type.
355
     *
356
     * Owner type is needed for proper expressions evaluation. If neither traits nor array need the owner
357
     * for expressions evaluation, detail::DummyArrayOwner is used and such array do not need the owner at all.
358
     */
359
    using OwnerType = typename detail::array_owner_type<ArrayTraits, ArrayExpressions>::type;
360
361
    /** Typedef for allocator type. */
362
    using allocator_type = typename RawArray::allocator_type;
363
364
    /**
365
     * Empty constructor.
366
     *
367
     * \param allocator Allocator to use for the raw array.
368
     */
369
    explicit Array(const allocator_type& allocator = allocator_type()) :
370
            m_rawArray(allocator)
371
10.2k
    {}
372
373
    /**
374
     * Constructor from l-value raw array.
375
     *
376
     * \param rawArray Raw array.
377
     */
378
    explicit Array(const RawArray& rawArray) :
379
            m_rawArray(rawArray)
380
3.31k
    {}
381
382
    /**
383
     * Constructor from r-value raw array.
384
     *
385
     * \param rawArray Raw array.
386
     */
387
    explicit Array(RawArray&& rawArray) :
388
            m_rawArray(std::move(rawArray))
389
44
    {}
390
391
    /**
392
     * Method generated by default.
393
     *
394
     * \{
395
     */
396
23.6k
    ~Array() = default;
397
3.31k
    Array(const Array& other) = default;
398
3.31k
    Array& operator=(const Array& other) = default;
399
3.39k
    Array(Array&& other) = default;
400
3.39k
    Array& operator=(Array&& other) = default;
401
    /**
402
     * \}
403
     */
404
405
    /**
406
     * Copy constructor which prevents initialization of parameterized elements.
407
     *
408
     * Note that elements will be initialized later by a parent compound.
409
     *
410
     * \param other Instance to construct from.
411
     */
412
    template <typename T = typename RAW_ARRAY::value_type,
413
            typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
414
    Array(NoInitT, const Array& other) :
415
            Array(std::allocator_traits<allocator_type>::select_on_container_copy_construction(
416
                    other.m_rawArray.get_allocator()))
417
64
    {
418
64
        m_rawArray.reserve(other.m_rawArray.size());
419
64
        for (const auto& value : other.m_rawArray)
420
192
            m_rawArray.emplace_back(NoInit, value);
421
64
    }
422
423
    /**
424
     * Assignment which prevents initialization of parameterized elements.
425
     *
426
     * Note that elements will be initialized later by a parent compound.
427
     *
428
     * \param other Instance to move-assign from.
429
     */
430
    template <typename T = typename RAW_ARRAY::value_type,
431
            typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
432
    Array& assign(NoInitT, const Array& other)
433
64
    {
434
64
        const RawArray rawArray(other.m_rawArray.get_allocator());
435
64
        m_rawArray = rawArray; // copy assign to get correct allocator propagation behaviour
436
64
        m_rawArray.reserve(other.m_rawArray.size());
437
64
        for (const auto& value : other.m_rawArray)
438
192
            m_rawArray.emplace_back(NoInit, value);
439
440
64
        return *this;
441
64
    }
442
443
    /**
444
     * Move constructors which prevents initialization of parameterized elements.
445
     *
446
     * Provided for convenience since vector move constructor doesn't call move constructors of its elements.
447
     *
448
     * \param other Instance to move-construct from.
449
     */
450
    template <typename T = typename RAW_ARRAY::value_type,
451
            typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
452
    Array(NoInitT, Array&& other) :
453
            Array(std::move(other))
454
64
    {}
455
456
    /**
457
     * Assignment which prevents initialization of parameterized elements.
458
     *
459
     * Provided for convenience since vector move assignment operator doesn't call move assignment operators
460
     * of its elements.
461
     *
462
     * \param other Instance to move-assign from.
463
     */
464
    template <typename T = typename RAW_ARRAY::value_type,
465
            typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
466
    Array& assign(NoInitT, Array&& other)
467
64
    {
468
64
        return operator=(std::move(other));
469
64
    }
470
471
    /**
472
     * Copy constructor which forces allocator propagating while copying the raw array.
473
     *
474
     * \param other Source array to copy.
475
     * \param allocator Allocator to propagate during copying.
476
     */
477
    Array(PropagateAllocatorT, const Array& other, const allocator_type& allocator) :
478
            m_rawArray(allocatorPropagatingCopy(other.m_rawArray, allocator))
479
3.31k
    {}
480
481
    /**
482
     * Copy constructor which prevents initialization and forces allocator propagating while copying
483
     * the raw array.
484
     *
485
     * \param other Source array to copy.
486
     * \param allocator Allocator to propagate during copying.
487
     */
488
    template <typename T = typename RAW_ARRAY::value_type,
489
            typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
490
    Array(PropagateAllocatorT, NoInitT, const Array& other, const allocator_type& allocator) :
491
            m_rawArray(allocatorPropagatingCopy(NoInit, other.m_rawArray, allocator))
492
64
    {}
493
494
    /**
495
     * Operator equality.
496
     *
497
     * \param other Array to compare.
498
     *
499
     * \return True when the underlying raw arrays have same contents, false otherwise.
500
     */
501
    bool operator==(const Array& other) const
502
19.8k
    {
503
19.8k
        return m_rawArray == other.m_rawArray;
504
19.8k
    }
505
506
    /**
507
     * Operator less than.
508
     *
509
     * \param other Array to compare.
510
     *
511
     * \return True when the underlying raw array is less than the other underlying raw array.
512
     */
513
    bool operator<(const Array& other) const
514
6.62k
    {
515
6.62k
        return m_rawArray < other.m_rawArray;
516
6.62k
    }
517
518
    /**
519
     * Hash code.
520
     *
521
     * \return Hash code calculated on the underlying raw array.
522
     */
523
    uint32_t hashCode() const
524
1
    {
525
1
        return calcHashCode(HASH_SEED, m_rawArray);
526
1
    }
527
528
    /**
529
     * Gets raw array.
530
     *
531
     * \return Constant reference to the raw array.
532
     */
533
    const RawArray& getRawArray() const
534
20.3k
    {
535
20.3k
        return m_rawArray;
536
20.3k
    }
537
538
    /**
539
     * Gets raw array.
540
     *
541
     * \return Reference to the raw array.
542
     */
543
    RawArray& getRawArray()
544
13.9k
    {
545
13.9k
        return m_rawArray;
546
13.9k
    }
547
548
    /**
549
     * Initializes array elements.
550
     *
551
     * \param owner Array owner.
552
     */
553
    template <typename ARRAY_EXPRESSIONS_ = ArrayExpressions,
554
            typename std::enable_if<has_initialize_element<ARRAY_EXPRESSIONS_>::value, int>::type = 0>
555
    void initializeElements(OwnerType& owner)
556
70
    {
557
70
        size_t index = 0;
558
70
        for (auto&& element : m_rawArray)
559
195
        {
560
195
            ArrayExpressions::initializeElement(owner, element, index);
561
195
            index++;
562
195
        }
563
70
    }
564
565
    /**
566
     * Calculates bit size of this array.
567
     *
568
     * Available for arrays which do not need the owner.
569
     *
570
     * \param bitPosition Current bit position.
571
     *
572
     * \return Bit size of the array.
573
     */
574
    template <typename OWNER_TYPE_ = OwnerType,
575
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
576
    size_t bitSizeOf(size_t bitPosition) const
577
2.11k
    {
578
2.11k
        return bitSizeOfImpl(detail::DummyArrayOwner(), bitPosition);
579
2.11k
    }
580
581
    /**
582
     * Calculates bit size of this array.
583
     *
584
     * Available for arrays which need the owner.
585
     *
586
     * \param owner Array owner.
587
     * \param bitPosition Current bit position.
588
     *
589
     * \return Bit size of the array.
590
     */
591
    template <typename OWNER_TYPE_ = OwnerType,
592
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
593
    size_t bitSizeOf(const OwnerType& owner, size_t bitPosition) const
594
304
    {
595
304
        return bitSizeOfImpl(owner, bitPosition);
596
304
    }
597
598
    /**
599
     * Initializes indexed offsets.
600
     *
601
     * Available for arrays which do not need the owner.
602
     *
603
     * \param bitPosition Current bit position.
604
     *
605
     * \return Updated bit position which points to the first bit after the array.
606
     */
607
    template <typename OWNER_TYPE_ = OwnerType,
608
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
609
    size_t initializeOffsets(size_t bitPosition)
610
2.11k
    {
611
2.11k
        detail::DummyArrayOwner owner;
612
2.11k
        return initializeOffsetsImpl(owner, bitPosition);
613
2.11k
    }
614
615
    /**
616
     * Initializes indexed offsets.
617
     *
618
     * Available for arrays which need the owner.
619
     *
620
     * \param owner Array owner.
621
     * \param bitPosition Current bit position.
622
     *
623
     * \return Updated bit position which points to the first bit after the array.
624
     */
625
    template <typename OWNER_TYPE_ = OwnerType,
626
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
627
    size_t initializeOffsets(OwnerType& owner, size_t bitPosition)
628
304
    {
629
304
        return initializeOffsetsImpl(owner, bitPosition);
630
304
    }
631
632
    /**
633
     * Reads the array from the bit stream.
634
     *
635
     * Available for arrays which do not need the owner.
636
     *
637
     * \param in Bit stream reader to use for reading.
638
     * \param arrayLength Array length. Not needed for auto / implicit arrays.
639
     */
640
    template <typename OWNER_TYPE_ = OwnerType,
641
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
642
    void read(BitStreamReader& in, size_t arrayLength = 0)
643
2.11k
    {
644
2.11k
        detail::DummyArrayOwner owner;
645
2.11k
        readImpl(owner, in, arrayLength);
646
2.11k
    }
647
648
    /**
649
     * Reads the array from the bit stream.
650
     *
651
     * Available for arrays which need the owner.
652
     *
653
     * \param owner Array owner.
654
     * \param in Bit stream reader to use for reading.
655
     * \param arrayLength Array length. Not needed for auto / implicit arrays.
656
     */
657
    template <typename OWNER_TYPE_ = OwnerType,
658
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
659
    void read(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
660
304
    {
661
304
        readImpl(owner, in, arrayLength);
662
304
    }
663
664
    /**
665
     * Writes the array to the bit stream.
666
     *
667
     * Available for arrays which do not need the owner.
668
     *
669
     * \param out Bit stream write to use for writing.
670
     */
671
    template <typename OWNER_TYPE_ = OwnerType,
672
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
673
    void write(BitStreamWriter& out) const
674
2.11k
    {
675
2.11k
        writeImpl(detail::DummyArrayOwner(), out);
676
2.11k
    }
677
678
    /**
679
     * Writes the array to the bit stream.
680
     *
681
     * Available for arrays which need the owner.
682
     *
683
     * \param owner Array owner.
684
     * \param out Bit stream write to use for writing.
685
     */
686
    template <typename OWNER_TYPE_ = OwnerType,
687
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
688
    void write(const OwnerType& owner, BitStreamWriter& out) const
689
304
    {
690
304
        writeImpl(owner, out);
691
304
    }
692
693
    /**
694
     * Returns length of the packed array stored in the bit stream in bits.
695
     *
696
     * Available for arrays which do not need the owner.
697
     *
698
     * \param bitPosition Current bit stream position.
699
     *
700
     * \return Length of the array stored in the bit stream in bits.
701
     */
702
    template <typename OWNER_TYPE_ = OwnerType,
703
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
704
    size_t bitSizeOfPacked(size_t bitPosition) const
705
800
    {
706
800
        return bitSizeOfPackedImpl(detail::DummyArrayOwner(), bitPosition);
707
800
    }
708
709
    /**
710
     * Returns length of the packed array stored in the bit stream in bits.
711
     *
712
     * Available for arrays which need the owner.
713
     *
714
     * \param owner Array owner.
715
     * \param bitPosition Current bit stream position.
716
     *
717
     * \return Length of the array stored in the bit stream in bits.
718
     */
719
    template <typename OWNER_TYPE_ = OwnerType,
720
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
721
    size_t bitSizeOfPacked(const OwnerType& ownerType, size_t bitPosition) const
722
96
    {
723
96
        return bitSizeOfPackedImpl(ownerType, bitPosition);
724
96
    }
725
726
    /**
727
     * Initializes indexed offsets for the packed array.
728
     *
729
     * Available for arrays which do not need the owner.
730
     *
731
     * \param bitPosition Current bit stream position.
732
     *
733
     * \return Updated bit stream position which points to the first bit after the array.
734
     */
735
    template <typename OWNER_TYPE_ = OwnerType,
736
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
737
    size_t initializeOffsetsPacked(size_t bitPosition)
738
800
    {
739
800
        detail::DummyArrayOwner owner;
740
800
        return initializeOffsetsPackedImpl(owner, bitPosition);
741
800
    }
742
743
    /**
744
     * Initializes indexed offsets for the packed array.
745
     *
746
     * Available for arrays which need the owner.
747
     *
748
     * \param owner Array owner.
749
     * \param bitPosition Current bit stream position.
750
     *
751
     * \return Updated bit stream position which points to the first bit after the array.
752
     */
753
    template <typename OWNER_TYPE_ = OwnerType,
754
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
755
    size_t initializeOffsetsPacked(OwnerType& owner, size_t bitPosition)
756
96
    {
757
96
        return initializeOffsetsPackedImpl(owner, bitPosition);
758
96
    }
759
760
    /**
761
     * Reads packed array from the bit stream.
762
     *
763
     * Available for arrays which do not need the owner.
764
     *
765
     * \param in Bit stream from which to read.
766
     * \param arrayLength Number of elements to read or 0 in case of auto arrays.
767
     */
768
    template <typename OWNER_TYPE_ = OwnerType,
769
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
770
    void readPacked(BitStreamReader& in, size_t arrayLength = 0)
771
800
    {
772
800
        detail::DummyArrayOwner owner;
773
800
        readPackedImpl(owner, in, arrayLength);
774
800
    }
775
776
    /**
777
     * Reads packed array from the bit stream.
778
     *
779
     * Available for arrays which need the owner.
780
     *
781
     * \param owner Array owner.
782
     * \param in Bit stream from which to read.
783
     * \param arrayLength Number of elements to read or 0 in case of auto arrays.
784
     */
785
    template <typename OWNER_TYPE_ = OwnerType,
786
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
787
    void readPacked(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
788
96
    {
789
96
        readPackedImpl(owner, in, arrayLength);
790
96
    }
791
792
    /**
793
     * Writes packed array to the bit stream.
794
     *
795
     * Available for arrays which do not need the owner.
796
     *
797
     * \param out Bit stream where to write.
798
     */
799
    template <typename OWNER_TYPE_ = OwnerType,
800
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
801
    void writePacked(BitStreamWriter& out) const
802
800
    {
803
800
        writePackedImpl(detail::DummyArrayOwner(), out);
804
800
    }
805
806
    /**
807
     * Writes packed array to the bit stream.
808
     *
809
     * Available for arrays which need the owner.
810
     *
811
     * \param owner Array owner.
812
     * \param out Bit stream where to write.
813
     */
814
    template <typename OWNER_TYPE_ = OwnerType,
815
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
816
    void writePacked(const OwnerType& owner, BitStreamWriter& out) const
817
96
    {
818
96
        writePackedImpl(owner, out);
819
96
    }
820
821
private:
822
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
823
            typename std::enable_if<ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
824
                    int>::type = 0>
825
    static void addBitSizeOfArrayLength(size_t&, size_t)
826
3.45k
    {}
827
828
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
829
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
830
                    int>::type = 0>
831
    static void addBitSizeOfArrayLength(size_t& bitPosition, size_t arrayLength)
832
3.16k
    {
833
3.16k
        bitPosition += bitSizeOfVarSize(convertSizeToUInt32(arrayLength));
834
3.16k
    }
835
836
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
837
            typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
838
                    int>::type = 0>
839
    static void alignBitPosition(size_t&)
840
3.28k
    {}
841
842
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
843
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
844
                    int>::type = 0>
845
    static void alignBitPosition(size_t& bitPosition)
846
3.28k
    {
847
3.28k
        bitPosition = alignTo(8, bitPosition);
848
3.28k
    }
849
850
    template <typename IO, typename OWNER_TYPE, ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
851
            typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
852
                    int>::type = 0>
853
    static void alignAndCheckOffset(IO&, OWNER_TYPE&, size_t)
854
10.0k
    {}
855
856
    template <typename IO, typename OWNER_TYPE, ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
857
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
858
                    int>::type = 0>
859
    static void alignAndCheckOffset(IO& io, OWNER_TYPE& owner, size_t index)
860
9.40k
    {
861
9.40k
        io.alignTo(8);
862
9.40k
        detail::checkOffset<ArrayExpressions>(owner, index, io.getBitPosition() / 8);
863
9.40k
    }
864
865
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
866
            typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
867
                    int>::type = 0>
868
    static void initializeOffset(OwnerType&, size_t, size_t&)
869
5.01k
    {}
870
871
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
872
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
873
                    int>::type = 0>
874
    static void initializeOffset(OwnerType& owner, size_t index, size_t& bitPosition)
875
4.70k
    {
876
4.70k
        bitPosition = alignTo(8, bitPosition);
877
4.70k
        detail::initializeOffset<ArrayExpressions>(owner, index, bitPosition / 8);
878
4.70k
    }
879
880
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
881
            typename std::enable_if<ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO &&
882
                            ARRAY_TYPE_ != ArrayType::IMPLICIT,
883
                    int>::type = 0>
884
    static size_t readArrayLength(OwnerType&, BitStreamReader&, size_t arrayLength)
885
1.58k
    {
886
1.58k
        return arrayLength;
887
1.58k
    }
888
889
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
890
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
891
                    int>::type = 0>
892
    static size_t readArrayLength(OwnerType&, BitStreamReader& in, size_t)
893
1.58k
    {
894
1.58k
        return in.readVarSize();
895
1.58k
    }
896
897
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
898
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::IMPLICIT, int>::type = 0>
899
    static size_t readArrayLength(OwnerType& owner, BitStreamReader& in, size_t)
900
144
    {
901
144
        static_assert(ARRAY_TYPE != ArrayType::IMPLICIT || ArrayTraits::IS_BITSIZEOF_CONSTANT,
902
144
                "Implicit array elements must have constant bit size!");
903
904
144
        const size_t remainingBits = in.getBufferBitSize() - in.getBitPosition();
905
144
        return remainingBits / detail::arrayTraitsConstBitSizeOf<ArrayTraits>(owner);
906
144
    }
907
908
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
909
            typename std::enable_if<ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
910
                    int>::type = 0>
911
    static void writeArrayLength(BitStreamWriter&, size_t)
912
1.72k
    {}
913
914
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
915
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
916
                    int>::type = 0>
917
    static void writeArrayLength(BitStreamWriter& out, size_t arrayLength)
918
1.58k
    {
919
1.58k
        out.writeVarSize(convertSizeToUInt32(arrayLength));
920
1.58k
    }
921
922
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
923
            typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
924
                    int>::type = 0>
925
    static size_t constBitSizeOfElements(size_t, size_t arrayLength, size_t elementBitSize)
926
584
    {
927
584
        return arrayLength * elementBitSize;
928
584
    }
929
930
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
931
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
932
                    int>::type = 0>
933
    static size_t constBitSizeOfElements(size_t bitPosition, size_t arrayLength, size_t elementBitSize)
934
480
    {
935
480
        size_t endBitPosition = alignTo(8, bitPosition);
936
480
        endBitPosition += elementBitSize + (arrayLength - 1) * alignTo(8, elementBitSize);
937
938
480
        return endBitPosition - bitPosition;
939
480
    }
940
941
    template <typename ARRAY_TRAITS_ = ArrayTraits,
942
            typename std::enable_if<ARRAY_TRAITS_::IS_BITSIZEOF_CONSTANT, int>::type = 0>
943
    size_t bitSizeOfImpl(const OwnerType& owner, size_t bitPosition) const
944
1.42k
    {
945
1.42k
        size_t endBitPosition = bitPosition;
946
947
1.42k
        const size_t arrayLength = m_rawArray.size();
948
1.42k
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
949
950
1.42k
        if (arrayLength > 0)
951
1.06k
        {
952
1.06k
            const size_t elementBitSize = detail::arrayTraitsConstBitSizeOf<ArrayTraits>(owner);
953
1.06k
            endBitPosition += constBitSizeOfElements(endBitPosition, arrayLength, elementBitSize);
954
1.06k
        }
955
956
1.42k
        return endBitPosition - bitPosition;
957
1.42k
    }
958
959
    template <typename ARRAY_TRAITS_ = ArrayTraits,
960
            typename std::enable_if<!ARRAY_TRAITS_::IS_BITSIZEOF_CONSTANT, int>::type = 0>
961
    size_t bitSizeOfImpl(const OwnerType& owner, size_t bitPosition) const
962
993
    {
963
993
        size_t endBitPosition = bitPosition;
964
965
993
        const size_t arrayLength = m_rawArray.size();
966
993
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
967
968
3.74k
        for (size_t index = 0; index < arrayLength; 
++index2.75k
)
969
2.75k
        {
970
2.75k
            alignBitPosition(endBitPosition);
971
2.75k
            endBitPosition +=
972
2.75k
                    detail::arrayTraitsBitSizeOf<ArrayTraits>(owner, endBitPosition, m_rawArray[index]);
973
2.75k
        }
974
975
993
        return endBitPosition - bitPosition;
976
993
    }
977
978
    size_t initializeOffsetsImpl(OwnerType& owner, size_t bitPosition)
979
2.41k
    {
980
2.41k
        size_t endBitPosition = bitPosition;
981
982
2.41k
        const size_t arrayLength = m_rawArray.size();
983
2.41k
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
984
985
8.33k
        for (size_t index = 0; index < arrayLength; 
++index5.91k
)
986
5.91k
        {
987
5.91k
            initializeOffset(owner, index, endBitPosition);
988
5.91k
            endBitPosition =
989
5.91k
                    detail::arrayTraitsInitializeOffsets<ArrayTraits>(owner, endBitPosition, m_rawArray[index]);
990
5.91k
        }
991
992
2.41k
        return endBitPosition;
993
2.41k
    }
994
995
    void readImpl(OwnerType& owner, BitStreamReader& in, size_t arrayLength)
996
2.41k
    {
997
2.41k
        size_t readLength = readArrayLength(owner, in, arrayLength);
998
999
2.41k
        m_rawArray.clear();
1000
2.41k
        m_rawArray.reserve(readLength);
1001
8.33k
        for (size_t index = 0; index < readLength; 
++index5.91k
)
1002
5.91k
        {
1003
5.91k
            alignAndCheckOffset(in, owner, index);
1004
5.91k
            detail::arrayTraitsRead<ArrayTraits>(owner, m_rawArray, in, index);
1005
5.91k
        }
1006
2.41k
    }
1007
1008
    void writeImpl(const OwnerType& owner, BitStreamWriter& out) const
1009
2.41k
    {
1010
2.41k
        const size_t arrayLength = m_rawArray.size();
1011
2.41k
        writeArrayLength(out, arrayLength);
1012
1013
8.33k
        for (size_t index = 0; index < arrayLength; 
++index5.91k
)
1014
5.91k
        {
1015
5.91k
            alignAndCheckOffset(out, owner, index);
1016
5.91k
            detail::arrayTraitsWrite<ArrayTraits>(owner, out, m_rawArray[index]);
1017
5.91k
        }
1018
2.41k
    }
1019
1020
    using PackingContext = typename detail::packing_context_type<typename RawArray::value_type>::type;
1021
1022
    size_t bitSizeOfPackedImpl(const OwnerType& owner, size_t bitPosition) const
1023
896
    {
1024
896
        static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1025
1026
896
        size_t endBitPosition = bitPosition;
1027
1028
896
        const size_t arrayLength = m_rawArray.size();
1029
896
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
1030
1031
896
        if (arrayLength > 0)
1032
832
        {
1033
832
            PackingContext context;
1034
1035
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1036
3.80k
            {
1037
3.80k
                detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1038
3.80k
                        owner, context, m_rawArray[index]);
1039
3.80k
            }
1040
1041
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1042
3.80k
            {
1043
3.80k
                alignBitPosition(endBitPosition);
1044
3.80k
                endBitPosition += detail::packedArrayTraitsBitSizeOf<PackedArrayTraits<ArrayTraits>>(
1045
3.80k
                        owner, context, endBitPosition, m_rawArray[index]);
1046
3.80k
            }
1047
832
        }
1048
1049
896
        return endBitPosition - bitPosition;
1050
896
    }
1051
1052
    size_t initializeOffsetsPackedImpl(OwnerType& owner, size_t bitPosition)
1053
896
    {
1054
896
        static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1055
1056
896
        size_t endBitPosition = bitPosition;
1057
1058
896
        const size_t arrayLength = m_rawArray.size();
1059
896
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
1060
1061
896
        if (arrayLength > 0)
1062
832
        {
1063
832
            PackingContext context;
1064
1065
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1066
3.80k
            {
1067
3.80k
                detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1068
3.80k
                        owner, context, m_rawArray[index]);
1069
3.80k
            }
1070
1071
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1072
3.80k
            {
1073
3.80k
                initializeOffset(owner, index, endBitPosition);
1074
3.80k
                endBitPosition = detail::packedArrayTraitsInitializeOffsets<PackedArrayTraits<ArrayTraits>>(
1075
3.80k
                        owner, context, endBitPosition, m_rawArray[index]);
1076
3.80k
            }
1077
832
        }
1078
1079
896
        return endBitPosition;
1080
896
    }
1081
1082
    void readPackedImpl(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
1083
896
    {
1084
896
        static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1085
1086
896
        size_t readLength = readArrayLength(owner, in, arrayLength);
1087
1088
896
        m_rawArray.clear();
1089
1090
896
        if (readLength > 0)
1091
832
        {
1092
832
            m_rawArray.reserve(readLength);
1093
1094
832
            PackingContext context;
1095
1096
4.64k
            for (size_t index = 0; index < readLength; 
++index3.80k
)
1097
3.80k
            {
1098
3.80k
                alignAndCheckOffset(in, owner, index);
1099
3.80k
                detail::packedArrayTraitsRead<PackedArrayTraits<ArrayTraits>>(
1100
3.80k
                        owner, m_rawArray, context, in, index);
1101
3.80k
            }
1102
832
        }
1103
896
    }
1104
1105
    void writePackedImpl(const OwnerType& owner, BitStreamWriter& out) const
1106
896
    {
1107
896
        static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1108
1109
896
        const size_t arrayLength = m_rawArray.size();
1110
896
        writeArrayLength(out, arrayLength);
1111
1112
896
        if (arrayLength > 0)
1113
832
        {
1114
832
            PackingContext context;
1115
1116
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1117
3.80k
            {
1118
3.80k
                detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1119
3.80k
                        owner, context, m_rawArray[index]);
1120
3.80k
            }
1121
1122
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1123
3.80k
            {
1124
3.80k
                alignAndCheckOffset(out, owner, index);
1125
3.80k
                detail::packedArrayTraitsWrite<PackedArrayTraits<ArrayTraits>>(
1126
3.80k
                        owner, context, out, m_rawArray[index]);
1127
3.80k
            }
1128
832
        }
1129
896
    }
1130
1131
    RawArray m_rawArray;
1132
};
1133
1134
/**
1135
 * Helper for creating an optional array within templated field constructor, where the raw array can be
1136
 * actually the NullOpt.
1137
 */
1138
template <typename ARRAY, typename RAW_ARRAY>
1139
ARRAY createOptionalArray(RAW_ARRAY&& rawArray)
1140
1
{
1141
1
    return ARRAY(std::forward<RAW_ARRAY>(rawArray));
1142
1
}
1143
1144
/**
1145
 * Overload for NullOpt.
1146
 */
1147
template <typename ARRAY>
1148
NullOptType createOptionalArray(NullOptType)
1149
14
{
1150
14
    return NullOpt;
1151
14
}
1152
1153
} // namespace zserio
1154
1155
#endif // ZSERIO_ARRAY_H_INC