Coverage Report

Created: 2023-12-13 14:58

src/zserio/Walker.h
Line
Count
Source
1
#ifndef ZSERIO_WALKER_H_INC
2
#define ZSERIO_WALKER_H_INC
3
4
#include <functional>
5
#include <regex>
6
#include <algorithm>
7
8
#include "zserio/IReflectable.h"
9
#include "zserio/ITypeInfo.h"
10
#include "zserio/WalkerConst.h"
11
#include "zserio/IWalkObserver.h"
12
#include "zserio/IWalkFilter.h"
13
#include "zserio/TypeInfoUtil.h"
14
#include "zserio/StringConvertUtil.h"
15
#include "zserio/String.h"
16
#include "zserio/Vector.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
12
    void beginRoot(const IBasicReflectableConstPtr<ALLOC>&) override {}
114
12
    void endRoot(const IBasicReflectableConstPtr<ALLOC>&) override {}
115
116
    void beginArray(const IBasicReflectableConstPtr<ALLOC>&,
117
3
            const BasicFieldInfo<ALLOC>&) override {}
118
    void endArray(const IBasicReflectableConstPtr<ALLOC>&,
119
3
            const BasicFieldInfo<ALLOC>&) override {}
120
121
    void beginCompound(const IBasicReflectableConstPtr<ALLOC>&,
122
3
            const BasicFieldInfo<ALLOC>&, size_t) override {}
123
    void endCompound(const IBasicReflectableConstPtr<ALLOC>&,
124
3
            const BasicFieldInfo<ALLOC>&, size_t) override {}
125
126
    void visitValue(const IBasicReflectableConstPtr<ALLOC>&,
127
9
            const BasicFieldInfo<ALLOC>&, size_t) override {}
128
};
129
130
/**
131
 * Default walk filter which filters nothing.
132
 */
133
template <typename ALLOC = std::allocator<uint8_t>>
134
class BasicDefaultWalkFilter : public IBasicWalkFilter<ALLOC>
135
{
136
public:
137
    /**
138
     * Method generated by default.
139
     * \{
140
     */
141
92
    BasicDefaultWalkFilter() = default;
142
92
    ~BasicDefaultWalkFilter() override = default;
143
    /**
144
     * \}
145
     */
146
147
    /**
148
     * Copying and moving is disallowed!
149
     * \{
150
     */
151
    BasicDefaultWalkFilter(const BasicDefaultWalkFilter& other) = delete;
152
    BasicDefaultWalkFilter& operator=(const BasicDefaultWalkFilter& other) = delete;
153
154
    BasicDefaultWalkFilter(BasicDefaultWalkFilter&& other) = delete;
155
    BasicDefaultWalkFilter& operator=(BasicDefaultWalkFilter&& other) = delete;
156
    /**
157
     * \}
158
     */
159
160
    bool beforeArray(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&) override
161
5
    {
162
5
        return true;
163
5
    }
164
165
    bool afterArray(const IBasicReflectableConstPtr<ALLOC>&, const BasicFieldInfo<ALLOC>&) override
166
5
    {
167
5
        return true;
168
5
    }
169
170
    bool beforeCompound(const IBasicReflectableConstPtr<ALLOC>&,
171
            const BasicFieldInfo<ALLOC>&, size_t) override
172
12
    {
173
12
        return true;
174
12
    }
175
176
    bool afterCompound(const IBasicReflectableConstPtr<ALLOC>&,
177
            const BasicFieldInfo<ALLOC>&, size_t) override
178
12
    {
179
12
        return true;
180
12
    }
181
182
    bool beforeValue(const IBasicReflectableConstPtr<ALLOC>&,
183
            const BasicFieldInfo<ALLOC>&, size_t) override
184
48
    {
185
48
        return true;
186
48
    }
187
188
    bool afterValue(const IBasicReflectableConstPtr<ALLOC>&,
189
            const BasicFieldInfo<ALLOC>&, size_t) override
190
48
    {
191
48
        return true;
192
48
    }
193
};
194
195
/**
196
 * Walk filter which allows to walk only to the given maximum depth.
197
 */
198
template <typename ALLOC = std::allocator<uint8_t>>
199
class BasicDepthWalkFilter : public IBasicWalkFilter<ALLOC>
200
{
201
public:
202
    /**
203
     * Constructor.
204
     *
205
     * \param maxDepth Maximum depth to walk to.
206
     */
207
    explicit BasicDepthWalkFilter(size_t maxDepth);
208
209
    /**
210
     * Method generated by default.
211
     */
212
7
    ~BasicDepthWalkFilter() override = default;
213
214
    /**
215
     * Copying is disallowed!
216
     * \{
217
     */
218
    BasicDepthWalkFilter(const BasicDepthWalkFilter& other) = delete;
219
    BasicDepthWalkFilter& operator=(const BasicDepthWalkFilter& other) = delete;
220
221
    BasicDepthWalkFilter(BasicDepthWalkFilter&& other) = delete;
222
    BasicDepthWalkFilter& operator=(BasicDepthWalkFilter&& other) = delete;
223
    /**
224
     * \}
225
     */
226
227
    bool beforeArray(const IBasicReflectableConstPtr<ALLOC>& array,
228
            const BasicFieldInfo<ALLOC>& fieldInfo) override;
229
    bool afterArray(const IBasicReflectableConstPtr<ALLOC>& array,
230
            const BasicFieldInfo<ALLOC>& fieldInfo) override;
231
232
    bool beforeCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
233
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
234
    bool afterCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
235
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
236
237
    bool beforeValue(const IBasicReflectableConstPtr<ALLOC>& value,
238
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
239
    bool afterValue(const IBasicReflectableConstPtr<ALLOC>& value,
240
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
241
242
private:
243
    bool enterDepthLevel();
244
    bool leaveDepthLevel();
245
246
    size_t m_maxDepth;
247
    size_t m_depth;
248
};
249
250
/**
251
 * Walk filter which allows to walk only paths matching the given regex.
252
 *
253
 * The path is constructed from field names within the root object, thus the root object itself
254
 * is not part of the path.
255
 *
256
 * Array elements have the index appended to the path so that e.g. "compound.arrayField[0]" will match
257
 * only the first element in the array "arrayField".
258
 */
259
template <typename ALLOC = std::allocator<uint8_t>>
260
class BasicRegexWalkFilter : public IBasicWalkFilter<ALLOC>
261
{
262
public:
263
    /**
264
     * Constructor.
265
     *
266
     * \param pathRegex Path regex to use for filtering.
267
     */
268
    explicit BasicRegexWalkFilter(const char* pathRegex, const ALLOC& allocator = ALLOC());
269
270
    /**
271
     * Method generated by default.
272
     */
273
8
    ~BasicRegexWalkFilter() override = default;
274
275
    /**
276
     * Copying is disallowed!
277
     * \{
278
     */
279
    BasicRegexWalkFilter(const BasicRegexWalkFilter& other) = delete;
280
    BasicRegexWalkFilter& operator=(const BasicRegexWalkFilter& other) = delete;
281
282
    BasicRegexWalkFilter(BasicRegexWalkFilter&& other) = delete;
283
    BasicRegexWalkFilter& operator=(BasicRegexWalkFilter&& other) = delete;
284
    /**
285
     * \}
286
     */
287
288
    bool beforeArray(const IBasicReflectableConstPtr<ALLOC>& array,
289
            const BasicFieldInfo<ALLOC>& fieldInfo) override;
290
    bool afterArray(const IBasicReflectableConstPtr<ALLOC>& array,
291
            const BasicFieldInfo<ALLOC>& fieldInfo) override;
292
293
    bool beforeCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
294
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
295
    bool afterCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
296
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
297
298
    bool beforeValue(const IBasicReflectableConstPtr<ALLOC>& value,
299
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
300
    bool afterValue(const IBasicReflectableConstPtr<ALLOC>& value,
301
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
302
303
private:
304
    void appendPath(const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex);
305
    void popPath(const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex);
306
    string<ALLOC> getCurrentPath() const;
307
    bool matchSubtree(const IBasicReflectableConstPtr<ALLOC>& value,
308
            const BasicFieldInfo<ALLOC>& fieldInfo) const;
309
310
    vector<string<ALLOC>, ALLOC> m_currentPath;
311
    std::regex m_pathRegex;
312
    ALLOC m_allocator; // TODO[Mi-L@]: Check how std::regex_match allocates when results are omitted!
313
};
314
315
/**
316
 * Walk filter which allows to walk only to the given maximum array length.
317
 */
318
template <typename ALLOC = std::allocator<uint8_t>>
319
class BasicArrayLengthWalkFilter : public IBasicWalkFilter<ALLOC>
320
{
321
public:
322
    /**
323
     * Constructor.
324
     *
325
     * \param maxArrayLength Maximum array length to walk to.
326
     */
327
    explicit BasicArrayLengthWalkFilter(size_t maxArrayLength);
328
329
    /**
330
     * Method generated by default.
331
     */
332
1
    ~BasicArrayLengthWalkFilter() override = default;
333
334
    /**
335
     * Copying and moving is disallowed!
336
     * \{
337
     */
338
    BasicArrayLengthWalkFilter(const BasicArrayLengthWalkFilter& other) = delete;
339
    BasicArrayLengthWalkFilter& operator=(const BasicArrayLengthWalkFilter& other) = delete;
340
341
    BasicArrayLengthWalkFilter(BasicArrayLengthWalkFilter&& other) = delete;
342
    BasicArrayLengthWalkFilter& operator=(BasicArrayLengthWalkFilter&& other) = delete;
343
    /**
344
     * \}
345
     */
346
347
    bool beforeArray(const IBasicReflectableConstPtr<ALLOC>& array,
348
            const BasicFieldInfo<ALLOC>& fieldInfo) override;
349
    bool afterArray(const IBasicReflectableConstPtr<ALLOC>& array,
350
            const BasicFieldInfo<ALLOC>& fieldInfo) override;
351
352
    bool beforeCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
353
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
354
    bool afterCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
355
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
356
357
    bool beforeValue(const IBasicReflectableConstPtr<ALLOC>& value,
358
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
359
    bool afterValue(const IBasicReflectableConstPtr<ALLOC>& value,
360
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
361
362
private:
363
    bool filterArrayElement(size_t elementIndex);
364
365
    size_t m_maxArrayLength;
366
};
367
368
/**
369
 * Walk filter which implements composition of particular filters.
370
 *
371
 * The filters are called sequentially and logical and is applied on theirs results.
372
 * Note that all filters are always called.
373
 */
374
template <typename ALLOC = std::allocator<uint8_t>>
375
class BasicAndWalkFilter : public IBasicWalkFilter<ALLOC>
376
{
377
public:
378
    using WalkFilterRef = std::reference_wrapper<IBasicWalkFilter<ALLOC>>;
379
    using WalkFilters = vector<WalkFilterRef, ALLOC>;
380
381
    /**
382
     * Constructor.
383
     *
384
     * \param walkFilters List of filters to use in composition.
385
     */
386
    explicit BasicAndWalkFilter(const WalkFilters& walkFilters);
387
388
    /**
389
     * Method generated by default.
390
     */
391
4
    ~BasicAndWalkFilter() override = default;
392
393
    /**
394
     * Copying and moving is disallowed!
395
     * \{
396
     */
397
    BasicAndWalkFilter(const BasicAndWalkFilter& other) = delete;
398
    BasicAndWalkFilter& operator=(const BasicAndWalkFilter& other) = delete;
399
400
    BasicAndWalkFilter(BasicAndWalkFilter&& other) = delete;
401
    BasicAndWalkFilter& operator=(BasicAndWalkFilter&& other) = delete;
402
    /**
403
     * \}
404
     */
405
406
    bool beforeArray(const IBasicReflectableConstPtr<ALLOC>& array,
407
            const BasicFieldInfo<ALLOC>& fieldInfo) override;
408
    bool afterArray(const IBasicReflectableConstPtr<ALLOC>& array,
409
            const BasicFieldInfo<ALLOC>& fieldInfo) override;
410
411
    bool beforeCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
412
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
413
    bool afterCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
414
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
415
416
    bool beforeValue(const IBasicReflectableConstPtr<ALLOC>& value,
417
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
418
    bool afterValue(const IBasicReflectableConstPtr<ALLOC>& value,
419
            const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex) override;
420
421
private:
422
    template <typename FILTER_FUNC, typename ...ARGS>
423
    bool applyFilters(FILTER_FUNC filterFunc, ARGS... args)
424
24
    {
425
24
        bool result = true;
426
24
        for (IBasicWalkFilter<ALLOC>& walkFilter : m_walkFilters)
427
36
            result &= (walkFilter.*filterFunc)(args...);
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), m_walkFilter(m_defaultWalkFilter)
448
2
{}
449
450
template <typename ALLOC>
451
BasicWalker<ALLOC>::BasicWalker(IBasicWalkObserver<ALLOC>& walkObserver, IBasicWalkFilter<ALLOC>& walkFilter) :
452
        m_walkObserver(walkObserver), 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 '") << typeInfo.getSchemaName() <<
465
1
                "' 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(const IBasicReflectableConstPtr<ALLOC>& compound,
475
        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(fields.begin(), fields.end(),
484
38
                    [compoundChoice](const BasicFieldInfo<ALLOC>& fieldInfo) {
485
38
                            return fieldInfo.schemaName == compoundChoice; });
486
18
            if (fieldsIt != fields.end())
487
17
            {
488
17
                walkField(compound->getField(compoundChoice), *fieldsIt);
489
17
            }
490
18
        }
491
        // else uninitialized or empty branch
492
21
    }
493
50
    else
494
50
    {
495
50
        for (const BasicFieldInfo<ALLOC>& fieldInfo : typeInfo.getFields())
496
75
        {
497
75
            if (!walkField(compound->getField(fieldInfo.schemaName), fieldInfo))
498
3
                break;
499
75
        }
500
50
    }
501
71
}
502
503
template <typename ALLOC>
504
bool BasicWalker<ALLOC>::walkField(
505
        const IBasicReflectableConstPtr<ALLOC>& reflectable, const BasicFieldInfo<ALLOC>& fieldInfo)
506
92
{
507
92
    if (reflectable && 
fieldInfo.isArray87
)
508
10
    {
509
10
        if (m_walkFilter.beforeArray(reflectable, fieldInfo))
510
8
        {
511
8
            m_walkObserver.beginArray(reflectable, fieldInfo);
512
21
            for (size_t i = 0; i < reflectable->size(); 
++i13
)
513
14
            {
514
14
                if (!walkFieldValue(reflectable->at(i), fieldInfo, i))
515
1
                    break;
516
14
            }
517
8
            m_walkObserver.endArray(reflectable, fieldInfo);
518
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), m_depth(1)
554
7
{}
555
556
template <typename ALLOC>
557
bool BasicDepthWalkFilter<ALLOC>::beforeArray(const IBasicReflectableConstPtr<ALLOC>&,
558
        const BasicFieldInfo<ALLOC>&)
559
4
{
560
4
    return enterDepthLevel();
561
4
}
562
563
template <typename ALLOC>
564
bool BasicDepthWalkFilter<ALLOC>::afterArray(const IBasicReflectableConstPtr<ALLOC>&,
565
        const BasicFieldInfo<ALLOC>&)
566
4
{
567
4
    return leaveDepthLevel();
568
4
}
569
570
template <typename ALLOC>
571
bool BasicDepthWalkFilter<ALLOC>::beforeCompound(const IBasicReflectableConstPtr<ALLOC>&,
572
        const BasicFieldInfo<ALLOC>&, size_t)
573
4
{
574
4
    return enterDepthLevel();
575
4
}
576
577
template <typename ALLOC>
578
bool BasicDepthWalkFilter<ALLOC>::afterCompound(const IBasicReflectableConstPtr<ALLOC>&,
579
        const BasicFieldInfo<ALLOC>&, size_t)
580
4
{
581
4
    return leaveDepthLevel();
582
4
}
583
584
template <typename ALLOC>
585
bool BasicDepthWalkFilter<ALLOC>::beforeValue(const IBasicReflectableConstPtr<ALLOC>&,
586
        const BasicFieldInfo<ALLOC>&, size_t)
587
9
{
588
9
    return m_depth <= m_maxDepth;
589
9
}
590
591
template <typename ALLOC>
592
bool BasicDepthWalkFilter<ALLOC>::afterValue(const IBasicReflectableConstPtr<ALLOC>&,
593
        const BasicFieldInfo<ALLOC>&, size_t)
594
9
{
595
9
    return true;
596
9
}
597
598
template <typename ALLOC>
599
bool BasicDepthWalkFilter<ALLOC>::enterDepthLevel()
600
8
{
601
8
    const bool enter = (m_depth <= m_maxDepth);
602
8
    m_depth += 1;
603
8
    return enter;
604
8
}
605
606
template <typename ALLOC>
607
bool BasicDepthWalkFilter<ALLOC>::leaveDepthLevel()
608
8
{
609
8
    m_depth -= 1;
610
8
    return true;
611
8
}
612
613
namespace detail
614
{
615
616
template <typename ALLOC>
617
string<ALLOC> getCurrentPathImpl(
618
        const vector<string<ALLOC>, ALLOC>& currentPath,
619
        const ALLOC& allocator)
620
31
{
621
31
    string<ALLOC> currentPathStr(allocator);
622
80
    for (auto it = currentPath.begin(); it != currentPath.end(); 
++it49
)
623
49
    {
624
49
        if (!currentPathStr.empty())
625
18
            currentPathStr += ".";
626
49
        currentPathStr += *it;
627
49
    }
628
31
    return currentPathStr;
629
31
}
630
631
template <typename ALLOC>
632
void appendPathImpl(vector<string<ALLOC>, ALLOC>& currentPath,
633
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex, const ALLOC& allocator)
634
23
{
635
23
    if (elementIndex == WALKER_NOT_ELEMENT)
636
18
    {
637
18
        currentPath.emplace_back(fieldInfo.schemaName.data(), fieldInfo.schemaName.size(), allocator);
638
18
    }
639
5
    else
640
5
    {
641
5
        currentPath.back() = toString(fieldInfo.schemaName, allocator) +
642
5
                "[" + toString(elementIndex, allocator) + "]";
643
5
    }
644
23
}
645
646
template <typename ALLOC>
647
void popPathImpl(vector<string<ALLOC>, ALLOC>& currentPath,
648
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex, const ALLOC& allocator)
649
23
{
650
23
    if (elementIndex == WALKER_NOT_ELEMENT)
651
18
        currentPath.pop_back();
652
5
    else
653
5
        currentPath.back() = toString(fieldInfo.schemaName, allocator);
654
23
}
655
656
template <typename ALLOC>
657
class SubtreeRegexWalkFilter : public IBasicWalkFilter<ALLOC>
658
{
659
public:
660
    SubtreeRegexWalkFilter(const vector<string<ALLOC>, ALLOC>& currentPath,
661
            const std::regex& pathRegex, const ALLOC& allocator) :
662
            m_currentPath(currentPath), m_pathRegex(pathRegex), m_allocator(allocator)
663
11
    {}
664
665
    bool matches()
666
11
    {
667
11
        return m_matches;
668
11
    }
669
670
    bool beforeArray(const IBasicReflectableConstPtr<ALLOC>&,
671
            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>&,
687
            const BasicFieldInfo<ALLOC>& fieldInfo, 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), m_allocator(allocator)
746
8
{}
747
748
template <typename ALLOC>
749
bool BasicRegexWalkFilter<ALLOC>::beforeArray(const IBasicReflectableConstPtr<ALLOC>& array,
750
        const BasicFieldInfo<ALLOC>& fieldInfo)
751
4
{
752
4
    m_currentPath.emplace_back(fieldInfo.schemaName.data(), fieldInfo.schemaName.size(), m_allocator);
753
754
4
    if (std::regex_match(getCurrentPath(), m_pathRegex))
755
1
        return true; // the array itself matches
756
757
9
    
for (size_t i = 0; 3
i < array->size();
++i6
)
758
7
    {
759
7
        m_currentPath.back() = toString(fieldInfo.schemaName, m_allocator) +
760
7
                "[" + toString(i, m_allocator) + "]";
761
762
7
        if (matchSubtree(array->at(i), fieldInfo))
763
1
            return true;
764
7
    }
765
766
2
    m_currentPath.back() = toString(fieldInfo.schemaName, m_allocator);
767
768
2
    return false;
769
3
}
770
771
template <typename ALLOC>
772
bool BasicRegexWalkFilter<ALLOC>::afterArray(const IBasicReflectableConstPtr<ALLOC>&,
773
        const BasicFieldInfo<ALLOC>&)
774
4
{
775
4
    m_currentPath.pop_back();
776
4
    return true;
777
4
}
778
779
template <typename ALLOC>
780
bool BasicRegexWalkFilter<ALLOC>::beforeCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
781
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
782
5
{
783
5
    appendPath(fieldInfo, elementIndex);
784
5
    if (std::regex_match(getCurrentPath(), m_pathRegex))
785
1
        return true; // the compound itself matches
786
787
4
    return matchSubtree(compound, fieldInfo);
788
5
}
789
790
template <typename ALLOC>
791
bool BasicRegexWalkFilter<ALLOC>::afterCompound(const IBasicReflectableConstPtr<ALLOC>&,
792
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
793
5
{
794
5
    popPath(fieldInfo, elementIndex);
795
5
    return true;
796
5
}
797
798
template <typename ALLOC>
799
bool BasicRegexWalkFilter<ALLOC>::beforeValue(const IBasicReflectableConstPtr<ALLOC>& value,
800
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
801
7
{
802
7
    appendPath(fieldInfo, elementIndex);
803
7
    return matchSubtree(value, fieldInfo);
804
7
}
805
806
template <typename ALLOC>
807
bool BasicRegexWalkFilter<ALLOC>::afterValue(const IBasicReflectableConstPtr<ALLOC>&,
808
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
809
7
{
810
7
    popPath(fieldInfo, elementIndex);
811
7
    return true;
812
7
}
813
814
template <typename ALLOC>
815
void BasicRegexWalkFilter<ALLOC>::appendPath(const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
816
12
{
817
12
    detail::appendPathImpl(m_currentPath, fieldInfo, elementIndex, m_allocator);
818
12
}
819
820
template <typename ALLOC>
821
void BasicRegexWalkFilter<ALLOC>::popPath(const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
822
12
{
823
12
    detail::popPathImpl(m_currentPath, fieldInfo, elementIndex, m_allocator);
824
12
}
825
826
template <typename ALLOC>
827
string<ALLOC> BasicRegexWalkFilter<ALLOC>::getCurrentPath() const
828
16
{
829
16
    return detail::getCurrentPathImpl(m_currentPath, m_allocator);
830
16
}
831
832
template <typename ALLOC>
833
bool BasicRegexWalkFilter<ALLOC>::matchSubtree(const IBasicReflectableConstPtr<ALLOC>& value,
834
        const BasicFieldInfo<ALLOC>& fieldInfo) const
835
18
{
836
18
    if (value != nullptr && 
TypeInfoUtil::isCompound(fieldInfo.typeInfo.getSchemaType())13
)
837
11
    {
838
        // is a not null compound, try to find match within its subtree
839
11
        BasicDefaultWalkObserver<ALLOC> defaultObserver;
840
11
        detail::SubtreeRegexWalkFilter<ALLOC> subtreeFilter(m_currentPath, m_pathRegex, m_allocator);
841
11
        BasicWalker<ALLOC> walker(defaultObserver, subtreeFilter);
842
11
        walker.walk(value);
843
11
        return subtreeFilter.matches();
844
11
    }
845
7
    else
846
7
    {
847
        // try to match a simple value or null compound
848
7
        return std::regex_match(getCurrentPath(), m_pathRegex);
849
7
    }
850
18
}
851
852
template <typename ALLOC>
853
BasicArrayLengthWalkFilter<ALLOC>::BasicArrayLengthWalkFilter(size_t maxArrayLength) :
854
        m_maxArrayLength(maxArrayLength)
855
1
{}
856
857
template <typename ALLOC>
858
bool BasicArrayLengthWalkFilter<ALLOC>::beforeArray(const IBasicReflectableConstPtr<ALLOC>&,
859
        const BasicFieldInfo<ALLOC>&)
860
2
{
861
2
    return true;
862
2
}
863
864
template <typename ALLOC>
865
bool BasicArrayLengthWalkFilter<ALLOC>::afterArray(const IBasicReflectableConstPtr<ALLOC>&,
866
        const BasicFieldInfo<ALLOC>&)
867
2
{
868
2
    return true;
869
2
}
870
871
template <typename ALLOC>
872
bool BasicArrayLengthWalkFilter<ALLOC>::beforeCompound(const IBasicReflectableConstPtr<ALLOC>&,
873
        const BasicFieldInfo<ALLOC>&, size_t elementIndex)
874
2
{
875
2
    return filterArrayElement(elementIndex);
876
2
}
877
878
template <typename ALLOC>
879
bool BasicArrayLengthWalkFilter<ALLOC>::afterCompound(const IBasicReflectableConstPtr<ALLOC>&,
880
        const BasicFieldInfo<ALLOC>&, size_t elementIndex)
881
2
{
882
2
    return filterArrayElement(elementIndex);
883
2
}
884
885
template <typename ALLOC>
886
bool BasicArrayLengthWalkFilter<ALLOC>::beforeValue(const IBasicReflectableConstPtr<ALLOC>&,
887
        const BasicFieldInfo<ALLOC>&, size_t elementIndex)
888
3
{
889
3
    return filterArrayElement(elementIndex);
890
3
}
891
892
template <typename ALLOC>
893
bool BasicArrayLengthWalkFilter<ALLOC>::afterValue(const IBasicReflectableConstPtr<ALLOC>&,
894
        const BasicFieldInfo<ALLOC>&, size_t elementIndex)
895
3
{
896
3
    return filterArrayElement(elementIndex);
897
3
}
898
899
template <typename ALLOC>
900
bool BasicArrayLengthWalkFilter<ALLOC>::filterArrayElement(size_t elementIndex)
901
10
{
902
10
    return elementIndex == WALKER_NOT_ELEMENT ? 
true4
:
elementIndex < m_maxArrayLength6
;
903
10
}
904
905
template <typename ALLOC>
906
BasicAndWalkFilter<ALLOC>::BasicAndWalkFilter(const WalkFilters& walkFilters) :
907
        m_walkFilters(walkFilters)
908
4
{}
909
910
template <typename ALLOC>
911
bool BasicAndWalkFilter<ALLOC>::beforeArray(const IBasicReflectableConstPtr<ALLOC>& array,
912
        const BasicFieldInfo<ALLOC>& fieldInfo)
913
4
{
914
4
    return applyFilters(&IBasicWalkFilter<ALLOC>::beforeArray, array, fieldInfo);
915
4
}
916
917
template <typename ALLOC>
918
bool BasicAndWalkFilter<ALLOC>::afterArray(const IBasicReflectableConstPtr<ALLOC>& array,
919
        const BasicFieldInfo<ALLOC>& fieldInfo)
920
4
{
921
4
    return applyFilters(&IBasicWalkFilter<ALLOC>::afterArray, array, fieldInfo);
922
4
}
923
924
template <typename ALLOC>
925
bool BasicAndWalkFilter<ALLOC>::beforeCompound(const IBasicReflectableConstPtr<ALLOC>& compound,
926
        const BasicFieldInfo<ALLOC>& fieldInfo,
927
        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,
935
        size_t elementIndex)
936
4
{
937
4
    return applyFilters(&IBasicWalkFilter<ALLOC>::afterCompound, compound, fieldInfo, elementIndex);
938
4
}
939
940
template <typename ALLOC>
941
bool BasicAndWalkFilter<ALLOC>::beforeValue(const IBasicReflectableConstPtr<ALLOC>& value,
942
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
943
4
{
944
4
    return applyFilters(&IBasicWalkFilter<ALLOC>::beforeValue, value, fieldInfo, elementIndex);
945
4
}
946
947
template <typename ALLOC>
948
bool BasicAndWalkFilter<ALLOC>::afterValue(const IBasicReflectableConstPtr<ALLOC>& value,
949
        const BasicFieldInfo<ALLOC>& fieldInfo, size_t elementIndex)
950
4
{
951
4
    return applyFilters(&IBasicWalkFilter<ALLOC>::afterValue, value, fieldInfo, elementIndex);
952
4
}
953
954
} // namespace zserio
955
956
#endif // ZSERIO_WALKER_H_INC