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