Coverage Report

Created: 2024-07-18 11:41

src/zserio/Walker.h
Line
Count
Source
1
#ifndef ZSERIO_WALKER_H_INC
2
#define ZSERIO_WALKER_H_INC
3
4
#include <algorithm>
5
#include <functional>
6
#include <regex>
7
8
#include "zserio/IReflectable.h"
9
#include "zserio/ITypeInfo.h"
10
#include "zserio/IWalkFilter.h"
11
#include "zserio/IWalkObserver.h"
12
#include "zserio/String.h"
13
#include "zserio/StringConvertUtil.h"
14
#include "zserio/TypeInfoUtil.h"
15
#include "zserio/Vector.h"
16
#include "zserio/WalkerConst.h"
17
18
namespace zserio
19
{
20
21
template <typename ALLOC>
22
class BasicDefaultWalkFilter;
23
24
/**
25
 * Walker through zserio objects, based on generated type info (see -withTypeInfoCode) and
26
 * reflectable interface (see -withReflectionCode).
27
 */
28
template <typename ALLOC = std::allocator<uint8_t>>
29
class BasicWalker
30
{
31
public:
32
    /**
33
     * Constructor using default walk filter.
34
     *
35
     * \param walkObserver Observer to use during walking.
36
     */
37
    explicit BasicWalker(IBasicWalkObserver<ALLOC>& walkObserver);
38
39
    /**
40
     * Constructor.
41
     *
42
     * \param walkObserver Observer to use during walking.
43
     * \param walkFilter Walk filter to use.
44
     */
45
    BasicWalker(IBasicWalkObserver<ALLOC>& walkObserver, IBasicWalkFilter<ALLOC>& walkFilter);
46
47
    /**
48
     * Method generated by default.
49
     */
50
56
    ~BasicWalker() = default;
51
52
    /**
53
     * Copying and moving is disallowed!
54
     * \{
55
     */
56
    BasicWalker(const BasicWalker& other) = delete;
57
    BasicWalker& operator=(const BasicWalker& other) = delete;
58
59
    BasicWalker(BasicWalker&& other) = delete;
60
    BasicWalker& operator=(BasicWalker&& other) = delete;
61
    /**
62
     * \}
63
     */
64
65
    /**
66
     * Walks given reflectable zserio compound object.
67
     *
68
     * \param compound Zserio compound object to walk.
69
     */
70
    void walk(const IBasicReflectableConstPtr<ALLOC>& compound);
71
72
private:
73
    void walkFields(const IBasicReflectableConstPtr<ALLOC>& compound, const IBasicTypeInfo<ALLOC>& typeInfo);
74
    bool walkField(const IBasicReflectableConstPtr<ALLOC>& reflectable, const BasicFieldInfo<ALLOC>& fieldInfo);
75
    bool walkFieldValue(const IBasicReflectableConstPtr<ALLOC>& reflectable,
76
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex = WALKER_NOT_ELEMENT);
77
78
    IBasicWalkObserver<ALLOC>& m_walkObserver;
79
    BasicDefaultWalkFilter<ALLOC> m_defaultWalkFilter;
80
    IBasicWalkFilter<ALLOC>& m_walkFilter;
81
};
82
83
/**
84
 * Default walk observer which just does nothing.
85
 */
86
template <typename ALLOC = std::allocator<uint8_t>>
87
class BasicDefaultWalkObserver : public IBasicWalkObserver<ALLOC>
88
{
89
public:
90
    /**
91
     * Method generated by default.
92
     * \{
93
     */
94
14
    BasicDefaultWalkObserver() = default;
95
14
    ~BasicDefaultWalkObserver() override = default;
96
    /**
97
     * \}
98
     */
99
100
    /**
101
     * Copying and moving is disallowed!
102
     * \{
103
     */
104
    BasicDefaultWalkObserver(const BasicDefaultWalkObserver& other) = delete;
105
    BasicDefaultWalkObserver& operator=(const BasicDefaultWalkObserver& other) = delete;
106
107
    BasicDefaultWalkObserver(BasicDefaultWalkObserver&& other) = delete;
108
    BasicDefaultWalkObserver& operator=(BasicDefaultWalkObserver&& other) = delete;
109
    /**
110
     * \}
111
     */
112
113
    void beginRoot(const IBasicReflectableConstPtr<ALLOC>&) override
114
12
    {}
115
    void endRoot(const IBasicReflectableConstPtr<ALLOC>&) override
116
12
    {}
117
118
    void beginArray(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&) override
119
3
    {}
120
    void endArray(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&) override
121
3
    {}
122
123
    void beginCompound(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t) override
124
3
    {}
125
    void endCompound(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t) override
126
3
    {}
127
128
    void visitValue(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t) override
129
9
    {}
130
};
131
132
/**
133
 * Default walk filter which filters nothing.
134
 */
135
template <typename ALLOC = std::allocator<uint8_t>>
136
class BasicDefaultWalkFilter : public IBasicWalkFilter<ALLOC>
137
{
138
public:
139
    /**
140
     * Method generated by default.
141
     * \{
142
     */
143
92
    BasicDefaultWalkFilter() = default;
144
92
    ~BasicDefaultWalkFilter() override = default;
145
    /**
146
     * \}
147
     */
148
149
    /**
150
     * Copying and moving is disallowed!
151
     * \{
152
     */
153
    BasicDefaultWalkFilter(const BasicDefaultWalkFilter& other) = delete;
154
    BasicDefaultWalkFilter& operator=(const BasicDefaultWalkFilter& other) = delete;
155
156
    BasicDefaultWalkFilter(BasicDefaultWalkFilter&& other) = delete;
157
    BasicDefaultWalkFilter& operator=(BasicDefaultWalkFilter&& other) = delete;
158
    /**
159
     * \}
160
     */
161
162
    bool beforeArray(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&) override
163
5
    {
164
5
        return true;
165
5
    }
166
167
    bool afterArray(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&) override
168
5
    {
169
5
        return true;
170
5
    }
171
172
    bool beforeCompound(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t) override
173
12
    {
174
12
        return true;
175
12
    }
176
177
    bool afterCompound(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t) override
178
12
    {
179
12
        return true;
180
12
    }
181
182
    bool beforeValue(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t) override
183
48
    {
184
48
        return true;
185
48
    }
186
187
    bool afterValue(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t) override
188
48
    {
189
48
        return true;
190
48
    }
191
};
192
193
/**
194
 * Walk filter which allows to walk only to the given maximum depth.
195
 */
196
template <typename ALLOC = std::allocator<uint8_t>>
197
class BasicDepthWalkFilter : public IBasicWalkFilter<ALLOC>
198
{
199
public:
200
    /**
201
     * Constructor.
202
     *
203
     * \param maxDepth Maximum depth to walk to.
204
     */
205
    explicit BasicDepthWalkFilter(size_t maxDepth);
206
207
    /**
208
     * Method generated by default.
209
     */
210
7
    ~BasicDepthWalkFilter() override = default;
211
212
    /**
213
     * Copying is disallowed!
214
     * \{
215
     */
216
    BasicDepthWalkFilter(const BasicDepthWalkFilter& other) = delete;
217
    BasicDepthWalkFilter& operator=(const BasicDepthWalkFilter& other) = delete;
218
219
    BasicDepthWalkFilter(BasicDepthWalkFilter&& other) = delete;
220
    BasicDepthWalkFilter& operator=(BasicDepthWalkFilter&& other) = delete;
221
    /**
222
     * \}
223
     */
224
225
    bool beforeArray(
226
            const IBasicReflectableConstPtr<ALLOC>& array, const BasicFieldInfo<ALLOC>& fieldInfo) override;
227
    bool afterArray(
228
            const IBasicReflectableConstPtr<ALLOC>& array, const BasicFieldInfo<ALLOC>& fieldInfo) override;
229
230
    bool beforeCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
231
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
232
    bool afterCompound(const IBasicReflectableConstPtr<ALLOC>& compound, const BasicFieldInfo<ALLOC>& fieldInfo,
233
            size_t elementIndex) override;
234
235
    bool beforeValue(const IBasicReflectableConstPtr<ALLOC>& value, const BasicFieldInfo<ALLOC>& fieldInfo,
236
            size_t elementIndex) override;
237
    bool afterValue(const IBasicReflectableConstPtr<ALLOC>& value, const BasicFieldInfo<ALLOC>& fieldInfo,
238
            size_t elementIndex) override;
239
240
private:
241
    bool enterDepthLevel();
242
    bool leaveDepthLevel();
243
244
    size_t m_maxDepth;
245
    size_t m_depth;
246
};
247
248
/**
249
 * Walk filter which allows to walk only paths matching the given regex.
250
 *
251
 * The path is constructed from field names within the root object, thus the root object itself
252
 * is not part of the path.
253
 *
254
 * Array elements have the index appended to the path so that e.g. "compound.arrayField[0]" will match
255
 * only the first element in the array "arrayField".
256
 */
257
template <typename ALLOC = std::allocator<uint8_t>>
258
class BasicRegexWalkFilter : public IBasicWalkFilter<ALLOC>
259
{
260
public:
261
    /**
262
     * Constructor.
263
     *
264
     * \param pathRegex Path regex to use for filtering.
265
     */
266
    explicit BasicRegexWalkFilter(const char* pathRegex, const ALLOC& allocator = ALLOC());
267
268
    /**
269
     * Method generated by default.
270
     */
271
8
    ~BasicRegexWalkFilter() override = default;
272
273
    /**
274
     * Copying is disallowed!
275
     * \{
276
     */
277
    BasicRegexWalkFilter(const BasicRegexWalkFilter& other) = delete;
278
    BasicRegexWalkFilter& operator=(const BasicRegexWalkFilter& other) = delete;
279
280
    BasicRegexWalkFilter(BasicRegexWalkFilter&& other) = delete;
281
    BasicRegexWalkFilter& operator=(BasicRegexWalkFilter&& other) = delete;
282
    /**
283
     * \}
284
     */
285
286
    bool beforeArray(
287
            const IBasicReflectableConstPtr<ALLOC>& array, const BasicFieldInfo<ALLOC>& fieldInfo) override;
288
    bool afterArray(
289
            const IBasicReflectableConstPtr<ALLOC>& array, const BasicFieldInfo<ALLOC>& fieldInfo) override;
290
291
    bool beforeCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
292
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
293
    bool afterCompound(const IBasicReflectableConstPtr<ALLOC>& compound, const BasicFieldInfo<ALLOC>& fieldInfo,
294
            size_t elementIndex) override;
295
296
    bool beforeValue(const IBasicReflectableConstPtr<ALLOC>& value, const BasicFieldInfo<ALLOC>& fieldInfo,
297
            size_t elementIndex) override;
298
    bool afterValue(const IBasicReflectableConstPtr<ALLOC>& value, const BasicFieldInfo<ALLOC>& fieldInfo,
299
            size_t elementIndex) override;
300
301
private:
302
    void appendPath(const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex);
303
    void popPath(const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex);
304
    string<ALLOC> getCurrentPath() const;
305
    bool matchSubtree(
306
            const IBasicReflectableConstPtr<ALLOC>& value, const BasicFieldInfo<ALLOC>& fieldInfo) const;
307
308
    vector<string<ALLOC>, ALLOC> m_currentPath;
309
    std::regex m_pathRegex;
310
    ALLOC m_allocator; // TODO[Mi-L@]: Check how std::regex_match allocates when results are omitted!
311
};
312
313
/**
314
 * Walk filter which allows to walk only to the given maximum array length.
315
 */
316
template <typename ALLOC = std::allocator<uint8_t>>
317
class BasicArrayLengthWalkFilter : public IBasicWalkFilter<ALLOC>
318
{
319
public:
320
    /**
321
     * Constructor.
322
     *
323
     * \param maxArrayLength Maximum array length to walk to.
324
     */
325
    explicit BasicArrayLengthWalkFilter(size_t maxArrayLength);
326
327
    /**
328
     * Method generated by default.
329
     */
330
1
    ~BasicArrayLengthWalkFilter() override = default;
331
332
    /**
333
     * Copying and moving is disallowed!
334
     * \{
335
     */
336
    BasicArrayLengthWalkFilter(const BasicArrayLengthWalkFilter& other) = delete;
337
    BasicArrayLengthWalkFilter& operator=(const BasicArrayLengthWalkFilter& other) = delete;
338
339
    BasicArrayLengthWalkFilter(BasicArrayLengthWalkFilter&& other) = delete;
340
    BasicArrayLengthWalkFilter& operator=(BasicArrayLengthWalkFilter&& other) = delete;
341
    /**
342
     * \}
343
     */
344
345
    bool beforeArray(
346
            const IBasicReflectableConstPtr<ALLOC>& array, const BasicFieldInfo<ALLOC>& fieldInfo) override;
347
    bool afterArray(
348
            const IBasicReflectableConstPtr<ALLOC>& array, const BasicFieldInfo<ALLOC>& fieldInfo) override;
349
350
    bool beforeCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
351
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
352
    bool afterCompound(const IBasicReflectableConstPtr<ALLOC>& compound, const BasicFieldInfo<ALLOC>& fieldInfo,
353
            size_t elementIndex) override;
354
355
    bool beforeValue(const IBasicReflectableConstPtr<ALLOC>& value, const BasicFieldInfo<ALLOC>& fieldInfo,
356
            size_t elementIndex) override;
357
    bool afterValue(const IBasicReflectableConstPtr<ALLOC>& value, const BasicFieldInfo<ALLOC>& fieldInfo,
358
            size_t elementIndex) override;
359
360
private:
361
    bool filterArrayElement(size_t elementIndex);
362
363
    size_t m_maxArrayLength;
364
};
365
366
/**
367
 * Walk filter which implements composition of particular filters.
368
 *
369
 * The filters are called sequentially and logical and is applied on theirs results.
370
 * Note that all filters are always called.
371
 */
372
template <typename ALLOC = std::allocator<uint8_t>>
373
class BasicAndWalkFilter : public IBasicWalkFilter<ALLOC>
374
{
375
public:
376
    using WalkFilterRef = std::reference_wrapper<IBasicWalkFilter<ALLOC>>;
377
    using WalkFilters = vector<WalkFilterRef, ALLOC>;
378
379
    /**
380
     * Constructor.
381
     *
382
     * \param walkFilters List of filters to use in composition.
383
     */
384
    explicit BasicAndWalkFilter(const WalkFilters& walkFilters);
385
386
    /**
387
     * Method generated by default.
388
     */
389
4
    ~BasicAndWalkFilter() override = default;
390
391
    /**
392
     * Copying and moving is disallowed!
393
     * \{
394
     */
395
    BasicAndWalkFilter(const BasicAndWalkFilter& other) = delete;
396
    BasicAndWalkFilter& operator=(const BasicAndWalkFilter& other) = delete;
397
398
    BasicAndWalkFilter(BasicAndWalkFilter&& other) = delete;
399
    BasicAndWalkFilter& operator=(BasicAndWalkFilter&& other) = delete;
400
    /**
401
     * \}
402
     */
403
404
    bool beforeArray(
405
            const IBasicReflectableConstPtr<ALLOC>& array, const BasicFieldInfo<ALLOC>& fieldInfo) override;
406
    bool afterArray(
407
            const IBasicReflectableConstPtr<ALLOC>& array, const BasicFieldInfo<ALLOC>& fieldInfo) override;
408
409
    bool beforeCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
410
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
411
    bool afterCompound(const IBasicReflectableConstPtr<ALLOC>& compound, const BasicFieldInfo<ALLOC>& fieldInfo,
412
            size_t elementIndex) override;
413
414
    bool beforeValue(const IBasicReflectableConstPtr<ALLOC>& value, const BasicFieldInfo<ALLOC>& fieldInfo,
415
            size_t elementIndex) override;
416
    bool afterValue(const IBasicReflectableConstPtr<ALLOC>& value, const BasicFieldInfo<ALLOC>& fieldInfo,
417
            size_t elementIndex) override;
418
419
private:
420
    template <typename FILTER_FUNC, typename... ARGS>
421
    bool applyFilters(FILTER_FUNC filterFunc, ARGS... args)
422
24
    {
423
24
        bool result = true;
424
24
        for (IBasicWalkFilter<ALLOC>& walkFilter : m_walkFilters)
425
36
        {
426
36
            result &= (walkFilter.*filterFunc)(args...);
427
36
        }
428
24
        return result;
429
24
    }
430
431
    WalkFilters m_walkFilters;
432
};
433
434
/** Typedefs to walker related classes provided for convenience - using default std::allocator<uint8_t>. */
435
/** \{ */
436
using Walker = BasicWalker<>;
437
using DefaultWalkObserver = BasicDefaultWalkObserver<>;
438
using DefaultWalkFilter = BasicDefaultWalkFilter<>;
439
using DepthWalkFilter = BasicDepthWalkFilter<>;
440
using RegexWalkFilter = BasicRegexWalkFilter<>;
441
using ArrayLengthWalkFilter = BasicArrayLengthWalkFilter<>;
442
using AndWalkFilter = BasicAndWalkFilter<>;
443
/** \} */
444
445
template <typename ALLOC>
446
BasicWalker<ALLOC>::BasicWalker(IBasicWalkObserver<ALLOC>& walkObserver) :
447
        m_walkObserver(walkObserver),
448
        m_walkFilter(m_defaultWalkFilter)
449
2
{}
450
451
template <typename ALLOC>
452
BasicWalker<ALLOC>::BasicWalker(IBasicWalkObserver<ALLOC>& walkObserver, IBasicWalkFilter<ALLOC>& walkFilter) :
453
        m_walkObserver(walkObserver),
454
        m_walkFilter(walkFilter)
455
54
{}
456
457
template <typename ALLOC>
458
void BasicWalker<ALLOC>::walk(const IBasicReflectableConstPtr<ALLOC>& compound)
459
56
{
460
56
    if (!compound)
461
1
    {
462
1
        throw CppRuntimeException("Walker: Root object cannot be NULL!");
463
1
    }
464
465
55
    const IBasicTypeInfo<ALLOC>& typeInfo = compound->getTypeInfo();
466
55
    if (!TypeInfoUtil::isCompound(typeInfo.getSchemaType()))
467
1
    {
468
1
        throw CppRuntimeException("Walker: Root object '")
469
1
                << typeInfo.getSchemaName() << "' is not a compound type!";
470
1
    }
471
472
54
    m_walkObserver.beginRoot(compound);
473
54
    walkFields(compound, typeInfo);
474
54
    m_walkObserver.endRoot(compound);
475
54
}
476
477
template <typename ALLOC>
478
void BasicWalker<ALLOC>::walkFields(
479
        const IBasicReflectableConstPtr<ALLOC>& compound, const IBasicTypeInfo<ALLOC>& typeInfo)
480
71
{
481
71
    if (TypeInfoUtil::hasChoice(typeInfo.getSchemaType()))
482
21
    {
483
21
        StringView compoundChoice = compound->getChoice();
484
21
        if (!compoundChoice.empty())
485
18
        {
486
18
            Span<const BasicFieldInfo<ALLOC>> fields = typeInfo.getFields();
487
18
            auto fieldsIt = std::find_if(
488
38
                    fields.begin(), fields.end(), [compoundChoice](const BasicFieldInfo<ALLOC>& fieldInfo) {
489
38
                        return fieldInfo.schemaName == compoundChoice;
490
38
                    });
491
18
            if (fieldsIt != fields.end())
492
17
            {
493
17
                walkField(compound->getField(compoundChoice), *fieldsIt);
494
17
            }
495
18
        }
496
        // else uninitialized or empty branch
497
21
    }
498
50
    else
499
50
    {
500
50
        for (const BasicFieldInfo<ALLOC>& fieldInfo : typeInfo.getFields())
501
75
        {
502
75
            if (!walkField(compound->getField(fieldInfo.schemaName), fieldInfo))
503
3
            {
504
3
                break;
505
3
            }
506
75
        }
507
50
    }
508
71
}
509
510
template <typename ALLOC>
511
bool BasicWalker<ALLOC>::walkField(
512
        const IBasicReflectableConstPtr<ALLOC>& reflectable, const BasicFieldInfo<ALLOC>& fieldInfo)
513
92
{
514
92
    if (reflectable && 
fieldInfo.isArray87
)
515
10
    {
516
10
        if (m_walkFilter.beforeArray(reflectable, fieldInfo))
517
8
        {
518
8
            m_walkObserver.beginArray(reflectable, fieldInfo);
519
21
            for (size_t i = 0; i < reflectable->size(); 
++i13
)
520
14
            {
521
14
                if (!walkFieldValue(reflectable->at(i), fieldInfo, i))
522
1
                {
523
1
                    break;
524
1
                }
525
14
            }
526
8
            m_walkObserver.endArray(reflectable, fieldInfo);
527
8
        }
528
10
        return m_walkFilter.afterArray(reflectable, fieldInfo);
529
10
    }
530
82
    else
531
82
    {
532
82
        return walkFieldValue(reflectable, fieldInfo);
533
82
    }
534
92
}
535
536
template <typename ALLOC>
537
bool BasicWalker<ALLOC>::walkFieldValue(const IBasicReflectableConstPtr<ALLOC>& reflectable,
538
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
539
96
{
540
96
    const IBasicTypeInfo<ALLOC>& typeInfo = fieldInfo.typeInfo;
541
96
    if (reflectable && 
TypeInfoUtil::isCompound(typeInfo.getSchemaType())91
)
542
22
    {
543
22
        if (m_walkFilter.beforeCompound(reflectable, fieldInfo, elementIndex))
544
17
        {
545
17
            m_walkObserver.beginCompound(reflectable, fieldInfo, elementIndex);
546
17
            walkFields(reflectable, typeInfo);
547
17
            m_walkObserver.endCompound(reflectable, fieldInfo, elementIndex);
548
17
        }
549
22
        return m_walkFilter.afterCompound(reflectable, fieldInfo, elementIndex);
550
22
    }
551
74
    else
552
74
    {
553
74
        if (m_walkFilter.beforeValue(reflectable, fieldInfo, elementIndex))
554
68
        {
555
68
            m_walkObserver.visitValue(reflectable, fieldInfo, elementIndex);
556
68
        }
557
74
        return m_walkFilter.afterValue(reflectable, fieldInfo, elementIndex);
558
74
    }
559
96
}
560
561
template <typename ALLOC>
562
BasicDepthWalkFilter<ALLOC>::BasicDepthWalkFilter(size_t maxDepth) :
563
        m_maxDepth(maxDepth),
564
        m_depth(1)
565
7
{}
566
567
template <typename ALLOC>
568
bool BasicDepthWalkFilter<ALLOC>::beforeArray(
569
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&)
570
4
{
571
4
    return enterDepthLevel();
572
4
}
573
574
template <typename ALLOC>
575
bool BasicDepthWalkFilter<ALLOC>::afterArray(
576
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&)
577
4
{
578
4
    return leaveDepthLevel();
579
4
}
580
581
template <typename ALLOC>
582
bool BasicDepthWalkFilter<ALLOC>::beforeCompound(
583
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t)
584
4
{
585
4
    return enterDepthLevel();
586
4
}
587
588
template <typename ALLOC>
589
bool BasicDepthWalkFilter<ALLOC>::afterCompound(
590
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t)
591
4
{
592
4
    return leaveDepthLevel();
593
4
}
594
595
template <typename ALLOC>
596
bool BasicDepthWalkFilter<ALLOC>::beforeValue(
597
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t)
598
9
{
599
9
    return m_depth <= m_maxDepth;
600
9
}
601
602
template <typename ALLOC>
603
bool BasicDepthWalkFilter<ALLOC>::afterValue(
604
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t)
605
9
{
606
9
    return true;
607
9
}
608
609
template <typename ALLOC>
610
bool BasicDepthWalkFilter<ALLOC>::enterDepthLevel()
611
8
{
612
8
    const bool enter = (m_depth <= m_maxDepth);
613
8
    m_depth += 1;
614
8
    return enter;
615
8
}
616
617
template <typename ALLOC>
618
bool BasicDepthWalkFilter<ALLOC>::leaveDepthLevel()
619
8
{
620
8
    m_depth -= 1;
621
8
    return true;
622
8
}
623
624
namespace detail
625
{
626
627
template <typename ALLOC>
628
string<ALLOC> getCurrentPathImpl(const vector<string<ALLOC>, ALLOC>& currentPath, const ALLOC& allocator)
629
31
{
630
31
    string<ALLOC> currentPathStr(allocator);
631
80
    for (auto it = currentPath.begin(); it != currentPath.end(); 
++it49
)
632
49
    {
633
49
        if (!currentPathStr.empty())
634
18
        {
635
18
            currentPathStr += ".";
636
18
        }
637
49
        currentPathStr += *it;
638
49
    }
639
31
    return currentPathStr;
640
31
}
641
642
template <typename ALLOC>
643
void appendPathImpl(vector<string<ALLOC>, ALLOC>& currentPath, const BasicFieldInfo<ALLOC>& fieldInfo,
644
        size_t elementIndex, const ALLOC& allocator)
645
23
{
646
23
    if (elementIndex == WALKER_NOT_ELEMENT)
647
18
    {
648
18
        currentPath.emplace_back(fieldInfo.schemaName.data(), fieldInfo.schemaName.size(), allocator);
649
18
    }
650
5
    else
651
5
    {
652
5
        currentPath.back() =
653
5
                toString(fieldInfo.schemaName, allocator) + "[" + toString(elementIndex, allocator) + "]";
654
5
    }
655
23
}
656
657
template <typename ALLOC>
658
void popPathImpl(vector<string<ALLOC>, ALLOC>& currentPath, const BasicFieldInfo<ALLOC>& fieldInfo,
659
        size_t elementIndex, const ALLOC& allocator)
660
23
{
661
23
    if (elementIndex == WALKER_NOT_ELEMENT)
662
18
    {
663
18
        currentPath.pop_back();
664
18
    }
665
5
    else
666
5
    {
667
5
        currentPath.back() = toString(fieldInfo.schemaName, allocator);
668
5
    }
669
23
}
670
671
template <typename ALLOC>
672
class SubtreeRegexWalkFilter : public IBasicWalkFilter<ALLOC>
673
{
674
public:
675
    SubtreeRegexWalkFilter(const vector<string<ALLOC>, ALLOC>& currentPath, const std::regex& pathRegex,
676
            const ALLOC& allocator) :
677
            m_currentPath(currentPath),
678
            m_pathRegex(pathRegex),
679
            m_allocator(allocator)
680
11
    {}
681
682
    bool matches()
683
11
    {
684
11
        return m_matches;
685
11
    }
686
687
    bool beforeArray(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>& fieldInfo) override
688
4
    {
689
4
        m_currentPath.emplace_back(fieldInfo.schemaName.data(), fieldInfo.schemaName.size());
690
4
        m_matches = std::regex_match(getCurrentPath(), m_pathRegex);
691
692
        // terminate when the match is already found (note that array is never null here)
693
4
        return !m_matches;
694
4
    }
695
696
    bool afterArray(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&) override
697
4
    {
698
4
        m_currentPath.pop_back();
699
4
        return !m_matches; // terminate when the match is already found
700
4
    }
701
702
    bool beforeCompound(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>& fieldInfo,
703
            size_t elementIndex) override
704
2
    {
705
2
        appendPath(fieldInfo, elementIndex);
706
2
        m_matches = std::regex_match(getCurrentPath(), m_pathRegex);
707
708
        // terminate when the match is already found (note that compound is never null here)
709
2
        return !m_matches;
710
2
    }
711
712
    bool afterCompound(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>& fieldInfo,
713
            size_t elementIndex) override
714
2
    {
715
2
        popPath(fieldInfo, elementIndex);
716
2
        return !m_matches; // terminate when the match is already found
717
2
    }
718
719
    bool beforeValue(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>& fieldInfo,
720
            size_t elementIndex) override
721
9
    {
722
9
        appendPath(fieldInfo, elementIndex);
723
9
        m_matches = std::regex_match(getCurrentPath(), m_pathRegex);
724
725
9
        return !m_matches; // terminate when the match is already found
726
9
    }
727
728
    bool afterValue(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>& fieldInfo,
729
            size_t elementIndex) override
730
9
    {
731
9
        popPath(fieldInfo, elementIndex);
732
9
        return !m_matches; // terminate when the match is already found
733
9
    }
734
735
private:
736
    string<ALLOC> getCurrentPath() const
737
15
    {
738
15
        return detail::getCurrentPathImpl(m_currentPath, m_allocator);
739
15
    }
740
741
    void appendPath(const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
742
11
    {
743
11
        detail::appendPathImpl(m_currentPath, fieldInfo, elementIndex, m_allocator);
744
11
    }
745
746
    void popPath(const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
747
11
    {
748
11
        detail::popPathImpl(m_currentPath, fieldInfo, elementIndex, m_allocator);
749
11
    }
750
751
    vector<string<ALLOC>, ALLOC> m_currentPath;
752
    std::regex m_pathRegex;
753
    ALLOC m_allocator;
754
    bool m_matches = false;
755
};
756
757
} // namespace detail
758
759
template <typename ALLOC>
760
BasicRegexWalkFilter<ALLOC>::BasicRegexWalkFilter(const char* pathRegex, const ALLOC& allocator) :
761
        m_pathRegex(pathRegex),
762
        m_allocator(allocator)
763
8
{}
764
765
template <typename ALLOC>
766
bool BasicRegexWalkFilter<ALLOC>::beforeArray(
767
        const IBasicReflectableConstPtr<ALLOC>& array, const BasicFieldInfo<ALLOC>& fieldInfo)
768
4
{
769
4
    m_currentPath.emplace_back(fieldInfo.schemaName.data(), fieldInfo.schemaName.size(), m_allocator);
770
771
4
    if (std::regex_match(getCurrentPath(), m_pathRegex))
772
1
    {
773
1
        return true; // the array itself matches
774
1
    }
775
776
9
    
for (size_t i = 0; 3
i < array->size();
++i6
)
777
7
    {
778
7
        m_currentPath.back() =
779
7
                toString(fieldInfo.schemaName, m_allocator) + "[" + toString(i, m_allocator) + "]";
780
781
7
        if (matchSubtree(array->at(i), fieldInfo))
782
1
        {
783
1
            return true;
784
1
        }
785
7
    }
786
787
2
    m_currentPath.back() = toString(fieldInfo.schemaName, m_allocator);
788
789
2
    return false;
790
3
}
791
792
template <typename ALLOC>
793
bool BasicRegexWalkFilter<ALLOC>::afterArray(
794
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&)
795
4
{
796
4
    m_currentPath.pop_back();
797
4
    return true;
798
4
}
799
800
template <typename ALLOC>
801
bool BasicRegexWalkFilter<ALLOC>::beforeCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
802
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
803
5
{
804
5
    appendPath(fieldInfo, elementIndex);
805
5
    if (std::regex_match(getCurrentPath(), m_pathRegex))
806
1
    {
807
1
        return true; // the compound itself matches
808
1
    }
809
810
4
    return matchSubtree(compound, fieldInfo);
811
5
}
812
813
template <typename ALLOC>
814
bool BasicRegexWalkFilter<ALLOC>::afterCompound(
815
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
816
5
{
817
5
    popPath(fieldInfo, elementIndex);
818
5
    return true;
819
5
}
820
821
template <typename ALLOC>
822
bool BasicRegexWalkFilter<ALLOC>::beforeValue(const IBasicReflectableConstPtr<ALLOC>& value,
823
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
824
7
{
825
7
    appendPath(fieldInfo, elementIndex);
826
7
    return matchSubtree(value, fieldInfo);
827
7
}
828
829
template <typename ALLOC>
830
bool BasicRegexWalkFilter<ALLOC>::afterValue(
831
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
832
7
{
833
7
    popPath(fieldInfo, elementIndex);
834
7
    return true;
835
7
}
836
837
template <typename ALLOC>
838
void BasicRegexWalkFilter<ALLOC>::appendPath(const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
839
12
{
840
12
    detail::appendPathImpl(m_currentPath, fieldInfo, elementIndex, m_allocator);
841
12
}
842
843
template <typename ALLOC>
844
void BasicRegexWalkFilter<ALLOC>::popPath(const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
845
12
{
846
12
    detail::popPathImpl(m_currentPath, fieldInfo, elementIndex, m_allocator);
847
12
}
848
849
template <typename ALLOC>
850
string<ALLOC> BasicRegexWalkFilter<ALLOC>::getCurrentPath() const
851
16
{
852
16
    return detail::getCurrentPathImpl(m_currentPath, m_allocator);
853
16
}
854
855
template <typename ALLOC>
856
bool BasicRegexWalkFilter<ALLOC>::matchSubtree(
857
        const IBasicReflectableConstPtr<ALLOC>& value, const BasicFieldInfo<ALLOC>& fieldInfo) const
858
18
{
859
18
    if (value != nullptr && 
TypeInfoUtil::isCompound(fieldInfo.typeInfo.getSchemaType())13
)
860
11
    {
861
        // is a not null compound, try to find match within its subtree
862
11
        BasicDefaultWalkObserver<ALLOC> defaultObserver;
863
11
        detail::SubtreeRegexWalkFilter<ALLOC> subtreeFilter(m_currentPath, m_pathRegex, m_allocator);
864
11
        BasicWalker<ALLOC> walker(defaultObserver, subtreeFilter);
865
11
        walker.walk(value);
866
11
        return subtreeFilter.matches();
867
11
    }
868
7
    else
869
7
    {
870
        // try to match a simple value or null compound
871
7
        return std::regex_match(getCurrentPath(), m_pathRegex);
872
7
    }
873
18
}
874
875
template <typename ALLOC>
876
BasicArrayLengthWalkFilter<ALLOC>::BasicArrayLengthWalkFilter(size_t maxArrayLength) :
877
        m_maxArrayLength(maxArrayLength)
878
1
{}
879
880
template <typename ALLOC>
881
bool BasicArrayLengthWalkFilter<ALLOC>::beforeArray(
882
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&)
883
2
{
884
2
    return true;
885
2
}
886
887
template <typename ALLOC>
888
bool BasicArrayLengthWalkFilter<ALLOC>::afterArray(
889
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&)
890
2
{
891
2
    return true;
892
2
}
893
894
template <typename ALLOC>
895
bool BasicArrayLengthWalkFilter<ALLOC>::beforeCompound(
896
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t elementIndex)
897
2
{
898
2
    return filterArrayElement(elementIndex);
899
2
}
900
901
template <typename ALLOC>
902
bool BasicArrayLengthWalkFilter<ALLOC>::afterCompound(
903
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t elementIndex)
904
2
{
905
2
    return filterArrayElement(elementIndex);
906
2
}
907
908
template <typename ALLOC>
909
bool BasicArrayLengthWalkFilter<ALLOC>::beforeValue(
910
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t elementIndex)
911
3
{
912
3
    return filterArrayElement(elementIndex);
913
3
}
914
915
template <typename ALLOC>
916
bool BasicArrayLengthWalkFilter<ALLOC>::afterValue(
917
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t elementIndex)
918
3
{
919
3
    return filterArrayElement(elementIndex);
920
3
}
921
922
template <typename ALLOC>
923
bool BasicArrayLengthWalkFilter<ALLOC>::filterArrayElement(size_t elementIndex)
924
10
{
925
10
    return elementIndex == WALKER_NOT_ELEMENT ? 
true4
:
elementIndex < m_maxArrayLength6
;
926
10
}
927
928
template <typename ALLOC>
929
BasicAndWalkFilter<ALLOC>::BasicAndWalkFilter(const WalkFilters& walkFilters) :
930
        m_walkFilters(walkFilters)
931
4
{}
932
933
template <typename ALLOC>
934
bool BasicAndWalkFilter<ALLOC>::beforeArray(
935
        const IBasicReflectableConstPtr<ALLOC>& array, const BasicFieldInfo<ALLOC>& fieldInfo)
936
4
{
937
4
    return applyFilters(&IBasicWalkFilter<ALLOC>::beforeArray, array, fieldInfo);
938
4
}
939
940
template <typename ALLOC>
941
bool BasicAndWalkFilter<ALLOC>::afterArray(
942
        const IBasicReflectableConstPtr<ALLOC>& array, const BasicFieldInfo<ALLOC>& fieldInfo)
943
4
{
944
4
    return applyFilters(&IBasicWalkFilter<ALLOC>::afterArray, array, fieldInfo);
945
4
}
946
947
template <typename ALLOC>
948
bool BasicAndWalkFilter<ALLOC>::beforeCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
949
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
950
4
{
951
4
    return applyFilters(&IBasicWalkFilter<ALLOC>::beforeCompound, compound, fieldInfo, elementIndex);
952
4
}
953
954
template <typename ALLOC>
955
bool BasicAndWalkFilter<ALLOC>::afterCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
956
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
957
4
{
958
4
    return applyFilters(&IBasicWalkFilter<ALLOC>::afterCompound, compound, fieldInfo, elementIndex);
959
4
}
960
961
template <typename ALLOC>
962
bool BasicAndWalkFilter<ALLOC>::beforeValue(const IBasicReflectableConstPtr<ALLOC>& value,
963
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
964
4
{
965
4
    return applyFilters(&IBasicWalkFilter<ALLOC>::beforeValue, value, fieldInfo, elementIndex);
966
4
}
967
968
template <typename ALLOC>
969
bool BasicAndWalkFilter<ALLOC>::afterValue(const IBasicReflectableConstPtr<ALLOC>& value,
970
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
971
4
{
972
4
    return applyFilters(&IBasicWalkFilter<ALLOC>::afterValue, value, fieldInfo, elementIndex);
973
4
}
974
975
} // namespace zserio
976
977
#endif // ZSERIO_WALKER_H_INC