ALib C++ Library
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
stringtreeiterator.inl
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header-file is part of module \alib_containers of the \aliblong.
4///
5/// \emoji :copyright: 2013-2025 A-Worx GmbH, Germany.
6/// Published under \ref mainpage_license "Boost Software License".
7//==================================================================================================
8ALIB_EXPORT namespace alib { namespace containers {
9
10/// This class is to be used with instances of class \alib{containers;StringTree} and allows
11/// iterating recursively through its nodes.<br>
12/// The type does <b>not</b> apply to the concept of \c std::iterator_traits.
13/// The rationale for this is the fact that mechanics for sorting the child nodes are
14/// provided, which requires the allocation of more resources than usual container iterators do.
15/// Therefore, objects of this type are not supposed to be temporary and
16/// created "on the fly", e.g., in C++ range-based loops.
17/// Instead, instances should rather be created once and then re-used with later iterations.
18///
19/// The sorting of child nodes is optional and can be changed before each recursion.
20/// Whenever a recursion in iteration occurs, the most recent settings of sorting are respected
21/// for the children of the node that is processed with that recursion.<br>
22/// A built-in comparison function which works on node names (path names) allows choosing
23/// ascending and descending order and to ignore or be sensitive about the letter case.
24/// Besides this, custom comparison functions that take a combination of arbitrary node
25/// attributes, including a node's value of template type \p{T} can be established.
26/// See method #SetSorting for details on this topic.
27///
28/// Method #Initialize starts a new 'use' of this class. Besides the start node, a boolean
29/// parameter allows deciding whether the start node should be included in the iteration or
30/// not. This is useful in cases where the start-node could optionally be a leaf-node.
31/// For example, when processing files with class \alib{files;FTree}, an application might
32/// allow accepting a single file or a folder that contains files. In this case, the
33/// iteration should include the start node, as otherwise, in case a file was given, that
34/// leaf-node would be skipped.
35///
36/// The maximum depth of recursion may be limited with optional parameter \p{depth}
37/// found with each overloaded version of #Initialize.
38/// During the iteration, the recursion can be individually selected per node visited.
39/// This is done by using either of the methods #Next or #NextSibling to proceed.
40/// Furthermore, the method #NextParentSibling allows skipping the rest of the current iteration
41/// branch.<br>
42/// The end of an iteration is detected with the method #IsValid.
43///
44/// Finally, the generation of a string representing the actual path to the current
45/// iteration node, relative to the iteration's start node, can be activated.
46/// See method #SetPathGeneration for more information about this feature.
47///
48/// \see
49/// Further information on how this class is used are given with paragraph
50/// \ref alib_ns_containers_stringtree_iterator "2.2 Class StringTreeIterator"
51/// of the description of class \b %StringTree.
52///
53/// @tparam TStringTree The \alib{containers;StringTree} that this class is working with.
54template<typename TStringTree>
56 #if !DOXYGEN
57 #if ALIB_DEBUG_CRITICAL_SECTIONS
58 #undef DCS
59 #undef DCSSHRD
60 #define DCS ALIB_DCS_WITH( tree->DbgGetDCS())
61 #define DCSSHRD ALIB_DCS_SHARED_WITH(tree->DbgGetDCS())
62 #endif
63 #endif
64
65 public:
66 /// Publicly Exposes template parameter \p{TStringTree}.
67 using StringTreeType= TStringTree;
68
69 /// Evaluates to \c true if the given template parameter \p{TStringTree} is a constant type.
70 static constexpr bool IsConst = std::is_const_v<TStringTree>;
71
72 /// Publicly exposes the cursor type that is used to walk the tree.
73 /// Evaluates to the constant or mutable types \alib{containers;StringTree::Cursor} or
74 /// or \alib{containers;StringTree::ConstCursor}.
75 using CursorType = std::conditional_t< !IsConst,
76 typename StringTreeType::Cursor,
77 typename StringTreeType::ConstCursor>;
78
79 /// Exposes \alib{containers;StringTree::CharacterType} #StringTreeType.
80 using CharacterType = typename StringTreeType::CharacterType;
81
82 protected:
83 /// Constant or mutable version of the base tree type, depending on template parameter
84 /// \p{TStringTree}
85 using cursorHandle= std::conditional_t<!IsConst,
86 typename StringTreeType::CursorHandle,
87 typename StringTreeType::ConstCursorHandle>;
88
89
90 //############################################# Sorter ###########################################
91 public:
92
93 /// Abstract base type to be used to implement custom sorting.
94 /// One simple built-in descendant is provided with struct #NameSorter.
95 struct Sorter {
96 /// Necessary virtual destructor.
97 virtual ~Sorter() =default;
98
99 /// Abstract method which needs to be implemented by descendants.
100 /// @param lhs The left-hand side cursor to the node to compare.
101 /// @param rhs The right-hand side cursor to the node to compare.
102 /// @return Needs to return \c true if \p{lhs} is 'smaller' than \p{rhs}, and \c false
103 /// otherwise.
104 virtual bool Compare( const StringTreeType::ConstCursor& lhs,
105 const StringTreeType::ConstCursor& rhs) =0;
106 };
107
108 /// Built-in descendant of struct #Sorter used to perform simple sorting based on
109 /// the name of <b>StringTree</b>-nodes.
111 /// Unless changed by the caller, this is copied with every recursion step.
112 bool Descending =false;
113
114 /// Unless changed by the caller, this is copied with every recursion step.
115 bool CaseSensitive =false;
116
117 /// Implementation of the abstract method. Compares the names of the nodes using
118 /// the string method \alib{strings::TString;CompareTo;String;CompareTo}.
119 /// @param lhs The left-hand side cursor to the node to compare.
120 /// @param rhs The right-hand side cursor to the node to compare.
121 /// @return Returns \c true if \p{lhs} is 'smaller' than \p{rhs}, and \c false otherwise.
122 bool Compare(const StringTreeType::ConstCursor& lhs,
123 const StringTreeType::ConstCursor& rhs) override {
124
125 int compResult= CaseSensitive
126 ? lhs.Name().template CompareTo<CHK,lang::Case::Sensitive>(rhs.Name())
127 : lhs.Name().template CompareTo<CHK,lang::Case::Ignore >(rhs.Name());
128 return Descending ? compResult > 0
129 : compResult < 0;
130 }
131 };
132
133 //#################################### Inner type RecursionData ##################################
134 protected:
135 /// Protected, internal struct used to store the data of recursive iterations.
137 {
138 /// Combines a node hook and a current vector index used to remember the
139 /// current child in unsorted, respectively sorted mode.
141 {
142 /// The current child of the current node in case of unsorted access.
143 /// If this is pointing to the end of the child map, then
144 /// the actual node itself is selected by this StringTreeIterator.
146
147 /// The current child index in case of sorted access.
148 /// A value of <c>size_t(-1)</c> indicates that
149 /// the actual node itself is selected.
150 size_t sortedIdx;
151 };
152
153 /// The actual child handle, respectively index.
155
156 /// The child hook of the parent node, used with unsorted iteration.
157 /// Note that this is declared \c const, in case \c constexpr field \p{IsConst}
158 /// equals \c true.
160
161 /// A pointer to a dynamically allocated vector of children used with sorting.
162 std::vector<cursorHandle> sortedChildren;
163
164 /// The (optional) sorter used with the actual node.
165 /// Unless changed by the caller, this is copied with every recursion step.
167
168 /// The path string length of the actual recursion depth.
170
171 /// Trivial default constructor.
172 RecursionData() noexcept =default;
173
174 /// Trivial default copy constructor.
175 RecursionData( const RecursionData& ) =default;
176
177 /// Trivial default move constructor.
178 RecursionData( RecursionData&& ) noexcept =default;
179
180 /// Trivial default copy assign operator.
181 /// @return A reference to \c this.
182 RecursionData& operator=( const RecursionData& ) =default;
183
184 /// Trivial default move assign operator.
185 /// @return A reference to \c this.
186 RecursionData& operator=( RecursionData&& ) noexcept =default;
187
188 /// Trivial default destructor.
189 ~RecursionData() noexcept =default;
190 }; // inner struct RecursionData
191
192 //############################################ members ###########################################
193 /// The \b %StringTree that this iterator works on.
194 TStringTree* tree =nullptr;
195
196 /// The pointer to the actual node.
198
199 /// A stack holding the recursive list of unsorted or sorted children and the
200 /// hook to the current child. Implemented as a vector in combination with member #actDepth,
201 /// to reuse allocated storage space during iteration and when this iterator is
202 /// re-used (freshly initialized).
203 std::vector<RecursionData> stack;
204
205 /// The path to the actual node (excluding the name of the actual node).
206 /// If this object is \e nulled, no paths are generated.
208
209 /// The current depth of the iteration (and usage but not size of field #stack).
210 /// set to \c -1 to if iteration is finished, respectively this iterator was not
211 /// initialized.
212 int actDepth =-1;
213
214 /// The requested maximum depth of iteration recursion.
215 unsigned maxDepth =(std::numeric_limits<unsigned int>::max)();
216
217 /// A pointer to a user-defined comparison object used with the next iteration.
218 Sorter* nextSorter =nullptr;
219
220//###################################### Constructor/Destructor ####################################
221 public:
222 /// Default constructor.
224
225 /// Trivial copy constructor.
227
228 /// Trivial default move constructor.
230
231 /// Trivial default copy assign operator.
232 /// @return A reference to \c this.
233 StringTreeIterator& operator =( const StringTreeIterator& ) =default;
234
235 /// Trivial default move assign operator.
236 /// @return A reference to \c this.
237 StringTreeIterator& operator =( StringTreeIterator&& ) =default;
238
239
240 /// Destructor.
242
243 //########################################### Interface ##########################################
244 /// With this method, the assembly of a string representing the absolute path of the actual
245 /// node is activated or deactivated.<br>
246 /// If activated, the path to the current node can be received with the method #Path.
247 ///
248 /// Note that, for technical reasons, the invocation of the method invalidates this iterator.
249 /// @param pathGeneration Denotes whether the path should be generated and retrievable or not.
250 void SetPathGeneration( lang::Switch pathGeneration ) {
251 Invalidate();
252 actPath.Reset( pathGeneration == lang::Switch::On ? EMPTY_STRING
253 : NULL_STRING );
254 }
255
256 /// Resets this iterator to the first child of the node that the given cursor
257 /// object represents.<br>
258 /// If the given node has no children, this iterator is marked invalid when this method returns,
259 /// unless param \p{includeStartNode} is set to \c true. In the latter case, at least the
260 /// start node is part of the iteration.
261 /// @param startNode The cursor that defines the branch of the tree to be iterated.
262 /// In debug-builts it is asserted that this instance is valid.
263 /// @param includeStartNode Denotes whether the \p{startNode} is included in the iteration or
264 /// not. If so, the start node will be the first node visited.
265 void Initialize( CursorType startNode, lang::Inclusion includeStartNode ) {
266 ALIB_ASSERT_ERROR( startNode.IsValid(), "STRINGTREE", "Invalid start-node given." )
267 this->tree= &startNode.template Tree<TStringTree>();
268 stack.clear();
269 DCSSHRD
270 if( actPath.IsNotNull() )
271 startNode.AssemblePath(actPath, lang::CurrentData::Clear);
272
273 node= startNode.Export();
274
275 if ( includeStartNode == lang::Inclusion::Include) {
276 RecursionData& rd= stack.emplace_back();
277 node= startNode.Export();
278 rd.actChild.sortedIdx= 0;
279 rd.sortedChildren.emplace_back(node);
280 actDepth= 0;
281 return;
282 }
283
284
285 if( startNode.HasChildren() ) {
286 actDepth= -1;
287 recursion();
288 }
289 else
290 actDepth= -1;
291 }
292
293 /// Invalidates this object. After invoking this method, this iterator cannot be
294 /// used further until one of the overloaded methods #Initialize is invoked.
295 /// After the invocation, the method #IsValid will return \c false.
296 void Invalidate() { actDepth= -1; }
297
298 /// Determines if this instance is valid. \b StringTreeIterator instances may become invalid
299 /// after invocations of one of the methods #Next, #NextSibling or #NextParentSibling
300 /// (at the end of the iteration) and become valid with the invocation of one of the
301 /// overloaded methods #Initialize.
302 ///
303 /// @return \c true if this is a valid iterator. If invalid, \c false is returned and
304 /// the iterator must not be evaluated before being initialized.
305 bool IsValid() const { return actDepth != -1; }
306
307 /// The negation of #IsValid.
308 ///
309 /// @return \c false if this is a valid iterator. If invalid, \c true is returned and
310 /// the iterator must not be evaluated before being initialized.
311 bool IsInvalid() const { return !IsValid(); }
312
313
314 /// Sets a sorter instance which is used for any next recursion step.
315 ///
316 /// This method may be invoked at any time, even on invalid iterators and those that are not
317 /// initialized, yet. The given \p{sorter} is stored for future use.
318 /// Such a use happens whenever a recursive iteration over a list of child nodes is
319 /// started. At that moment the current configuration of sorting is applied to
320 /// the list of direct children.
321 /// @param sorter A custom comparison method used for sorting the children
322 /// of nodes.
323 void SetSorting(Sorter *sorter) { nextSorter= sorter; }
324
325 /// Iterates to the first child of the current node. If no such child exists,
326 /// to the next sibling node. If also no sibling exists, iteration continues
327 /// with the next available node of a previous recursion level.
328 ///
329 /// @return \c true if a next node was found, \c false otherwise.
330 /// If \c false is returned, this iterator is invalid after the call.
331 bool Next() { DCSSHRD return next(0); }
332
333 /// Omits recursion on the current node's children, even if the current depth
334 /// is lower than #MaxDepth.<br>
335 ///
336 /// If no sibling exists, iteration continues with the next available node of a
337 /// previous recursion level.
338 ///
339 /// @return \c true if a next node was found, \c false otherwise.
340 /// If \c false is returned, this iterator is invalid after the call.
341 bool NextSibling() { DCSSHRD return next(1); }
342
343 /// Skips the remaining siblings of the current recursion level and continues with
344 /// the next available sibling of a previous level.
345 ///
346 /// @return \c true if a next node was found, \c false otherwise.
347 /// If \c false is returned, this iterator is invalid after the call.
348 bool NextParentSibling() { DCSSHRD return next(2); }
349
350
351 /// Retrieves the current path of walking as a string representation. The path returned is
352 /// absolute with a leading separator character.
353 ///
354 /// Note that this method can be used only if path generation was activated before the current
355 /// iteration. Activation is performed with the method SetPathGeneration.
356 ///
357 /// @return The path of the current node.
358 const TStringTree::NameType Path() const {
359 ALIB_ASSERT_ERROR( actPath.IsNotNull(), "STRINGTREE", "Path generation not activated" )
360 return actPath;
361 }
362
363 /// Returns the requested maximum depth of iteration, set with #Initialize.
364 /// @see For the current iteration depth, use #CurrentDepth.
365 /// @return The distance of the current node and the node of the start of the
366 /// iteration.
367 unsigned MaxDepth() const { return maxDepth; }
368
369 /// Changes the maximum depth of iteration. This method may be invoked any time, also after
370 /// iteration has started.
371 /// @param newMaxDepth The maximum depth to use from now on.
372 /// Defaults to the maximum <c>unsigned int</c> value.
373 void SetMaxDepth(unsigned int newMaxDepth= (std::numeric_limits<unsigned>::max)())
374 { maxDepth= newMaxDepth; }
375
376 /// Returns the depth of the current iteration. This is value is available to the
377 /// algorithm, which means this method executes in constant time.
378 ///
379 /// To get the absolute depth of the current node, the method
380 /// \doxlinkproblem{classalib_1_1containers_1_1StringTree_1_1TCursor.html;ac0ea9d0558dbd3565be5051fec3222fb;TCursor::Depth},
381 /// may be used.
382 ///
383 /// @return The distance of the current node and the node of the start of the
384 /// iteration.
385 unsigned CurrentDepth() const {
386 ALIB_ASSERT_ERROR( IsValid(), "STRINGTREE",
387 "StringTreeIterator not initialized or exceeded (invalid)." )
388 return unsigned(actDepth);
389 }
390
391 /// Returns the current node, encapsulated in a cursor object.
392 ///
393 /// \note
394 /// It is \b not allowed to use the method
395 /// \doxlinkproblem{classalib_1_1containers_1_1StringTree_1_1TCursor.html;a04cf02f30f8a652bb40cf889b8b9e61e;TCursor::Delete}
396 /// on the node returned by this method.
397 /// As a replacement, use the method #DeleteNode provided with this class.<br>
398 /// However, the methods
399 /// \doxlinkproblem{classalib_1_1containers_1_1StringTree_1_1TCursor.html;ae406201cd8da023cf9bf50df25626153;TCursor::DeleteChild} and
400 /// \doxlinkproblem{classalib_1_1containers_1_1StringTree_1_1TCursor.html;af655aeecbd2712df8db94a340a8385ee;TCursor::DeleteChildren}
401 /// are allowed
402 /// to be invoked and therefore have no replacement in this class.
403 ///
404 /// @return An instance of the public node interface pointing to the currently
405 /// referenced tree node.
406 CursorType Node() const {
407 ALIB_ASSERT_ERROR( IsValid(), "STRINGTREE",
408 "StringTreeIterator not initialized or exceeded (invalid)." )
409 return tree->ImportCursor(node);
410 }
411
412 //######################################### node deletion ########################################
413
414 /// Deletes the node that this iterator currently refers to from the tree.
415 /// After the operation, the iterator is moved forward to the next sibling
416 /// of the current node, respectively of the first sibling found in the
417 /// recursion stack.
418 ///
419 /// \note
420 /// This method constitutes a legal alternative to method
421 /// \doxlinkproblem{classalib_1_1containers_1_1StringTree_1_1TCursor.html;a04cf02f30f8a652bb40cf889b8b9e61e;TCursor::Delete},
422 /// which is forbidden to be invoked on the node returned by method #Node as this would
423 /// invalidate this iterator.<br>
424 /// Methods
425 /// \doxlinkproblem{classalib_1_1containers_1_1StringTree_1_1TCursor.html;ae406201cd8da023cf9bf50df25626153;TCursor::DeleteChild} and
426 /// \doxlinkproblem{classalib_1_1containers_1_1StringTree_1_1TCursor.html;af655aeecbd2712df8db94a340a8385ee;TCursor::DeleteChildren}
427 /// are allowed with this iterator type.
428 /// Consequently, no replacement method for those is given with this class.
429 ///
430 /// @return The total number of nodes deleted.
432 ALIB_ASSERT_ERROR( IsValid(), "STRINGTREE",
433 "StringTreeIterator not initialized or exceeded (invalid)." )
434 auto nodeToDelete= node;
435 next( 1 ); // next sibling
436 auto ntd= tree->ImportCursor(nodeToDelete);
437 return ntd.Parent().DeleteChild( ntd );
438 }
439
440 //################################## StringTreeIterator Internals ################################
441 protected:
442 /// Sets this iterator to point to the first child of the actual node.
443 /// If sorting is enabled, copies all children from the map to a vector and sorts
444 /// them there.
445 void recursion() {
446 ++actDepth;
447 if( stack.size() == size_t(actDepth) )
448 stack.emplace_back();
449
450 auto& rd= stack[size_t(actDepth)];
451
452 auto cursor= tree->ImportCursor(node);
453 rd.sorter= nextSorter;
454
455 // no sorting: set link to node's child hook
456 if (!rd.sorter) {
457 rd.unsortedParent= tree->ImportCursor(node).FirstChild().Export();
458 node= (rd.actChild.unsortedHandle= rd.unsortedParent);
459 } else {
460
461 // sorting: copy children to a sortable vector
462 rd.sortedChildren.clear();
463 rd.sortedChildren.reserve( size_t( cursor.CountChildren() ) );
464 cursor.GoToFirstChild();
465 while( cursor.IsValid() ) {
466 rd.sortedChildren.emplace_back( cursor.Export() );
467 cursor.GoToNextSibling();
468 }
469
470 // sort
471 std::sort( rd.sortedChildren.begin(), rd.sortedChildren.end(),
472 [this,&rd]( cursorHandle lhs,
473 cursorHandle rhs )
474 {
475 return rd.sorter->Compare( tree->ImportCursor(lhs),
476 tree->ImportCursor(rhs) );
477 }
478 );
479
480 // set to first child
481 rd.actChild.sortedIdx= 0;
482 node= rd.sortedChildren[0];
483 }
484
485 // add path information
486 if ( actPath.IsNotEmpty() ) {
487 rd.pathStringLen= actPath.Length();
488 if ( rd.pathStringLen == 1 ) rd.pathStringLen= 0;
489 else actPath.template _<NC>( tree->Separator() );
490
491 actPath.template _<NC>( tree->ImportCursor(node).Name() );
492 } }
493
494
495 /// Goes to the next node.
496 /// This method is used with interface methods #Next, #NextSibling and
497 /// #NextParentSibling, as well as with #DeleteNode}.
498 ///
499 /// @param skipMode \c 0: iterates to the first child (if available),
500 /// \c 1: iterates to the next sibling (if available) and
501 /// \c 2: to the next available sibling of the parent, respectively the
502 /// current recursion stack.
503 /// @return \c true if this iterator is valid (a next node was found), \c false
504 /// otherwise.
505 bool next(int skipMode) {
506 ALIB_ASSERT_ERROR( actDepth != -1, "STRINGTREE", "Invalid iterator" )
507
508 auto cursor= tree->ImportCursor(node);
509
510 // recursion to first child of actual node?
511 if( skipMode == 0
512 && unsigned(actDepth) < maxDepth
513 && cursor.CountChildren() )
514 {
515 // increase stack capacity
516 if( stack.size() == size_t(actDepth) + 1 )
517 stack.emplace_back();
518
519 recursion();
520
521 return true;
522 }
523
524 for(;;) {
525 if( skipMode != 2 ) {
526 // next sibling
527 RecursionData& rd= stack[ size_t(actDepth) ];
528 if( rd.sortedChildren.size() ) {
529 ++rd.actChild.sortedIdx;
530 if( rd.actChild.sortedIdx < rd.sortedChildren.size() ) {
531 node= rd.sortedChildren[rd.actChild.sortedIdx];
532 break;
533 }
534 } else {
535 auto next= tree->ImportCursor(rd.actChild.unsortedHandle).NextSibling();
536 node= (rd.actChild.unsortedHandle= next.Export());
537 if ( next.IsValid() )
538 break;
539 } }
540
541 skipMode= 0;
542
543 // climb down
544 if (--actDepth == -1 )
545 return false;
546 }
547
548 // adjust path
549 if ( actPath.IsNotEmpty() ) {
550 actPath.ShortenTo(stack[ size_t(actDepth) ].pathStringLen + 1)
551 .template _<NC>(tree->ImportCursor(node).Name());
552 }
553
554 return true;
555 }
556
557 #if !DOXYGEN
558 #if ALIB_DEBUG_CRITICAL_SECTIONS
559 #undef DCS
560 #undef DCSSHRD
561 #endif
562 #endif
563
564}; // class "StringTreeIterator"
565
566} // namespace alib::[containers]
567
568/// Type alias in namespace \b alib.
569template<typename TTree>
571
572} // namespace [alib]
TStringTree StringTreeType
Publicly Exposes template parameter TStringTree.
StringTreeIterator()=default
Default constructor.
void SetMaxDepth(unsigned int newMaxDepth=(std::numeric_limits< unsigned >::max)())
void Initialize(CursorType startNode, lang::Inclusion includeStartNode)
typename StringTreeType::CharacterType CharacterType
Exposes StringTree::CharacterType StringTreeType.
std::conditional_t< !IsConst, typename StringTreeType::Cursor, typename StringTreeType::ConstCursor > CursorType
const TStringTree::NameType Path() const
std::conditional_t<!IsConst, typename StringTreeType::CursorHandle, typename StringTreeType::ConstCursorHandle > cursorHandle
void SetPathGeneration(lang::Switch pathGeneration)
#define ALIB_EXPORT
Definition alib.inl:497
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1066
@ On
Switch it on, switched on, etc.
@ Clear
Chooses to clear existing data.
Inclusion
Denotes how members of a set something should be taken into account.
@ Include
Chooses inclusion.
constexpr String NULL_STRING
A nulled string of the default character type.
Definition string.inl:2271
constexpr const String EMPTY_STRING
An empty string of the default character type.
Definition string.inl:2251
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.inl:152
containers::StringTreeIterator< TTree > StringTreeIterator
Type alias in namespace alib.
bool Compare(const StringTreeType::ConstCursor &lhs, const StringTreeType::ConstCursor &rhs) override
bool CaseSensitive
Unless changed by the caller, this is copied with every recursion step.
bool Descending
Unless changed by the caller, this is copied with every recursion step.
integer pathStringLen
The path string length of the actual recursion depth.
std::vector< cursorHandle > sortedChildren
A pointer to a dynamically allocated vector of children used with sorting.
ActChildIdentifier actChild
The actual child handle, respectively index.
RecursionData() noexcept=default
Trivial default constructor.
virtual bool Compare(const StringTreeType::ConstCursor &lhs, const StringTreeType::ConstCursor &rhs)=0
virtual ~Sorter()=default
Necessary virtual destructor.