Coverage Report

Created: 2024-07-18 11:41

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
        {
421
192
            m_rawArray.emplace_back(NoInit, value);
422
192
        }
423
64
    }
424
425
    /**
426
     * Assignment which prevents initialization of parameterized elements.
427
     *
428
     * Note that elements will be initialized later by a parent compound.
429
     *
430
     * \param other Instance to move-assign from.
431
     */
432
    template <typename T = typename RAW_ARRAY::value_type,
433
            typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
434
    Array& assign(NoInitT, const Array& other)
435
64
    {
436
64
        const RawArray rawArray(other.m_rawArray.get_allocator());
437
64
        m_rawArray = rawArray; // copy assign to get correct allocator propagation behaviour
438
64
        m_rawArray.reserve(other.m_rawArray.size());
439
64
        for (const auto& value : other.m_rawArray)
440
192
        {
441
192
            m_rawArray.emplace_back(NoInit, value);
442
192
        }
443
444
64
        return *this;
445
64
    }
446
447
    /**
448
     * Move constructors which prevents initialization of parameterized elements.
449
     *
450
     * Provided for convenience since vector move constructor doesn't call move constructors of its elements.
451
     *
452
     * \param other Instance to move-construct from.
453
     */
454
    template <typename T = typename RAW_ARRAY::value_type,
455
            typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
456
    Array(NoInitT, Array&& other) :
457
            Array(std::move(other))
458
64
    {}
459
460
    /**
461
     * Assignment which prevents initialization of parameterized elements.
462
     *
463
     * Provided for convenience since vector move assignment operator doesn't call move assignment operators
464
     * of its elements.
465
     *
466
     * \param other Instance to move-assign from.
467
     */
468
    template <typename T = typename RAW_ARRAY::value_type,
469
            typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
470
    Array& assign(NoInitT, Array&& other)
471
64
    {
472
64
        return operator=(std::move(other));
473
64
    }
474
475
    /**
476
     * Copy constructor which forces allocator propagating while copying the raw array.
477
     *
478
     * \param other Source array to copy.
479
     * \param allocator Allocator to propagate during copying.
480
     */
481
    Array(PropagateAllocatorT, const Array& other, const allocator_type& allocator) :
482
            m_rawArray(allocatorPropagatingCopy(other.m_rawArray, allocator))
483
3.31k
    {}
484
485
    /**
486
     * Copy constructor which prevents initialization and forces allocator propagating while copying
487
     * the raw array.
488
     *
489
     * \param other Source array to copy.
490
     * \param allocator Allocator to propagate during copying.
491
     */
492
    template <typename T = typename RAW_ARRAY::value_type,
493
            typename std::enable_if<std::is_constructible<T, NoInitT, T>::value, int>::type = 0>
494
    Array(PropagateAllocatorT, NoInitT, const Array& other, const allocator_type& allocator) :
495
            m_rawArray(allocatorPropagatingCopy(NoInit, other.m_rawArray, allocator))
496
64
    {}
497
498
    /**
499
     * Operator equality.
500
     *
501
     * \param other Array to compare.
502
     *
503
     * \return True when the underlying raw arrays have same contents, false otherwise.
504
     */
505
    bool operator==(const Array& other) const
506
19.8k
    {
507
19.8k
        return m_rawArray == other.m_rawArray;
508
19.8k
    }
509
510
    /**
511
     * Operator less than.
512
     *
513
     * \param other Array to compare.
514
     *
515
     * \return True when the underlying raw array is less than the other underlying raw array.
516
     */
517
    bool operator<(const Array& other) const
518
6.62k
    {
519
6.62k
        return m_rawArray < other.m_rawArray;
520
6.62k
    }
521
522
    /**
523
     * Hash code.
524
     *
525
     * \return Hash code calculated on the underlying raw array.
526
     */
527
    uint32_t hashCode() const
528
1
    {
529
1
        return calcHashCode(HASH_SEED, m_rawArray);
530
1
    }
531
532
    /**
533
     * Gets raw array.
534
     *
535
     * \return Constant reference to the raw array.
536
     */
537
    const RawArray& getRawArray() const
538
20.3k
    {
539
20.3k
        return m_rawArray;
540
20.3k
    }
541
542
    /**
543
     * Gets raw array.
544
     *
545
     * \return Reference to the raw array.
546
     */
547
    RawArray& getRawArray()
548
13.9k
    {
549
13.9k
        return m_rawArray;
550
13.9k
    }
551
552
    /**
553
     * Initializes array elements.
554
     *
555
     * \param owner Array owner.
556
     */
557
    template <typename ARRAY_EXPRESSIONS_ = ArrayExpressions,
558
            typename std::enable_if<has_initialize_element<ARRAY_EXPRESSIONS_>::value, int>::type = 0>
559
    void initializeElements(OwnerType& owner)
560
70
    {
561
70
        size_t index = 0;
562
70
        for (auto&& element : m_rawArray)
563
195
        {
564
195
            ArrayExpressions::initializeElement(owner, element, index);
565
195
            index++;
566
195
        }
567
70
    }
568
569
    /**
570
     * Calculates bit size of this array.
571
     *
572
     * Available for arrays which do not need the owner.
573
     *
574
     * \param bitPosition Current bit position.
575
     *
576
     * \return Bit size of the array.
577
     */
578
    template <typename OWNER_TYPE_ = OwnerType,
579
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
580
    size_t bitSizeOf(size_t bitPosition) const
581
2.11k
    {
582
2.11k
        return bitSizeOfImpl(detail::DummyArrayOwner(), bitPosition);
583
2.11k
    }
584
585
    /**
586
     * Calculates bit size of this array.
587
     *
588
     * Available for arrays which need the owner.
589
     *
590
     * \param owner Array owner.
591
     * \param bitPosition Current bit position.
592
     *
593
     * \return Bit size of the array.
594
     */
595
    template <typename OWNER_TYPE_ = OwnerType,
596
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
597
    size_t bitSizeOf(const OwnerType& owner, size_t bitPosition) const
598
304
    {
599
304
        return bitSizeOfImpl(owner, bitPosition);
600
304
    }
601
602
    /**
603
     * Initializes indexed offsets.
604
     *
605
     * Available for arrays which do not need the owner.
606
     *
607
     * \param bitPosition Current bit position.
608
     *
609
     * \return Updated bit position which points to the first bit after the array.
610
     */
611
    template <typename OWNER_TYPE_ = OwnerType,
612
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
613
    size_t initializeOffsets(size_t bitPosition)
614
2.11k
    {
615
2.11k
        detail::DummyArrayOwner owner;
616
2.11k
        return initializeOffsetsImpl(owner, bitPosition);
617
2.11k
    }
618
619
    /**
620
     * Initializes indexed offsets.
621
     *
622
     * Available for arrays which need the owner.
623
     *
624
     * \param owner Array owner.
625
     * \param bitPosition Current bit position.
626
     *
627
     * \return Updated bit position which points to the first bit after the array.
628
     */
629
    template <typename OWNER_TYPE_ = OwnerType,
630
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
631
    size_t initializeOffsets(OwnerType& owner, size_t bitPosition)
632
304
    {
633
304
        return initializeOffsetsImpl(owner, bitPosition);
634
304
    }
635
636
    /**
637
     * Reads the array from the bit stream.
638
     *
639
     * Available for arrays which do not need the owner.
640
     *
641
     * \param in Bit stream reader to use for reading.
642
     * \param arrayLength Array length. Not needed for auto / implicit arrays.
643
     */
644
    template <typename OWNER_TYPE_ = OwnerType,
645
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
646
    void read(BitStreamReader& in, size_t arrayLength = 0)
647
2.11k
    {
648
2.11k
        detail::DummyArrayOwner owner;
649
2.11k
        readImpl(owner, in, arrayLength);
650
2.11k
    }
651
652
    /**
653
     * Reads the array from the bit stream.
654
     *
655
     * Available for arrays which need the owner.
656
     *
657
     * \param owner Array owner.
658
     * \param in Bit stream reader to use for reading.
659
     * \param arrayLength Array length. Not needed for auto / implicit arrays.
660
     */
661
    template <typename OWNER_TYPE_ = OwnerType,
662
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
663
    void read(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
664
304
    {
665
304
        readImpl(owner, in, arrayLength);
666
304
    }
667
668
    /**
669
     * Writes the array to the bit stream.
670
     *
671
     * Available for arrays which do not need the owner.
672
     *
673
     * \param out Bit stream write to use for writing.
674
     */
675
    template <typename OWNER_TYPE_ = OwnerType,
676
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
677
    void write(BitStreamWriter& out) const
678
2.11k
    {
679
2.11k
        writeImpl(detail::DummyArrayOwner(), out);
680
2.11k
    }
681
682
    /**
683
     * Writes the array to the bit stream.
684
     *
685
     * Available for arrays which need the owner.
686
     *
687
     * \param owner Array owner.
688
     * \param out Bit stream write to use for writing.
689
     */
690
    template <typename OWNER_TYPE_ = OwnerType,
691
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
692
    void write(const OwnerType& owner, BitStreamWriter& out) const
693
304
    {
694
304
        writeImpl(owner, out);
695
304
    }
696
697
    /**
698
     * Returns length of the packed array stored in the bit stream in bits.
699
     *
700
     * Available for arrays which do not need the owner.
701
     *
702
     * \param bitPosition Current bit stream position.
703
     *
704
     * \return Length of the array stored in the bit stream in bits.
705
     */
706
    template <typename OWNER_TYPE_ = OwnerType,
707
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
708
    size_t bitSizeOfPacked(size_t bitPosition) const
709
800
    {
710
800
        return bitSizeOfPackedImpl(detail::DummyArrayOwner(), bitPosition);
711
800
    }
712
713
    /**
714
     * Returns length of the packed array stored in the bit stream in bits.
715
     *
716
     * Available for arrays which need the owner.
717
     *
718
     * \param owner Array owner.
719
     * \param bitPosition Current bit stream position.
720
     *
721
     * \return Length of the array stored in the bit stream in bits.
722
     */
723
    template <typename OWNER_TYPE_ = OwnerType,
724
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
725
    size_t bitSizeOfPacked(const OwnerType& ownerType, size_t bitPosition) const
726
96
    {
727
96
        return bitSizeOfPackedImpl(ownerType, bitPosition);
728
96
    }
729
730
    /**
731
     * Initializes indexed offsets for the packed array.
732
     *
733
     * Available for arrays which do not need the owner.
734
     *
735
     * \param bitPosition Current bit stream position.
736
     *
737
     * \return Updated bit stream position which points to the first bit after the array.
738
     */
739
    template <typename OWNER_TYPE_ = OwnerType,
740
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
741
    size_t initializeOffsetsPacked(size_t bitPosition)
742
800
    {
743
800
        detail::DummyArrayOwner owner;
744
800
        return initializeOffsetsPackedImpl(owner, bitPosition);
745
800
    }
746
747
    /**
748
     * Initializes indexed offsets for the packed array.
749
     *
750
     * Available for arrays which need the owner.
751
     *
752
     * \param owner Array owner.
753
     * \param bitPosition Current bit stream position.
754
     *
755
     * \return Updated bit stream position which points to the first bit after the array.
756
     */
757
    template <typename OWNER_TYPE_ = OwnerType,
758
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
759
    size_t initializeOffsetsPacked(OwnerType& owner, size_t bitPosition)
760
96
    {
761
96
        return initializeOffsetsPackedImpl(owner, bitPosition);
762
96
    }
763
764
    /**
765
     * Reads packed array from the bit stream.
766
     *
767
     * Available for arrays which do not need the owner.
768
     *
769
     * \param in Bit stream from which to read.
770
     * \param arrayLength Number of elements to read or 0 in case of auto arrays.
771
     */
772
    template <typename OWNER_TYPE_ = OwnerType,
773
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
774
    void readPacked(BitStreamReader& in, size_t arrayLength = 0)
775
800
    {
776
800
        detail::DummyArrayOwner owner;
777
800
        readPackedImpl(owner, in, arrayLength);
778
800
    }
779
780
    /**
781
     * Reads packed array from the bit stream.
782
     *
783
     * Available for arrays which need the owner.
784
     *
785
     * \param owner Array owner.
786
     * \param in Bit stream from which to read.
787
     * \param arrayLength Number of elements to read or 0 in case of auto arrays.
788
     */
789
    template <typename OWNER_TYPE_ = OwnerType,
790
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
791
    void readPacked(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
792
96
    {
793
96
        readPackedImpl(owner, in, arrayLength);
794
96
    }
795
796
    /**
797
     * Writes packed array to the bit stream.
798
     *
799
     * Available for arrays which do not need the owner.
800
     *
801
     * \param out Bit stream where to write.
802
     */
803
    template <typename OWNER_TYPE_ = OwnerType,
804
            typename std::enable_if<std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
805
    void writePacked(BitStreamWriter& out) const
806
800
    {
807
800
        writePackedImpl(detail::DummyArrayOwner(), out);
808
800
    }
809
810
    /**
811
     * Writes packed array to the bit stream.
812
     *
813
     * Available for arrays which need the owner.
814
     *
815
     * \param owner Array owner.
816
     * \param out Bit stream where to write.
817
     */
818
    template <typename OWNER_TYPE_ = OwnerType,
819
            typename std::enable_if<!std::is_same<OWNER_TYPE_, detail::DummyArrayOwner>::value, int>::type = 0>
820
    void writePacked(const OwnerType& owner, BitStreamWriter& out) const
821
96
    {
822
96
        writePackedImpl(owner, out);
823
96
    }
824
825
private:
826
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
827
            typename std::enable_if<ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
828
                    int>::type = 0>
829
    static void addBitSizeOfArrayLength(size_t&, size_t)
830
3.45k
    {}
831
832
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
833
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
834
                    int>::type = 0>
835
    static void addBitSizeOfArrayLength(size_t& bitPosition, size_t arrayLength)
836
3.16k
    {
837
3.16k
        bitPosition += bitSizeOfVarSize(convertSizeToUInt32(arrayLength));
838
3.16k
    }
839
840
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
841
            typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
842
                    int>::type = 0>
843
    static void alignBitPosition(size_t&)
844
3.28k
    {}
845
846
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
847
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
848
                    int>::type = 0>
849
    static void alignBitPosition(size_t& bitPosition)
850
3.28k
    {
851
3.28k
        bitPosition = alignTo(8, bitPosition);
852
3.28k
    }
853
854
    template <typename IO, typename OWNER_TYPE, ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
855
            typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
856
                    int>::type = 0>
857
    static void alignAndCheckOffset(IO&, OWNER_TYPE&, size_t)
858
10.0k
    {}
859
860
    template <typename IO, typename OWNER_TYPE, ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
861
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
862
                    int>::type = 0>
863
    static void alignAndCheckOffset(IO& io, OWNER_TYPE& owner, size_t index)
864
9.40k
    {
865
9.40k
        io.alignTo(8);
866
9.40k
        detail::checkOffset<ArrayExpressions>(owner, index, io.getBitPosition() / 8);
867
9.40k
    }
868
869
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
870
            typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
871
                    int>::type = 0>
872
    static void initializeOffset(OwnerType&, size_t, size_t&)
873
5.01k
    {}
874
875
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
876
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
877
                    int>::type = 0>
878
    static void initializeOffset(OwnerType& owner, size_t index, size_t& bitPosition)
879
4.70k
    {
880
4.70k
        bitPosition = alignTo(8, bitPosition);
881
4.70k
        detail::initializeOffset<ArrayExpressions>(owner, index, bitPosition / 8);
882
4.70k
    }
883
884
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
885
            typename std::enable_if<ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO &&
886
                            ARRAY_TYPE_ != ArrayType::IMPLICIT,
887
                    int>::type = 0>
888
    static size_t readArrayLength(OwnerType&, BitStreamReader&, size_t arrayLength)
889
1.58k
    {
890
1.58k
        return arrayLength;
891
1.58k
    }
892
893
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
894
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
895
                    int>::type = 0>
896
    static size_t readArrayLength(OwnerType&, BitStreamReader& in, size_t)
897
1.58k
    {
898
1.58k
        return in.readVarSize();
899
1.58k
    }
900
901
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
902
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::IMPLICIT, int>::type = 0>
903
    static size_t readArrayLength(OwnerType& owner, BitStreamReader& in, size_t)
904
144
    {
905
144
        static_assert(ARRAY_TYPE != ArrayType::IMPLICIT || ArrayTraits::IS_BITSIZEOF_CONSTANT,
906
144
                "Implicit array elements must have constant bit size!");
907
908
144
        const size_t remainingBits = in.getBufferBitSize() - in.getBitPosition();
909
144
        return remainingBits / detail::arrayTraitsConstBitSizeOf<ArrayTraits>(owner);
910
144
    }
911
912
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
913
            typename std::enable_if<ARRAY_TYPE_ != ArrayType::AUTO && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
914
                    int>::type = 0>
915
    static void writeArrayLength(BitStreamWriter&, size_t)
916
1.72k
    {}
917
918
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
919
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::AUTO || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
920
                    int>::type = 0>
921
    static void writeArrayLength(BitStreamWriter& out, size_t arrayLength)
922
1.58k
    {
923
1.58k
        out.writeVarSize(convertSizeToUInt32(arrayLength));
924
1.58k
    }
925
926
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
927
            typename std::enable_if<ARRAY_TYPE_ != ArrayType::ALIGNED && ARRAY_TYPE_ != ArrayType::ALIGNED_AUTO,
928
                    int>::type = 0>
929
    static size_t constBitSizeOfElements(size_t, size_t arrayLength, size_t elementBitSize)
930
584
    {
931
584
        return arrayLength * elementBitSize;
932
584
    }
933
934
    template <ArrayType ARRAY_TYPE_ = ARRAY_TYPE,
935
            typename std::enable_if<ARRAY_TYPE_ == ArrayType::ALIGNED || ARRAY_TYPE_ == ArrayType::ALIGNED_AUTO,
936
                    int>::type = 0>
937
    static size_t constBitSizeOfElements(size_t bitPosition, size_t arrayLength, size_t elementBitSize)
938
480
    {
939
480
        size_t endBitPosition = alignTo(8, bitPosition);
940
480
        endBitPosition += elementBitSize + (arrayLength - 1) * alignTo(8, elementBitSize);
941
942
480
        return endBitPosition - bitPosition;
943
480
    }
944
945
    template <typename ARRAY_TRAITS_ = ArrayTraits,
946
            typename std::enable_if<ARRAY_TRAITS_::IS_BITSIZEOF_CONSTANT, int>::type = 0>
947
    size_t bitSizeOfImpl(const OwnerType& owner, size_t bitPosition) const
948
1.42k
    {
949
1.42k
        size_t endBitPosition = bitPosition;
950
951
1.42k
        const size_t arrayLength = m_rawArray.size();
952
1.42k
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
953
954
1.42k
        if (arrayLength > 0)
955
1.06k
        {
956
1.06k
            const size_t elementBitSize = detail::arrayTraitsConstBitSizeOf<ArrayTraits>(owner);
957
1.06k
            endBitPosition += constBitSizeOfElements(endBitPosition, arrayLength, elementBitSize);
958
1.06k
        }
959
960
1.42k
        return endBitPosition - bitPosition;
961
1.42k
    }
962
963
    template <typename ARRAY_TRAITS_ = ArrayTraits,
964
            typename std::enable_if<!ARRAY_TRAITS_::IS_BITSIZEOF_CONSTANT, int>::type = 0>
965
    size_t bitSizeOfImpl(const OwnerType& owner, size_t bitPosition) const
966
993
    {
967
993
        size_t endBitPosition = bitPosition;
968
969
993
        const size_t arrayLength = m_rawArray.size();
970
993
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
971
972
3.74k
        for (size_t index = 0; index < arrayLength; 
++index2.75k
)
973
2.75k
        {
974
2.75k
            alignBitPosition(endBitPosition);
975
2.75k
            endBitPosition +=
976
2.75k
                    detail::arrayTraitsBitSizeOf<ArrayTraits>(owner, endBitPosition, m_rawArray[index]);
977
2.75k
        }
978
979
993
        return endBitPosition - bitPosition;
980
993
    }
981
982
    size_t initializeOffsetsImpl(OwnerType& owner, size_t bitPosition)
983
2.41k
    {
984
2.41k
        size_t endBitPosition = bitPosition;
985
986
2.41k
        const size_t arrayLength = m_rawArray.size();
987
2.41k
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
988
989
8.33k
        for (size_t index = 0; index < arrayLength; 
++index5.91k
)
990
5.91k
        {
991
5.91k
            initializeOffset(owner, index, endBitPosition);
992
5.91k
            endBitPosition =
993
5.91k
                    detail::arrayTraitsInitializeOffsets<ArrayTraits>(owner, endBitPosition, m_rawArray[index]);
994
5.91k
        }
995
996
2.41k
        return endBitPosition;
997
2.41k
    }
998
999
    void readImpl(OwnerType& owner, BitStreamReader& in, size_t arrayLength)
1000
2.41k
    {
1001
2.41k
        size_t readLength = readArrayLength(owner, in, arrayLength);
1002
1003
2.41k
        m_rawArray.clear();
1004
2.41k
        m_rawArray.reserve(readLength);
1005
8.33k
        for (size_t index = 0; index < readLength; 
++index5.91k
)
1006
5.91k
        {
1007
5.91k
            alignAndCheckOffset(in, owner, index);
1008
5.91k
            detail::arrayTraitsRead<ArrayTraits>(owner, m_rawArray, in, index);
1009
5.91k
        }
1010
2.41k
    }
1011
1012
    void writeImpl(const OwnerType& owner, BitStreamWriter& out) const
1013
2.41k
    {
1014
2.41k
        const size_t arrayLength = m_rawArray.size();
1015
2.41k
        writeArrayLength(out, arrayLength);
1016
1017
8.33k
        for (size_t index = 0; index < arrayLength; 
++index5.91k
)
1018
5.91k
        {
1019
5.91k
            alignAndCheckOffset(out, owner, index);
1020
5.91k
            detail::arrayTraitsWrite<ArrayTraits>(owner, out, m_rawArray[index]);
1021
5.91k
        }
1022
2.41k
    }
1023
1024
    using PackingContext = typename detail::packing_context_type<typename RawArray::value_type>::type;
1025
1026
    size_t bitSizeOfPackedImpl(const OwnerType& owner, size_t bitPosition) const
1027
896
    {
1028
896
        static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1029
1030
896
        size_t endBitPosition = bitPosition;
1031
1032
896
        const size_t arrayLength = m_rawArray.size();
1033
896
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
1034
1035
896
        if (arrayLength > 0)
1036
832
        {
1037
832
            PackingContext context;
1038
1039
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1040
3.80k
            {
1041
3.80k
                detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1042
3.80k
                        owner, context, m_rawArray[index]);
1043
3.80k
            }
1044
1045
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1046
3.80k
            {
1047
3.80k
                alignBitPosition(endBitPosition);
1048
3.80k
                endBitPosition += detail::packedArrayTraitsBitSizeOf<PackedArrayTraits<ArrayTraits>>(
1049
3.80k
                        owner, context, endBitPosition, m_rawArray[index]);
1050
3.80k
            }
1051
832
        }
1052
1053
896
        return endBitPosition - bitPosition;
1054
896
    }
1055
1056
    size_t initializeOffsetsPackedImpl(OwnerType& owner, size_t bitPosition)
1057
896
    {
1058
896
        static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1059
1060
896
        size_t endBitPosition = bitPosition;
1061
1062
896
        const size_t arrayLength = m_rawArray.size();
1063
896
        addBitSizeOfArrayLength(endBitPosition, arrayLength);
1064
1065
896
        if (arrayLength > 0)
1066
832
        {
1067
832
            PackingContext context;
1068
1069
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1070
3.80k
            {
1071
3.80k
                detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1072
3.80k
                        owner, context, m_rawArray[index]);
1073
3.80k
            }
1074
1075
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1076
3.80k
            {
1077
3.80k
                initializeOffset(owner, index, endBitPosition);
1078
3.80k
                endBitPosition = detail::packedArrayTraitsInitializeOffsets<PackedArrayTraits<ArrayTraits>>(
1079
3.80k
                        owner, context, endBitPosition, m_rawArray[index]);
1080
3.80k
            }
1081
832
        }
1082
1083
896
        return endBitPosition;
1084
896
    }
1085
1086
    void readPackedImpl(OwnerType& owner, BitStreamReader& in, size_t arrayLength = 0)
1087
896
    {
1088
896
        static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1089
1090
896
        size_t readLength = readArrayLength(owner, in, arrayLength);
1091
1092
896
        m_rawArray.clear();
1093
1094
896
        if (readLength > 0)
1095
832
        {
1096
832
            m_rawArray.reserve(readLength);
1097
1098
832
            PackingContext context;
1099
1100
4.64k
            for (size_t index = 0; index < readLength; 
++index3.80k
)
1101
3.80k
            {
1102
3.80k
                alignAndCheckOffset(in, owner, index);
1103
3.80k
                detail::packedArrayTraitsRead<PackedArrayTraits<ArrayTraits>>(
1104
3.80k
                        owner, m_rawArray, context, in, index);
1105
3.80k
            }
1106
832
        }
1107
896
    }
1108
1109
    void writePackedImpl(const OwnerType& owner, BitStreamWriter& out) const
1110
896
    {
1111
896
        static_assert(ARRAY_TYPE != ArrayType::IMPLICIT, "Implicit array cannot be packed!");
1112
1113
896
        const size_t arrayLength = m_rawArray.size();
1114
896
        writeArrayLength(out, arrayLength);
1115
1116
896
        if (arrayLength > 0)
1117
832
        {
1118
832
            PackingContext context;
1119
1120
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1121
3.80k
            {
1122
3.80k
                detail::packedArrayTraitsInitContext<PackedArrayTraits<ArrayTraits>>(
1123
3.80k
                        owner, context, m_rawArray[index]);
1124
3.80k
            }
1125
1126
4.64k
            for (size_t index = 0; index < arrayLength; 
++index3.80k
)
1127
3.80k
            {
1128
3.80k
                alignAndCheckOffset(out, owner, index);
1129
3.80k
                detail::packedArrayTraitsWrite<PackedArrayTraits<ArrayTraits>>(
1130
3.80k
                        owner, context, out, m_rawArray[index]);
1131
3.80k
            }
1132
832
        }
1133
896
    }
1134
1135
    RawArray m_rawArray;
1136
};
1137
1138
/**
1139
 * Helper for creating an optional array within templated field constructor, where the raw array can be
1140
 * actually the NullOpt.
1141
 */
1142
template <typename ARRAY, typename RAW_ARRAY>
1143
ARRAY createOptionalArray(RAW_ARRAY&& rawArray)
1144
1
{
1145
1
    return ARRAY(std::forward<RAW_ARRAY>(rawArray));
1146
1
}
1147
1148
/**
1149
 * Overload for NullOpt.
1150
 */
1151
template <typename ARRAY>
1152
NullOptType createOptionalArray(NullOptType)
1153
14
{
1154
14
    return NullOpt;
1155
14
}
1156
1157
} // namespace zserio
1158
1159
#endif // ZSERIO_ARRAY_H_INC