Coverage Report

Created: 2024-04-30 09:35

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
            result &= (walkFilter.*filterFunc)(args...);
426
24
        return result;
427
24
    }
428
429
    WalkFilters m_walkFilters;
430
};
431
432
/** Typedefs to walker related classes provided for convenience - using default std::allocator<uint8_t>. */
433
/** \{ */
434
using Walker = BasicWalker<>;
435
using DefaultWalkObserver = BasicDefaultWalkObserver<>;
436
using DefaultWalkFilter = BasicDefaultWalkFilter<>;
437
using DepthWalkFilter = BasicDepthWalkFilter<>;
438
using RegexWalkFilter = BasicRegexWalkFilter<>;
439
using ArrayLengthWalkFilter = BasicArrayLengthWalkFilter<>;
440
using AndWalkFilter = BasicAndWalkFilter<>;
441
/** \} */
442
443
template <typename ALLOC>
444
BasicWalker<ALLOC>::BasicWalker(IBasicWalkObserver<ALLOC>& walkObserver) :
445
        m_walkObserver(walkObserver),
446
        m_walkFilter(m_defaultWalkFilter)
447
2
{}
448
449
template <typename ALLOC>
450
BasicWalker<ALLOC>::BasicWalker(IBasicWalkObserver<ALLOC>& walkObserver, IBasicWalkFilter<ALLOC>& walkFilter) :
451
        m_walkObserver(walkObserver),
452
        m_walkFilter(walkFilter)
453
54
{}
454
455
template <typename ALLOC>
456
void BasicWalker<ALLOC>::walk(const IBasicReflectableConstPtr<ALLOC>& compound)
457
56
{
458
56
    if (!compound)
459
1
        throw CppRuntimeException("Walker: Root object cannot be NULL!");
460
461
55
    const IBasicTypeInfo<ALLOC>& typeInfo = compound->getTypeInfo();
462
55
    if (!TypeInfoUtil::isCompound(typeInfo.getSchemaType()))
463
1
    {
464
1
        throw CppRuntimeException("Walker: Root object '")
465
1
                << typeInfo.getSchemaName() << "' is not a compound type!";
466
1
    }
467
468
54
    m_walkObserver.beginRoot(compound);
469
54
    walkFields(compound, typeInfo);
470
54
    m_walkObserver.endRoot(compound);
471
54
}
472
473
template <typename ALLOC>
474
void BasicWalker<ALLOC>::walkFields(
475
        const IBasicReflectableConstPtr<ALLOC>& compound, const IBasicTypeInfo<ALLOC>& typeInfo)
476
71
{
477
71
    if (TypeInfoUtil::hasChoice(typeInfo.getSchemaType()))
478
21
    {
479
21
        StringView compoundChoice = compound->getChoice();
480
21
        if (!compoundChoice.empty())
481
18
        {
482
18
            Span<const BasicFieldInfo<ALLOC>> fields = typeInfo.getFields();
483
18
            auto fieldsIt = std::find_if(
484
38
                    fields.begin(), fields.end(), [compoundChoice](const BasicFieldInfo<ALLOC>& fieldInfo) {
485
38
                        return fieldInfo.schemaName == compoundChoice;
486
38
                    });
487
18
            if (fieldsIt != fields.end())
488
17
            {
489
17
                walkField(compound->getField(compoundChoice), *fieldsIt);
490
17
            }
491
18
        }
492
        // else uninitialized or empty branch
493
21
    }
494
50
    else
495
50
    {
496
50
        for (const BasicFieldInfo<ALLOC>& fieldInfo : typeInfo.getFields())
497
75
        {
498
75
            if (!walkField(compound->getField(fieldInfo.schemaName), fieldInfo))
499
3
                break;
500
75
        }
501
50
    }
502
71
}
503
504
template <typename ALLOC>
505
bool BasicWalker<ALLOC>::walkField(
506
        const IBasicReflectableConstPtr<ALLOC>& reflectable, const BasicFieldInfo<ALLOC>& fieldInfo)
507
92
{
508
92
    if (reflectable && 
fieldInfo.isArray87
)
509
10
    {
510
10
        if (m_walkFilter.beforeArray(reflectable, fieldInfo))
511
8
        {
512
8
            m_walkObserver.beginArray(reflectable, fieldInfo);
513
21
            for (size_t i = 0; i < reflectable->size(); 
++i13
)
514
14
            {
515
14
                if (!walkFieldValue(reflectable->at(i), fieldInfo, i))
516
1
                    break;
517
14
            }
518
8
            m_walkObserver.endArray(reflectable, fieldInfo);
519
8
        }
520
10
        return m_walkFilter.afterArray(reflectable, fieldInfo);
521
10
    }
522
82
    else
523
82
    {
524
82
        return walkFieldValue(reflectable, fieldInfo);
525
82
    }
526
92
}
527
528
template <typename ALLOC>
529
bool BasicWalker<ALLOC>::walkFieldValue(const IBasicReflectableConstPtr<ALLOC>& reflectable,
530
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
531
96
{
532
96
    const IBasicTypeInfo<ALLOC>& typeInfo = fieldInfo.typeInfo;
533
96
    if (reflectable && 
TypeInfoUtil::isCompound(typeInfo.getSchemaType())91
)
534
22
    {
535
22
        if (m_walkFilter.beforeCompound(reflectable, fieldInfo, elementIndex))
536
17
        {
537
17
            m_walkObserver.beginCompound(reflectable, fieldInfo, elementIndex);
538
17
            walkFields(reflectable, typeInfo);
539
17
            m_walkObserver.endCompound(reflectable, fieldInfo, elementIndex);
540
17
        }
541
22
        return m_walkFilter.afterCompound(reflectable, fieldInfo, elementIndex);
542
22
    }
543
74
    else
544
74
    {
545
74
        if (m_walkFilter.beforeValue(reflectable, fieldInfo, elementIndex))
546
68
            m_walkObserver.visitValue(reflectable, fieldInfo, elementIndex);
547
74
        return m_walkFilter.afterValue(reflectable, fieldInfo, elementIndex);
548
74
    }
549
96
}
550
551
template <typename ALLOC>
552
BasicDepthWalkFilter<ALLOC>::BasicDepthWalkFilter(size_t maxDepth) :
553
        m_maxDepth(maxDepth),
554
        m_depth(1)
555
7
{}
556
557
template <typename ALLOC>
558
bool BasicDepthWalkFilter<ALLOC>::beforeArray(
559
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&)
560
4
{
561
4
    return enterDepthLevel();
562
4
}
563
564
template <typename ALLOC>
565
bool BasicDepthWalkFilter<ALLOC>::afterArray(
566
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&)
567
4
{
568
4
    return leaveDepthLevel();
569
4
}
570
571
template <typename ALLOC>
572
bool BasicDepthWalkFilter<ALLOC>::beforeCompound(
573
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t)
574
4
{
575
4
    return enterDepthLevel();
576
4
}
577
578
template <typename ALLOC>
579
bool BasicDepthWalkFilter<ALLOC>::afterCompound(
580
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t)
581
4
{
582
4
    return leaveDepthLevel();
583
4
}
584
585
template <typename ALLOC>
586
bool BasicDepthWalkFilter<ALLOC>::beforeValue(
587
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t)
588
9
{
589
9
    return m_depth <= m_maxDepth;
590
9
}
591
592
template <typename ALLOC>
593
bool BasicDepthWalkFilter<ALLOC>::afterValue(
594
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t)
595
9
{
596
9
    return true;
597
9
}
598
599
template <typename ALLOC>
600
bool BasicDepthWalkFilter<ALLOC>::enterDepthLevel()
601
8
{
602
8
    const bool enter = (m_depth <= m_maxDepth);
603
8
    m_depth += 1;
604
8
    return enter;
605
8
}
606
607
template <typename ALLOC>
608
bool BasicDepthWalkFilter<ALLOC>::leaveDepthLevel()
609
8
{
610
8
    m_depth -= 1;
611
8
    return true;
612
8
}
613
614
namespace detail
615
{
616
617
template <typename ALLOC>
618
string<ALLOC> getCurrentPathImpl(const vector<string<ALLOC>, ALLOC>& currentPath, const ALLOC& allocator)
619
31
{
620
31
    string<ALLOC> currentPathStr(allocator);
621
80
    for (auto it = currentPath.begin(); it != currentPath.end(); 
++it49
)
622
49
    {
623
49
        if (!currentPathStr.empty())
624
18
            currentPathStr += ".";
625
49
        currentPathStr += *it;
626
49
    }
627
31
    return currentPathStr;
628
31
}
629
630
template <typename ALLOC>
631
void appendPathImpl(vector<string<ALLOC>, ALLOC>& currentPath, const BasicFieldInfo<ALLOC>& fieldInfo,
632
        size_t elementIndex, const ALLOC& allocator)
633
23
{
634
23
    if (elementIndex == WALKER_NOT_ELEMENT)
635
18
    {
636
18
        currentPath.emplace_back(fieldInfo.schemaName.data(), fieldInfo.schemaName.size(), allocator);
637
18
    }
638
5
    else
639
5
    {
640
5
        currentPath.back() =
641
5
                toString(fieldInfo.schemaName, allocator) + "[" + toString(elementIndex, allocator) + "]";
642
5
    }
643
23
}
644
645
template <typename ALLOC>
646
void popPathImpl(vector<string<ALLOC>, ALLOC>& currentPath, const BasicFieldInfo<ALLOC>& fieldInfo,
647
        size_t elementIndex, const ALLOC& allocator)
648
23
{
649
23
    if (elementIndex == WALKER_NOT_ELEMENT)
650
18
        currentPath.pop_back();
651
5
    else
652
5
        currentPath.back() = toString(fieldInfo.schemaName, allocator);
653
23
}
654
655
template <typename ALLOC>
656
class SubtreeRegexWalkFilter : public IBasicWalkFilter<ALLOC>
657
{
658
public:
659
    SubtreeRegexWalkFilter(const vector<string<ALLOC>, ALLOC>& currentPath, const std::regex& pathRegex,
660
            const ALLOC& allocator) :
661
            m_currentPath(currentPath),
662
            m_pathRegex(pathRegex),
663
            m_allocator(allocator)
664
11
    {}
665
666
    bool matches()
667
11
    {
668
11
        return m_matches;
669
11
    }
670
671
    bool beforeArray(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>& fieldInfo) override
672
4
    {
673
4
        m_currentPath.emplace_back(fieldInfo.schemaName.data(), fieldInfo.schemaName.size());
674
4
        m_matches = std::regex_match(getCurrentPath(), m_pathRegex);
675
676
        // terminate when the match is already found (note that array is never null here)
677
4
        return !m_matches;
678
4
    }
679
680
    bool afterArray(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&) override
681
4
    {
682
4
        m_currentPath.pop_back();
683
4
        return !m_matches; // terminate when the match is already found
684
4
    }
685
686
    bool beforeCompound(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>& fieldInfo,
687
            size_t elementIndex) override
688
2
    {
689
2
        appendPath(fieldInfo, elementIndex);
690
2
        m_matches = std::regex_match(getCurrentPath(), m_pathRegex);
691
692
        // terminate when the match is already found (note that compound is never null here)
693
2
        return !m_matches;
694
2
    }
695
696
    bool afterCompound(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>& fieldInfo,
697
            size_t elementIndex) override
698
2
    {
699
2
        popPath(fieldInfo, elementIndex);
700
2
        return !m_matches; // terminate when the match is already found
701
2
    }
702
703
    bool beforeValue(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>& fieldInfo,
704
            size_t elementIndex) override
705
9
    {
706
9
        appendPath(fieldInfo, elementIndex);
707
9
        m_matches = std::regex_match(getCurrentPath(), m_pathRegex);
708
709
9
        return !m_matches; // terminate when the match is already found
710
9
    }
711
712
    bool afterValue(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>& fieldInfo,
713
            size_t elementIndex) override
714
9
    {
715
9
        popPath(fieldInfo, elementIndex);
716
9
        return !m_matches; // terminate when the match is already found
717
9
    }
718
719
private:
720
    string<ALLOC> getCurrentPath() const
721
15
    {
722
15
        return detail::getCurrentPathImpl(m_currentPath, m_allocator);
723
15
    }
724
725
    void appendPath(const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
726
11
    {
727
11
        detail::appendPathImpl(m_currentPath, fieldInfo, elementIndex, m_allocator);
728
11
    }
729
730
    void popPath(const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
731
11
    {
732
11
        detail::popPathImpl(m_currentPath, fieldInfo, elementIndex, m_allocator);
733
11
    }
734
735
    vector<string<ALLOC>, ALLOC> m_currentPath;
736
    std::regex m_pathRegex;
737
    ALLOC m_allocator;
738
    bool m_matches = false;
739
};
740
741
} // namespace detail
742
743
template <typename ALLOC>
744
BasicRegexWalkFilter<ALLOC>::BasicRegexWalkFilter(const char* pathRegex, const ALLOC& allocator) :
745
        m_pathRegex(pathRegex),
746
        m_allocator(allocator)
747
8
{}
748
749
template <typename ALLOC>
750
bool BasicRegexWalkFilter<ALLOC>::beforeArray(
751
        const IBasicReflectableConstPtr<ALLOC>& array, const BasicFieldInfo<ALLOC>& fieldInfo)
752
4
{
753
4
    m_currentPath.emplace_back(fieldInfo.schemaName.data(), fieldInfo.schemaName.size(), m_allocator);
754
755
4
    if (std::regex_match(getCurrentPath(), m_pathRegex))
756
1
        return true; // the array itself matches
757
758
9
    
for (size_t i = 0; 3
i < array->size();
++i6
)
759
7
    {
760
7
        m_currentPath.back() =
761
7
                toString(fieldInfo.schemaName, m_allocator) + "[" + toString(i, m_allocator) + "]";
762
763
7
        if (matchSubtree(array->at(i), fieldInfo))
764
1
            return true;
765
7
    }
766
767
2
    m_currentPath.back() = toString(fieldInfo.schemaName, m_allocator);
768
769
2
    return false;
770
3
}
771
772
template <typename ALLOC>
773
bool BasicRegexWalkFilter<ALLOC>::afterArray(
774
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&)
775
4
{
776
4
    m_currentPath.pop_back();
777
4
    return true;
778
4
}
779
780
template <typename ALLOC>
781
bool BasicRegexWalkFilter<ALLOC>::beforeCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
782
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
783
5
{
784
5
    appendPath(fieldInfo, elementIndex);
785
5
    if (std::regex_match(getCurrentPath(), m_pathRegex))
786
1
        return true; // the compound itself matches
787
788
4
    return matchSubtree(compound, fieldInfo);
789
5
}
790
791
template <typename ALLOC>
792
bool BasicRegexWalkFilter<ALLOC>::afterCompound(
793
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
794
5
{
795
5
    popPath(fieldInfo, elementIndex);
796
5
    return true;
797
5
}
798
799
template <typename ALLOC>
800
bool BasicRegexWalkFilter<ALLOC>::beforeValue(const IBasicReflectableConstPtr<ALLOC>& value,
801
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
802
7
{
803
7
    appendPath(fieldInfo, elementIndex);
804
7
    return matchSubtree(value, fieldInfo);
805
7
}
806
807
template <typename ALLOC>
808
bool BasicRegexWalkFilter<ALLOC>::afterValue(
809
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
810
7
{
811
7
    popPath(fieldInfo, elementIndex);
812
7
    return true;
813
7
}
814
815
template <typename ALLOC>
816
void BasicRegexWalkFilter<ALLOC>::appendPath(const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
817
12
{
818
12
    detail::appendPathImpl(m_currentPath, fieldInfo, elementIndex, m_allocator);
819
12
}
820
821
template <typename ALLOC>
822
void BasicRegexWalkFilter<ALLOC>::popPath(const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
823
12
{
824
12
    detail::popPathImpl(m_currentPath, fieldInfo, elementIndex, m_allocator);
825
12
}
826
827
template <typename ALLOC>
828
string<ALLOC> BasicRegexWalkFilter<ALLOC>::getCurrentPath() const
829
16
{
830
16
    return detail::getCurrentPathImpl(m_currentPath, m_allocator);
831
16
}
832
833
template <typename ALLOC>
834
bool BasicRegexWalkFilter<ALLOC>::matchSubtree(
835
        const IBasicReflectableConstPtr<ALLOC>& value, const BasicFieldInfo<ALLOC>& fieldInfo) const
836
18
{
837
18
    if (value != nullptr && 
TypeInfoUtil::isCompound(fieldInfo.typeInfo.getSchemaType())13
)
838
11
    {
839
        // is a not null compound, try to find match within its subtree
840
11
        BasicDefaultWalkObserver<ALLOC> defaultObserver;
841
11
        detail::SubtreeRegexWalkFilter<ALLOC> subtreeFilter(m_currentPath, m_pathRegex, m_allocator);
842
11
        BasicWalker<ALLOC> walker(defaultObserver, subtreeFilter);
843
11
        walker.walk(value);
844
11
        return subtreeFilter.matches();
845
11
    }
846
7
    else
847
7
    {
848
        // try to match a simple value or null compound
849
7
        return std::regex_match(getCurrentPath(), m_pathRegex);
850
7
    }
851
18
}
852
853
template <typename ALLOC>
854
BasicArrayLengthWalkFilter<ALLOC>::BasicArrayLengthWalkFilter(size_t maxArrayLength) :
855
        m_maxArrayLength(maxArrayLength)
856
1
{}
857
858
template <typename ALLOC>
859
bool BasicArrayLengthWalkFilter<ALLOC>::beforeArray(
860
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&)
861
2
{
862
2
    return true;
863
2
}
864
865
template <typename ALLOC>
866
bool BasicArrayLengthWalkFilter<ALLOC>::afterArray(
867
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&)
868
2
{
869
2
    return true;
870
2
}
871
872
template <typename ALLOC>
873
bool BasicArrayLengthWalkFilter<ALLOC>::beforeCompound(
874
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t elementIndex)
875
2
{
876
2
    return filterArrayElement(elementIndex);
877
2
}
878
879
template <typename ALLOC>
880
bool BasicArrayLengthWalkFilter<ALLOC>::afterCompound(
881
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t elementIndex)
882
2
{
883
2
    return filterArrayElement(elementIndex);
884
2
}
885
886
template <typename ALLOC>
887
bool BasicArrayLengthWalkFilter<ALLOC>::beforeValue(
888
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t elementIndex)
889
3
{
890
3
    return filterArrayElement(elementIndex);
891
3
}
892
893
template <typename ALLOC>
894
bool BasicArrayLengthWalkFilter<ALLOC>::afterValue(
895
        const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&, size_t elementIndex)
896
3
{
897
3
    return filterArrayElement(elementIndex);
898
3
}
899
900
template <typename ALLOC>
901
bool BasicArrayLengthWalkFilter<ALLOC>::filterArrayElement(size_t elementIndex)
902
10
{
903
10
    return elementIndex == WALKER_NOT_ELEMENT ? 
true4
:
elementIndex < m_maxArrayLength6
;
904
10
}
905
906
template <typename ALLOC>
907
BasicAndWalkFilter<ALLOC>::BasicAndWalkFilter(const WalkFilters& walkFilters) :
908
        m_walkFilters(walkFilters)
909
4
{}
910
911
template <typename ALLOC>
912
bool BasicAndWalkFilter<ALLOC>::beforeArray(
913
        const IBasicReflectableConstPtr<ALLOC>& array, const BasicFieldInfo<ALLOC>& fieldInfo)
914
4
{
915
4
    return applyFilters(&IBasicWalkFilter<ALLOC>::beforeArray, array, fieldInfo);
916
4
}
917
918
template <typename ALLOC>
919
bool BasicAndWalkFilter<ALLOC>::afterArray(
920
        const IBasicReflectableConstPtr<ALLOC>& array, const BasicFieldInfo<ALLOC>& fieldInfo)
921
4
{
922
4
    return applyFilters(&IBasicWalkFilter<ALLOC>::afterArray, array, fieldInfo);
923
4
}
924
925
template <typename ALLOC>
926
bool BasicAndWalkFilter<ALLOC>::beforeCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
927
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
928
4
{
929
4
    return applyFilters(&IBasicWalkFilter<ALLOC>::beforeCompound, compound, fieldInfo, elementIndex);
930
4
}
931
932
template <typename ALLOC>
933
bool BasicAndWalkFilter<ALLOC>::afterCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
934
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
935
4
{
936
4
    return applyFilters(&IBasicWalkFilter<ALLOC>::afterCompound, compound, fieldInfo, elementIndex);
937
4
}
938
939
template <typename ALLOC>
940
bool BasicAndWalkFilter<ALLOC>::beforeValue(const IBasicReflectableConstPtr<ALLOC>& value,
941
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
942
4
{
943
4
    return applyFilters(&IBasicWalkFilter<ALLOC>::beforeValue, value, fieldInfo, elementIndex);
944
4
}
945
946
template <typename ALLOC>
947
bool BasicAndWalkFilter<ALLOC>::afterValue(const IBasicReflectableConstPtr<ALLOC>& value,
948
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
949
4
{
950
4
    return applyFilters(&IBasicWalkFilter<ALLOC>::afterValue, value, fieldInfo, elementIndex);
951
4
}
952
953
} // namespace zserio
954
955
#endif // ZSERIO_WALKER_H_INC