Coverage Report

Created: 2025-07-31 16:33

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