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 |