ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
stringtree.hpp
Go to the documentation of this file.
1/** ************************************************************************************************
2 * \file
3 * This header file is part of module \alib_monomem of the \aliblong.
4 *
5 * \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
6 * Published under \ref mainpage_license "Boost Software License".
7 **************************************************************************************************/
8#ifndef HPP_ALIB_MONOMEM_STRINGTREE
9#define HPP_ALIB_MONOMEM_STRINGTREE 1
10
11#if !defined (HPP_ALIB_MONOMEM_MONOMEM)
13#endif
14
15ALIB_ASSERT_MODULE(STRINGS)
16
17#include "alib/monomem/detail/stringtreebase.inl"
18
19namespace alib { namespace monomem {
20
21#if ALIB_DEBUG
22 /** Statistic variable increased by \alib{monomem;StringTreeNamesDynamic} with every creation
23 * of a node. With process creation the variable is \c 0. A user may reset the variable to
24 * inspect percentages of name overflows during certain operations. The variable is not thread
25 * safe and used by any instance of class \b StringTree which uses node maintainer
26 * \b StringTreeNamesDynamic.
27 * @see Sibling variable \alib{monomem;DbgStatsStringTreeNameOverflows} */
29
30 /** Statistic variable increased by \alib{monomem;StringTreeNamesDynamic} with every creation
31 * of a node whose name exceeds the internal string buffer size.
32 * With process creation the variable is \c 0. A user may reset the variable to
33 * inspect percentages of name overflows during certain operations. The variable is not thread
34 * safe and used by any instance of class \b StringTree which uses node maintainer
35 * \b StringTreeNamesDynamic.
36 * @see Sibling variable \alib{monomem;DbgStatsStringTreeNameOverflows} */
38#endif
39
40/**
41 * This struct is the default type for template parameter
42 * \ref alib_ns_monomem_stringtree_referencedoc "TNodeMaintainer" of class
43 * \alib{monomem;StringTree}.
44 *
45 * Besides defining the character type as given with template parameter \p{TChar}, the node name
46 * string type is exposed with #NameStringType. The string type depends on template parameter
47 * \p{TLocalCapacity}:
48 * - If this is \c 0, the type evaluates to a simple string with no internal storage.
49 * - If this is greater than zero, the type evaluates to a \alib{strings;TLocalString;LocalString}
50 * of given capacity.
51 *
52 * This design allows to allocate a fixed-size string buffer with each node and only if a
53 * node's name exceeds this capacity, a dynamic allocation for storing the node name is performed.
54 * As a consequence, some overhead of wasted memory will occur, as this capacity is
55 * allocated with every node, regardless of its name's length.
56 * To investigate into the percentage of overflows to evaluate a reasonable value for template
57 * parameter \p{TLocalCapacity}, simple global debug counters
58 * \alib{monomem;DbgStatsStringTreeNames} and \alib{monomem;DbgStatsStringTreeNameOverflows}
59 * can be used.
60 *
61 * Method #InitializeNode is invoked after insertion of a new element (aka "node")
62 * into the container and #FreeNode is invoked prior to the destruction of a node.
63 * When #InitializeNode is invoked, the custom object of template type \p{T} (of the \b StringTree)
64 * is already default constructed and the key of the node in union
65 * (field \alib{monomem;detail::StringTreeBase::NodeKey::name}) is set to what was provided
66 * as a child name or path string. (In the latter case, it is set to a substring of the
67 * given path.). If template parameter \p{TLocalCapacity} is greater than 0, the
68 * method copies the key to field \e storage of the union (which is still accessible with the
69 * base string type of union-field \e key).
70 * If \c 0 is given, the node name is replaced by a copy of the string which is dynamically
71 * allocated.
72 *
73 * ## Custom Implementations ##
74 * A custom implementation has to provide all four entities that this type provides in a
75 * compatible fashion.
76 *
77 * The main purpose of the node maintainer types is to ensure that the name strings of inserted
78 * nodes are duly allocated, copied and freed as needed:
79 * When a new element is (or a whole path of new elements are) created, then the initial name
80 * of the nodes are taken from the string passed to the corresponding interface method of class
81 * \b StringTree (and inner types). The challenge is that these string's life-cycle might
82 * be only short term. Therefore, right after the creation of an element, method #InitializeNode
83 * is invoked, allowing to create a safe copy of the name.<br>
84 * To free any allocated space, method #FreeNode is invoked.
85 *
86 * Besides this, custom implementation may tweak the given node on their own discretion.
87 * Especially a custom implementation may create and recycle other portions of the stored
88 * objects, to establish \ref alib_monomem_intro_strictweak "weak monotonic allocation rules".
89 * A sample of such more complex behaviour is found with \alib type \alib{files;FTree}.
90 *
91 * \see
92 * Two other built-in implementations of this type to be used with \b StringTree instantiations
93 * are provided with this \alibmod:
94 * - \alib{monomem;StringTreeNamesStatic}.
95 * - \alib{monomem;StringTreeNamesMonoAlloc}.
96 * \see
97 * Further information can be found in chapter
98 * \ref alib_ns_monomem_stringtree_alloc_names "4. Node and Node Name String Allocation"
99 * of the reference documentation of class \b StringTree.
100 *
101 * @tparam TChar The character type of the key strings. This type is used with any
102 * interface method of \alib{monomem;StringTree} that accepts a node name
103 * or path string.<br>
104 * Defaults to type \alib{characters;character}.
105 * @tparam TLocalCapacity The capacity of the \alib{strings;TLocalString;LocalString} to place in
106 * the <b>StringTree</b>'s node. If \c 0 is given, a normal
107 * \alib{strings;TString;String} is used for the name, and the buffer is
108 * copied to an dynamically allocated array.<br>
109 * Defaults to \c 32.
110 */
111template<typename TChar= character, integer TLocalCapacity= 32>
113{
114 /** The character type that the \b StringTree uses for child name and path strings. */
115 using CharacterType = TChar;
116
117 /** The string type of a node's name. */
118 using NameStringType = ATMP_IF_T_F ( (TLocalCapacity > 0),
120 strings::TString <TChar> );
121
122
123 /**
124 * This implementation copies the node's name to a dynamically allocated piece of heap memory.
125 * \see
126 * See class description for further information.
127 * @param tree The instance of struct \alib{monomem;detail::StringTreeBase} that invokes
128 * this method. Any member may be accessed, including
129 * \alib{monomem::detail::StringTreeBase;nodeTable} which contains the
130 * \alib{monomem;MonoAllocator} that the tree uses for the allocation of nodes.
131 * @param node The node that was just created. Allows access to the key and
132 * custom value data. While the parent and sibling nodes are likewise accessible,
133 * it is strictly forbidden to modify those.
134 * @tparam TTree The type of the templated instantiation of struct
135 * \alib{monomem;detail::StringTreeBase} that this method is invoked by.
136 * (Deduced by the compiler.)
137 */
138 template<typename TTree>
139 static
140 void InitializeNode( TTree& tree, typename TTree::Node& node )
141 {
142 (void) tree;
143
144 // if not a local string buffer, then dynamically allocate and copy. Else, do nothing
145 if constexpr (TLocalCapacity <= 0)
146 {
147 CharacterType* buffer= new CharacterType[size_t(node.name.key.Length())];
148 node.name.key.CopyTo( buffer );
149 node.name.key= strings::TString<CharacterType>( buffer, node.name.key.Length() );
150 }
151 else
152 {
153 strings::TString<TChar> key= node.name.key; // get current pointer
154 new (&node.name.storage) NameStringType(); // placement new to re-establish local string
155 node.name.storage.DbgDisableBufferReplacementWarning();
156 ALIB_DBG( const TChar* internalBuffer= node.name.storage.Buffer(); )
157 node.name.storage.Append(key); // copy key to buf
159 if( internalBuffer != node.name.storage.Buffer() )
161 }
162 }
163
164 /**
165 * This implementation frees the dynamically allocated memory of the node's name.
166 * \see
167 * See class description for further information.
168 * @param tree The instance of struct \alib{monomem;detail::StringTreeBase} that invokes
169 * this method. Any member may be accessed, including
170 * \alib{monomem::detail::StringTreeBase;nodeTable} which contains the
171 * \alib{monomem;MonoAllocator} that the tree uses for the allocation of nodes.
172 * @param node The node that is to be removed. Allows access to the key and
173 * custom value data. While the parent and sibling nodes are likewise accessible,
174 * it is strictly forbidden to modify those.
175 * @tparam TTree The type of the templated instantiation of struct
176 * \alib{monomem;detail::StringTreeBase} that this method is invoked by.
177 * (Deduced by the compiler.)
178 */
179 template<typename TTree>
180 static
181 void FreeNode( TTree& tree, typename TTree::Node& node )
182 {
183 (void) tree;
184 if constexpr (TLocalCapacity <= 0)
185 delete[] node.name.key.Buffer();
186 else
187 node.name.storage.~TLocalString();
188 }
189};
190
191/**
192 * Built-in implementation usable as template parameter
193 * \ref alib_ns_monomem_stringtree_referencedoc "TNodeMaintainer" of class
194 * \alib{monomem;StringTree}.
195 *
196 * This type does not allocate memory and does not copy the key string of a node. Therefore, this
197 * type is very efficient to use in situations where exclusively "static" strings for child names
198 * and paths are passed to the interface methods of class \b StringTree (and inner types) which lead
199 * to the creation of new child nodes.<br>
200 * The term "static" here means that the strings given are either static character data of a
201 * compilation unit or by any other means their allocated memory and the contained data survive
202 * the life-cycle of the corresponding \b StringTree.
203 *
204 * \see
205 * Two other built-in implementations of this type to be used with \b StringTree instantiations
206 * are provided with this \alibmod:
207 * - \alib{monomem;StringTreeNamesDynamic}.
208 * - \alib{monomem;StringTreeNamesMonoAlloc}.
209 * \see
210 * Further information can be found in chapter
211 * \ref alib_ns_monomem_stringtree_alloc_names "4. Node and Node Name String Allocation"
212 * of the reference documentation of class \b StringTree.
213 *
214 * @tparam TChar The character type of the key strings. This type is used with any
215 * interface method of \alib{monomem;StringTree} that accepts a node name or path
216 * string.
217 */
218template<typename TChar= character>
220{
221 /** The character type that the \b StringTree uses for child name and path strings. */
222 using CharacterType = TChar;
223
224 /** The string type of a node's name. */
226
227 /**
228 * This implementation is empty.
229 *
230 * \see
231 * See description of this class and the "default implementation"
232 * \alib{monomem;StringTreeNamesDynamic}.
233 *
234 * @param tree The instance of struct \alib{monomem;detail::StringTreeBase} that invokes
235 * this method. Any member may be accessed, including
236 * \alib{monomem::detail::StringTreeBase;nodeTable} which contains the
237 * \alib{monomem;MonoAllocator} that the tree uses for the allocation of nodes.
238 * @param node The node that was just created. Allows access to the key and
239 * custom value data. While the parent and sibling nodes are likewise accessible,
240 * it is strictly forbidden to modify those.
241 * @tparam TTree The type of the templated instantiation of struct
242 * \alib{monomem;detail::StringTreeBase} that this method is invoked by.
243 * (Deduced by the compiler.)
244 */
245 template<typename TTree>
246 static
247 void InitializeNode( TTree& tree, typename TTree::Node& node )
248 {
249 (void) tree;
250 (void) node;
251 }
252
253 /**
254 * This implementation is empty.
255 *
256 * \see
257 * See description of this class and the "default implementation"
258 * \alib{monomem;StringTreeNamesDynamic}.
259 *
260 * @param tree The instance of struct \alib{monomem;detail::StringTreeBase} that invokes
261 * this method. Any member may be accessed, including
262 * \alib{monomem::detail::StringTreeBase;nodeTable} which contains the
263 * \alib{monomem;MonoAllocator} that the tree uses for the allocation of nodes.
264 * @param node The node that is to be removed. Allows access to the key and
265 * custom value data. While the parent and sibling nodes are likewise accessible,
266 * it is strictly forbidden to modify those.
267 * @tparam TTree The type of the templated instantiation of struct
268 * \alib{monomem;detail::StringTreeBase} that this method is invoked by.
269 * (Deduced by the compiler.)
270 */
271 template<typename TTree>
272 static
273 void FreeNode( TTree& tree, typename TTree::Node& node )
274 {
275 (void) tree;
276 (void) node;
277 }
278
279};
280
281/**
282 * Built-in implementation usable as template parameter
283 * \ref alib_ns_monomem_stringtree_referencedoc "TNodeMaintainer" of class
284 * \alib{monomem;StringTree}.
285 *
286 * This type copies the node's name into memory acquired with the monotonic allocator that the
287 * \b StringTree uses.<br>
288 *
289 * \attention
290 * The use of this type is dangerous in respect to memory exhaustion. While class
291 * \b StringTree uses monotonic allocation in a
292 * \ref alib_ns_monomem_stringtree_hashing "very safe way", with the use of this
293 * type, repeated removals and insertions of tree nodes, increase the memory usage.<br>
294 * Consequently, the use of this type is restricted to cases that imply a limited
295 * number of insertions.
296 *
297 * \see
298 * Two other built-in implementations of this type to be used with \b StringTree instantiations
299 * are provided with this \alibmod:
300 * - \alib{monomem;StringTreeNamesStatic}.
301 * - \alib{monomem;StringTreeNamesDynamic}.
302 * \see
303 * Further information can be found in chapter
304 * \ref alib_ns_monomem_stringtree_alloc_names "4. Node and Node Name String Allocation"
305 * of the reference documentation of class \b StringTree.
306 *
307 * @tparam TChar The character type of the key strings. This type is used with any
308 * interface method of \alib{monomem;StringTree} that accepts a node name or path
309 * string.
310 */
311template<typename TChar= character>
313{
314 /** The character type that the \b StringTree uses for child name and path strings. */
315 using CharacterType= TChar;
316
317 /** The string type of a node's name. */
319
320 /**
321 * This implementation copies the node's name to a piece of memory allocated in the
322 * \alib{monomem;MonoAllocator} found in field \alib{monomem::detail::StringTreeBase;nodeTable}
323 * of the given \p{tree}.
324 *
325 * \see
326 * See description of this class and the "default implementation"
327 * \alib{monomem;StringTreeNamesDynamic}.
328 *
329 * @param tree The instance of struct \alib{monomem;detail::StringTreeBase} that invokes
330 * this method. Any member may be accessed, including
331 * \alib{monomem::detail::StringTreeBase;nodeTable} which contains the
332 * \alib{monomem;MonoAllocator} that the tree uses for the allocation of nodes.
333 * @param node The node that was just created. Allows access to the key and
334 * custom value data. While the parent and sibling nodes are likewise accessible,
335 * it is strictly forbidden to modify those.
336 * @tparam TTree The type of the templated instantiation of struct
337 * \alib{monomem;detail::StringTreeBase} that this method is invoked by.
338 * (Deduced by the compiler.)
339 */
340 template<typename TTree>
341 static
342 void InitializeNode( TTree& tree, typename TTree::Node& node )
343 {
344 node.name.storage= tree.nodeTable.GetAllocator()->EmplaceString( node.name.key );
345 }
346
347 /**
348 * This implementation does nothing.
349 *
350 * \see
351 * See description of this class and the "default implementation"
352 * \alib{monomem;StringTreeNamesDynamic}.
353 *
354 * @param tree The instance of struct \alib{monomem;detail::StringTreeBase} that invokes
355 * this method. Any member may be accessed, including
356 * \alib{monomem::detail::StringTreeBase;nodeTable} which contains the
357 * \alib{monomem;MonoAllocator} that the tree uses for the allocation of nodes.
358 * @param node The node that is to be removed. Allows access to the key and
359 * custom value data. While the parent and sibling nodes are likewise accessible,
360 * it is strictly forbidden to modify those.
361 * @tparam TTree The type of the templated instantiation of struct
362 * \alib{monomem;detail::StringTreeBase} that this method is invoked by.
363 * (Deduced by the compiler.)
364 */
365 template<typename TTree>
366 static
367 void FreeNode( TTree& tree, typename TTree::baseNode& node )
368 {
369 (void) tree;
370 (void) node;
371 }
372
373};
374
375/** ********************************************************************************************
376 * # 1. Introduction # {#alib_ns_monomem_stringtree_overview}
377 * This container type implements a directed, non-circular graph (tree) with named nodes.
378 *
379 * The internal node type \alib{monomem;detail::StringTreeBase::Node} stores:
380 * 1. A name string, which has to be unique in respect to the names of sibling nodes. (Just like
381 * no two files in a folder may have the same name.)
382 * 2. Five pointers to related nodes:
383 * - the parent node
384 * - the previous and next sibling nodes,
385 * - the first and last child nodes,
386 * 3. A data field holding the node's custom value of template type \p{T}.
387 *
388 * The way from the root node to a descendent node, usually is called "path". The class incorporates
389 * functionality to work with string representations of such paths where names of child nodes are
390 * concatenated and separated by a special separation character.
391 *
392 * The search and creation of tree nodes by using aforementioned path strings, is very similar to
393 * what is well known from addressing files and folders in file systems.
394 * This class does not differentiate between 'folders' and 'files', hence between 'nodes' and
395 * 'leafs'. Every node has the same data of type \p{T} attached and may or may not have child nodes.
396 * If such differentiation - or other semantics - is wanted, this may well be modeled by custom
397 * attributes provided in template type \p{T}.
398 *
399 * \I{#############################################################################################}
400 * # 2. Inner Types # {#alib_ns_monomem_stringtree_inner}
401 * Two public inner types exist.
402 * All operations on tree nodes like insertion, deletion, search and attribute access is performed
403 * using objects of public type \alib{monomem;StringTree::TCursor}. This is a lightweight,
404 * iterator-like "handle" containing a pointer to the originating tree object and to a represented
405 * node. The type provides various methods to travers the tree. It is templated over a boolean
406 * value which determines if a const or mutable \b StringTree is given. Shortcuts for these
407 * types are \alib{monomem;StringTree::Cursor} and \alib{monomem;StringTree::ConstCursor}.
408 *
409 * Besides this, class \alib{monomem;StringTree::RecursiveIterator} allows recursive
410 * iterations with built-in or custom sort orders.
411 *
412 * Both types are explained in the following paragraphs.
413 *
414 * \I{#############################################################################################}
415 * ## 2.1 Inner Class Cursor ## {#alib_ns_monomem_stringtree_cursor}
416 *
417 * The main interface into class \b %StringTree is given by public, inner type
418 * \alib{monomem;StringTree::Cursor}. Method #Root returns an object of that type that
419 * initially refers to the root node of the tree.
420 * With this, child names and composite "paths" can be used to move the pointer along existing nodes
421 * of the tree or to create new child nodes or even a whole path of such child nodes at once.
422 *
423 * Class \b %Cursor is very lightweight as it contains just two pointers, one to the
424 * \b %StringTree it originates from and one to the tree node currently represented.
425 * Hence, objects of this type can be copied, assigned and passed around very efficiently.<br>
426 * The currently represented node's templated custom data can be accessed with method
427 * #TCursor::Value.
428 *
429 * The methods to traverse over the nodes of the tree are:
430 * - #TCursor::GoToRoot
431 * - #TCursor::GoToParent
432 * - #TCursor::GoToTraversedPath
433 * - #TCursor::GoToNextSibling
434 * - #TCursor::GoToPreviousSibling
435 * - #TCursor::GoToChild
436 * - #TCursor::GoToFirstChild
437 * - #TCursor::GoToLastChild
438 *
439 * With these methods, class \b StringTree::Cursor constitutes a sort of iterator idiom
440 * idiom. For example to traverse all entries in the root folder, the following schematic would
441 * be used:
442 *
443 * myCursor= myTree.GetRoot()
444 * myCursor.GotoFirstChild()
445 * While( myCursor.IsValid() )
446 * DoSomething( myCursor.Value() )
447 * myCursor.GotoNextSibling
448 *
449 * For some of these methods an alternative version exists, which returns a corresponding copy
450 * of the cursor, while leaving the original object unchanged. These methods share
451 * the same name excluding the prefix <b>GoTo</b>.
452 *
453 * For the creation of new child nodes or a complete path of such, methods
454 * - #TCursor::GoToCreateChildIfNotExistent and ,
455 * - #TCursor::GoToCreatedPathIfNotExistent
456 * are provided.
457 *
458 * Next, four methods that perform node deletion exist:
459 * - #TCursor::DeleteChild (two overloaded versions),
460 * - #TCursor::DeleteChildren and
461 * - #TCursor::Delete
462 *
463 * The already mentioned methods:
464 * - #TCursor::GoToParent},
465 * - #TCursor::GoToFirstChild},
466 * - #TCursor::GoToLastChild},
467 * - #TCursor::GoToNextSibling} and
468 * - #TCursor::GoToPreviousSibling}
469 *
470 * of class \b Cursor can be used to iterate from a node upward to the root node or through the
471 * list of children of a node. Each method may \e invalidate the object in the case that no
472 * corresponding parent or sibling node exists.
473 * Invalid cursor objects can be (or rather have to be!) detected using method
474 * #TCursor::IsValid.
475 * Most of the class's methods must not be invoked on an invalidated object. Doing so is undefined
476 * behavior and raises an \alib assertion in debug-builds.
477 * Invalid \b %Cursor objects can reset to a valid state using methods
478 * - #TCursor::GoToRoot and
479 * - #TCursor::GoToTraversedPath
480 *
481 * if absolute path addressing is used.
482 *
483 * Instances that have been default-constructed may only be set to a valid state by (copy-)
484 * assigning a valid instance.
485 *
486 * \I{#############################################################################################}
487 * ## 2.2. Inner Class RecursiveIterator ## {#alib_ns_monomem_stringtree_iterator}
488 * Class \alib{monomem;StringTree::RecursiveIterator} provides a configurable and controlled
489 * way of iterating a branch of a tree. Some features of the class are:
490 * - Iterators can be initialized to start from any node of the tree
491 * Iteration ends when all (recursive) child nodes of the start node have been visited.
492 * - The iteration follows a "depth first search" approach: Prior to visiting a sibling node,
493 * all children of a node are visited.
494 * - The recursion depth can be limited, including to depth \c 0, which iterates only the
495 * direct child nodes of the start node.
496 * - Prior to entering a new depth-level during iteration, different sort orders can be set.
497 * The choices are:
498 * - No sorting (iterates in order of node insertion).
499 * - Built-in sorting by node (path) name, ascending/descending, case sensitive or ignoring case
500 * - user defined by path name, number of children or any other attribute of the node, of-course
501 * including a node's custom data values.
502 *
503 * Class \b RecursiveIterator is of rather heavy weight and sorted iteration needs to allocate
504 * memory for sorting the child nodes for each depth level of a potential recursion.
505 * Therefore it is recommended to reuse instances of the class with subsequent, similar iterations.
506 * In addition this explains why this class does not follow the concept of <c>std::iterator_traits</c>,
507 * which is designed to be used with lightweight iterator types.
508 *
509 * \I{#############################################################################################}
510 * # 3. Node Allocation And Hashing # {#alib_ns_monomem_stringtree_hashing}
511 * While each node maintains a doubly linked list of child nodes for iteration, this class stores
512 * each inserted element in a \alib{monomem;HashTable} using the parent node and the element's
513 * name as a unique key.
514 * This is done to be able to search for a child with a given name in constant time.
515 * This container does not perform any other memory allocations than those that this
516 * \b HashTable does.
517 *
518 * With that, the implementation of this container type is able to leave all allocation and
519 * <em>"recycling"</em> of node elements to this hash table, which is found in base class's field
520 * \alib{monomem;detail::StringTreeBase::nodeTable}. As explained in the documentation of
521 * \alib{monomem;HashTable}, its allocation mechanism can be made safe in respect to memory
522 * exhaustion of the underlying \alib{monomem;MonoAllocator}, even if a virtually unlimited number of
523 * insertions and removals of elements is performed. Such safeness depends on template
524 * parameter \p{TRecycling} which is just passed to the definition of the internal hash table of
525 * nodes.
526 * \see
527 * For more information on this topic see also chapter \ref alib_monomem_intro_recycling
528 * of this \alibmod_nl Programmer's Manual.
529 *
530 * \I{#############################################################################################}
531 * # 4. Node and Node Name String Allocation # {#alib_ns_monomem_stringtree_alloc_names}
532 *
533 * The C++ version of this class allows user-defined allocation (and copying) of the node's name
534 * character strings. For this, template parameter \p{TNodeMaintainer} is defined,
535 * which defaults to built-tin struct \alib{monomem;StringTreeNamesDynamic}.
536 * This default "node maintainer" defines the name type of nodes to \alib{strings;TLocalString;LocalString}
537 * with a default capacity of \c 32 characters. This way, dynamic allocation is performed automatically
538 * by this local string when a node is constructed.<br>
539 * In the case that many "long" node names are expected, it might be efficient to set the capacity
540 * to \c 0. In this case, type \b StringTreeNamesDynamic defines the string type to a normal
541 * \b String and uses C++ keywords <c>new</c> and <c>delete[]</c> to allocate
542 * and free character buffers for the name string.
543 *
544 * A second built-in and ready to use "node maintainer" type is given with
545 * \alib{monomem;StringTreeNamesStatic}. This uses an unbuffered \b String and has empty
546 * implementations of its static methods. This way no copies of the original string buffers that
547 * are passed to the to interface methods of class \b Cursor that create children are made.
548 * This is useful (and very efficient!) if \b all child name and creation path strings provided
549 * of class \b %Cursor are permanently valid (in other words, their life-cycle spans over
550 * the life-cycle of the nodes in a tree) and therefore do not need to be copied to dedicated
551 * allocated memory. If this precondition is not assured, the \b StringTree produces undefined
552 * behavior.
553 *
554 * Finally, string trees that during their lifetime just grow and where no nodes (or only a limited
555 * number of nodes) are removed until the whole tree is disposed, may be instantiated using
556 * the third built-in type \alib{monomem;StringTreeNamesMonoAlloc}.
557 * With that, the concept of \ref alib_monomem_intro "monotonic allocation" that this container
558 * type uses can be extended to the node name strings.
559 * Type \b StringTreeNamesMonoAlloc grabs the allocator from the tree provided with method
560 * \alib{monomem::StringTreeNamesMonoAlloc;InitializeNode} and just clones the given string
561 * into this.
562 *
563 * \I{#############################################################################################}
564 * # 5. Equipping the Root Node with Values # {#alib_ns_monomem_stringtree_rootnodevalues}
565 * It depends on the field of application, whether the root node should dispose over an instance
566 * of custom type \p{T} or not.
567 * For example a tree of depth \c 1, which could be implemented using type
568 * <c>std::vector<T></c>, no value type can be be attached to the vector object itself, only to
569 * its "children".<br>
570 * Nevertheless, in many use cases, the root node naturally contains the same data as any other
571 * node in the tree. Therefore, if this class would not support root node data, using
572 * code would for example have to check a \alib{monomem::StringTree;TCursor;Cursor} for pointing
573 * to the root node and in this case get the custom data from somewhere else.<br>
574 * On the other hand, if this class would "insist" in the provision of root node values, then already
575 * with construction of the tree, arguments for the construction of the associated \p{T} object
576 * would have to be provided - even if the root node value was never used.
577 * The provision of initial "dummy" root data, is sometimes not even (easily) possible, and would
578 * sometimes add the need to adjust the custom value type \p{T} to fit into this class.
579 * (In fact, with former versions of \alib, root-node initialization data was mandatory to provide
580 * already with the construction of the tree.)
581 *
582 * Therefore, this class makes the use of root node values optional. After construction of a
583 * \b StringTree, methods \alib{monomem::StringTree;ConstructRootValue} and
584 * methods \alib{monomem::StringTree;DeleteRootValue} may be used to initialize and delete
585 * the optional root nodes' data.
586 *
587 * To prevent memory leaks, in debug-compilations, the following \alib assertions and warnings are
588 * raised:
589 * - \alib{monomem;StringTree;TCursor::Value;Cursor::Value} will raise an assertion if called
590 * on the root node without having set a value.
591 * - \alib{monomem::StringTree;ConstructRootValue} will raise a warning if called twice without
592 * a prior call to \alib{monomem::StringTree;DeleteRootValue}.
593 * - \alib{monomem::StringTree;DeleteRootValue} will raise a warning if called without
594 * a prior call to \alib{monomem::StringTree;ConstructRootValue}.
595 * - The destructor of this class will raise a warning if a root value was set but not deleted.
596 *
597 * \I{#############################################################################################}
598 * # Reference Documentation # {#alib_ns_monomem_stringtree_referencedoc}
599 *
600 * @tparam T The custom value type of elements stored in this container.
601 *
602 * @tparam TNodeMaintainer
603 * A template type that needs to provide an interface as documented with
604 * \alib{monomem;StringTreeNamesDynamic}, which is also the default type
605 * if not specified. For details see
606 * \ref alib_ns_monomem_stringtree_alloc_names "corresponding section" of this
607 * class's documentation.
608 *
609 * @tparam TRecycling
610 * Denotes the type of recycling that is to be performed. Possible values are
611 * \alib{monomem;Recycling::Private} (the default),
612 * \alib{monomem;Recycling::Shared} or \alib{monomem;Recycling::None}.
613 **************************************************************************************************/
614template<typename T,
615 typename TNodeMaintainer= StringTreeNamesDynamic<character>,
616 typename TRecycling = Recycling::Private>
617class StringTree : protected detail::StringTreeBase<T, TNodeMaintainer, TRecycling>
618{
619 #if !defined(ALIB_DOX)
620 protected:
621 friend class Cursor;
622
623 friend class ConstCursor;
624
625 friend TNodeMaintainer;
626
628 using baseNodeKey = typename basetree::NodeKey;
629 using baseNodeBase = typename basetree::NodeBase;
630 using baseNode = typename basetree::Node;
631 using baseCursor = typename basetree::CursorBase;
632 using baseConstCursor = typename basetree::ConstCursorBase;
633 #endif
634
635 public:
636
637 /** The character type of node names and paths strings. This is defined using character type
638 * definition \alib{monomem::StringTreeNamesDynamic;CharacterType} of template type
639 * \p{TNodeMaintainer}. */
640 using CharacterType = typename TNodeMaintainer::CharacterType;
641
642 /** The string type of node names and paths. This is defined using character type definition
643 * \alib{monomem::StringTreeNamesDynamic;CharacterType} of template type
644 * \p{TNodeMaintainer}. */
646
647 /** The sub-string type of paths. This is defined using character type definition
648 * \alib{monomem::StringTreeNamesDynamic;CharacterType} of template type
649 * \p{TNodeMaintainer}. */
651
652 /** This type definition may be used to define an externally managed shared recycler,
653 * which can be passed to the alternative constructor of this class when template
654 * parameter \p{TRecycling} equals \alib{monomem;Recycling::Shared}.
655 * \see
656 * Chapter \ref alib_monomem_containers_recycling_shared of the Programmer's Manual
657 * for this \alibmod. */
658 using TSharedRecycler = typename basetree::TSharedRecycler;
659
660 /** ****************************************************************************************
661 * This public, inner class provides the main interface into outer class \b StringTree.
662 * The class should be considered being similar to a simple pointer or to a lightweight
663 * iterator type, which refers to a tree and a current node.<br>
664 * The class's interface allows the access to a node's name and value and to insert and
665 * remove child nodes.
666 *
667 * Instances of this class can be received with methods #Root and #RecursiveIterator::Node.
668 *
669 * The default constructor creates an invalid object, which has to be initialized by
670 * assigning a valid object prior to its first use.
671 *
672 * \see
673 * For more information on how this class is used, see paragraph
674 * \ref alib_ns_monomem_stringtree_cursor "2.1 Inner Class Cursor"
675 * of the description of class \b %StringTree.
676 *
677 * @tparam TConst If true, internal fields representing the StringTree and the current Node
678 * become \c const and methods which are not declared \c const become
679 * unavailable.
680 *
681 * ## Friends ##
682 * class \alib{monomem;StringTree}
683 ******************************************************************************************/
684 template<bool TConst>
685 class TCursor : protected basetree::template TCursorBase<TConst>
686 {
687 #if !defined(ALIB_DOX)
688 friend class StringTree;
689 #endif
690
691 protected:
692 /** Constant or mutable version of the base tree type, depending on template parameter
693 * \p{TConst} */
694 using cmTree = ATMP_IF_T_F(!TConst, basetree, const basetree);
695
696 /** Constant or mutable version of the base node type, depending on template parameter
697 * \p{TConst} */
698 using cmNode = ATMP_IF_T_F(!TConst, baseNodeBase, const baseNodeBase);
699
700 /** Constant or mutable version of the base cursor type, depending on template parameter
701 * \p{TConst} */
702 using cmCursor = ATMP_IF_T_F(!TConst, baseCursor, baseConstCursor);
703
704 //#### Protected methods (class Cursor) ##############################################
705
706 /**
707 * Internal constructor
708 * @param pTree The \b %StringTree we work on.
709 * @param pNode The node to refer to.
710 */
711 TCursor(cmTree *pTree, cmNode *pNode) noexcept
712 : basetree::template TCursorBase<TConst>(pTree, pNode) {}
713
714 //#### Constructor, comparison operators, etc #####################################
715 public:
716 /** Constant or mutable version of the outer string tree type, depending on template
717 * parameter \p{TConst} */
719
720
721 /** Public constructor. Creates an invalid cursor.
722 * The only way to make a default-constructed instance valid is by
723 * (copy-) assigning another instance. */
724 TCursor() noexcept = default;
725
726 /** Public constructor taking an \ref Export "export value".
727 * TODO(240312 10:46): This method is needed for APath but should be valuable in general.
728 * What is missing here is const/mutable treatment.
729 * @param pTree The tree to use.
730 * @param exportValue A previously exported value. */
731 TCursor(TStringTree& pTree, uinteger exportValue) noexcept
732 : TCursor{ &pTree, reinterpret_cast<cmNode*>(exportValue) }
733 {}
734 /** Copy constructor.
735 * @param src The cursor to copy. */
736 TCursor( const TCursor& src) noexcept
737 : TCursor{ src.tree, src.node }
738 {}
739
740 /** Move constructor.
741 * @param src The cursor to move. */
742 TCursor( TCursor&& src) noexcept
743 : TCursor{ src.tree, src.node }
744 {}
745
746 /** Trivial default copy assign operator.
747 * @return A reference to \c this. */
748 TCursor &operator=(const TCursor &) noexcept = default;
749
750 /** Trivial default move assign operator.
751 * @return A reference to \c this. */
752 TCursor &operator=(TCursor &&) noexcept = default;
753
754 /** Trivial default destructor. */
755 ~TCursor() noexcept = default;
756
757 /**
758 * Conversion operator from <em>TCursor<TConst></em> to <em>TCursor<!TConst></em>.
759 * For const to mutable, this will fail as intended.
760 * @return A constant iterator, if this is a mutable. Otherwise compilation will
761 * duly fail.
762 */
763 operator TCursor<!TConst>() { return TCursor<!TConst>(cmCursor::tree, cmCursor::node); }
764
765 /** Comparison operator.
766 * @param other The object to compare ourselves to.
767 * @return \c true if this and given cursor are equal, \c false
768 * otherwise. */
769 bool operator==(const TCursor &other) const
770 {
771 return cmCursor::node == other.node
772 && cmCursor::tree == other.tree;
773 }
774
775 /** Comparison operator.
776 * @param other The object to compare ourselves to.
777 * @return \c false if this and given cursor are equal, \c true
778 * otherwise. */
779 bool operator!=(const TCursor &other) const
780 {
781 return !((*this) == other);
782 }
783
784 /**
785 * TODO(240312 10:50): This was needed for APath.
786 * Refer to the new corresponding constructor...
787 * @return todo.
788 */
790 {
791 return uinteger(cmCursor::node);
792 }
793
794 /**
795 * Determines if this is a valid object. Cursors may become invalid with
796 * transition methods like #GoToParent, #GoToFirstChild or GoToNextSibling.
797 * An invalid object may be turned into a valid one by either
798 * - assigning a valid object (copy assignment), or
799 * - invoking method #GoToRoot, or
800 * - invoking method #GoToTraversedPath using absolute path addressing.
801 *
802 * Note that the latter is not applicable to a default-constructed objects
803 * (which are also invalid) as with such no \b %StringTree is assigned.
804 *
805 * @return \c true if this is a valid cursor.
806 * If invalid, \c false is returned and this object must not be used.
807 */
808 bool IsValid() const
809 {
810 return cmCursor::node != nullptr;
811 }
812
813 /**
814 * Returns the opposite of #IsValid.
815 *
816 * @return \c true if this is an invalid cursor that must not be used,
817 * \c false otherwise.
818 */
819 bool IsInvalid() const
820 {
821 return !IsValid();
822 }
823
824 //#### Tree navigation inplace, returning status #########################
825 /**
826 * Creates a cursor value representing the same node like this pointer.
827 * @return A clone of this cursor.
828 */
830 {
831 return TCursor(cmCursor::tree, cmCursor::node);
832 }
833
834 /** Returns a cursor to the root node of the tree.
835 * @return A cursor representing the root node of the tree this pointer
836 * represents. */
837 TCursor Root() const
838 {
839 return TCursor(cmCursor::tree, &cmCursor::tree->root.root);
840 }
841
842 /** Moves this cursor to the root node of the tree.
843 * @return A reference to this object */
845 {
846 cmCursor::node = &cmCursor::tree->root.root;
847 return *this;
848 }
849
850 /**
851 * Creates a cursor value representing the parent node of the
852 * node represented by this object.
853 *
854 * If this object represents the root node of the tree, the returned cursor
855 * is invalid.
856 *
857 * @return A cursor pointing to the parent node of the node represented
858 * by this cursor.
859 */
861 {
862 ALIB_ASSERT_ERROR(IsValid(), "MONOMEM/STRINGTREE",
863 "Invalid StringTree::Cursor.")
864 return TCursor(cmCursor::tree, cmCursor::node->parent);
865 }
866
867 /**
868 * Moves this cursor to the parent of the current node.
869 * If this is the root node, this object becomes invalid.
870 *
871 * @return *this to allow concatenated calls
872 */
874 {
875 ALIB_ASSERT_ERROR(IsValid(), "MONOMEM/STRINGTREE",
876 "Invalid StringTree::Cursor.")
877 cmCursor::node = cmCursor::node->parent;
878 return (*this);
879 }
880
881 /**
882 * Returns a cursor value that represents the next sibling of the node
883 * represented this cursor.
884 * If the node has no next sibling, an invalid cursor is returned.
885 *
886 * @return A cursor object representing the next sibling of the node
887 * represented by this object.
888 */
890 {
891 return TCursor(cmCursor::tree, HasNextSibling() ? cmCursor::node->next()
892 : nullptr);
893 }
894
895 /**
896 * Moves this cursor to the next sibling of the represented node.
897 * If the node has no next sibling, this cursor becomes invalid.
898 * The latter is always true if this is the root node of the tree.
899 *
900 * @return \c true if this cursor was moved,
901 * \c false if the represented node has no next sibling.
902 */
904 {
905 // go to node next and check for hook?
906 if (HasNextSibling())
907 {
908 cmCursor::node = cmCursor::node->next();
909 return true;
910 }
911 cmCursor::node = nullptr;
912 return false;
913 }
914
915 /**
916 * Returns a cursor value that represents the previous sibling of the node
917 * represented this cursor.
918 * If the node has no previous sibling, an invalid cursor is returned.
919 *
920 * @return A cursor object representing the previous sibling of the node
921 * represented by this object.
922 */
924 {
925 return TCursor(cmCursor::tree, HasPreviousSibling() ? cmCursor::node->prev()
926 : nullptr);
927 }
928
929 /**
930 * Moves this cursor to the previous sibling of the represented node.
931 * If the node has no previous sibling, this cursor becomes invalid.
932 * The latter is always true if this is the root node of the tree.
933 *
934 * @return \c true if this cursor was moved,
935 * \c false if the represented node has no previous sibling.
936 */
938 {
939 if( HasPreviousSibling() )
940 {
941 cmCursor::node= cmCursor::node->prev();
942 return true;
943 }
944 cmCursor::node= nullptr;
945 return false;
946 }
947
948 /**
949 * Returns a cursor object that represents the first child of the node
950 * represented.
951 * If the represented node has no children, an invalid cursor is returned.
952 *
953 * @return A cursor representing the first child of the node this cursor points to.
954 */
956 {
957 return TCursor( cmCursor::tree, HasChildren() ? cmCursor::node->children.first()
958 : nullptr );
959 }
960
961 /**
962 * Moves this cursor to the first child of its represented node.
963 * If the represented node has no children, this cursor becomes invalid.
964 *
965 * @return \c true if the cursor was moved, \c false if the represented node
966 * has no children.
967 */
969 {
970 if( HasChildren() )
971 {
972 cmCursor::node= cmCursor::node->children.first();
973 return true;
974 }
975 cmCursor::node= nullptr;
976 return false;
977 }
978
979 /**
980 * Returns a cursor value that represents the last child of the node
981 * represented.
982 * If the represented node has no children, an invalid cursor is returned.
983 *
984 * @return A cursor representing the last child of the node represented
985 * by this cursor.
986 */
988 {
989 return TCursor( cmCursor::tree, HasChildren() ? cmCursor::node->children.last()
990 : nullptr );
991 }
992
993 /**
994 * Moves this cursor to the last child of its represented node.
995 * If the represented node has no children, this cursor becomes invalid.
996 *
997 * @return \c true if the cursor was moved, \c false if the represented node
998 * has no children.
999 */
1001 {
1002 if( HasChildren() )
1003 {
1004 cmCursor::node= cmCursor::node->children.last();
1005 return true;
1006 }
1007 cmCursor::node= nullptr;
1008 return false;
1009 }
1010
1011 /**
1012 * Searches a child with the given name and returns a cursor to it.
1013 * If no child with this name exists, the returned cursor is invalid
1014 *
1015 * The given \p{name} is not considered a path and is not checked for being <c>"."</c>
1016 * or <c>".."</c> or if it contains a separator character.
1017 * Children with such name can not exist and hence can't be found. However, in
1018 * debug builds, an \ref ALIB_WARNING is reported.
1019 *
1020 * @param name The name of the child to search.
1021 * @return A cursor representing the last child of the node represented
1022 * by this cursor.
1023 */
1024 TCursor Child( const NameType& name ) const
1025 {
1026 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE", "Invalid StringTree::Cursor." )
1027 ALIB_DBG( cmCursor::tree->checkChildName( name ); ) // gives warning
1028
1029 return TCursor(cmCursor::tree, cmCursor::node->findChild(cmCursor::tree, name));
1030 }
1031
1032 /**
1033 * Searches a child with the given name and moves this cursor to it.
1034 * If no child with this name exists, the cursor does not change and
1035 * \c false is returned.
1036 *
1037 * The given \p{name} is not considered a path and is not checked for being <c>"."</c>
1038 * or <c>".."</c> or if it contains a separator character.
1039 * Children with such name can not exist and hence can't be found. However, in
1040 * debug builds, an \ref ALIB_WARNING is reported.
1041 *
1042 * @param name The name of the child to search.
1043 * @return \c true if the child existed and this object changed, \c false
1044 * otherwise.
1045 */
1046 bool GoToChild( const NameType& name )
1047 {
1048 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE", "Invalid StringTree::Cursor." )
1049 ALIB_DBG( cmCursor::tree->checkChildName( name ); )
1050
1051 cmNode* child= cmCursor::node->findChild( cmCursor::tree, name );
1052 if(child)
1053 {
1054 cmCursor::node= child;
1055 return true;
1056 }
1057 return false;
1058 }
1059
1060 /**
1061 * Moves this cursor to the child with given \p{name}.
1062 * If no child with this name exists, one will be created.
1063 *
1064 * If the given \p{childName} is invalid (equals to <c>"."</c> or
1065 * <c>".."</c> or contains the separation character), then still \c true is returned,
1066 * but this cursor becomes invalid.
1067 * In addition, with debug builds, an \ref ALIB_WARNING is reported.
1068 *
1069 * @tparam TArgs Types of variadic parameters given with parameter \p{args}.
1070 * @param name The name of the desired child.
1071 * @param args Variadic parameters to be forwarded to constructor of custom type
1072 * \p{T} in the case a child is created.
1073 * @return A pair of a cursor pointing to the child and a boolean that equals
1074 * \c false if the child was found, and \c true if a child was created.
1075 * If the given name was invalid, the returned cursor will be invalid
1076 * while the boolean still indicates "not found" (aka \c true).
1077 */
1078 template<typename... TArgs>
1079 std::pair<TCursor, bool> CreateChildIfNotExistent( const NameType& name,
1080 TArgs&&... args )
1081 {
1082 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE", "Invalid StringTree::Cursor." )
1083
1084 if( !cmCursor::tree->checkChildName( name ) )
1085 return std::make_pair( TCursor(cmCursor::tree, nullptr), true );
1086
1087 auto result= cmCursor::node->findOrCreateChild( cmCursor::tree, name,
1088 std::forward<TArgs>(args)... );
1089
1090 return std::make_pair( TCursor( cmCursor::tree, result.first ), result.second );
1091 }
1092
1093 /**
1094 * Moves this cursor to the child with given \p{name}.
1095 * If no child with this name exists, one will be created.
1096 *
1097 * If the given \p{childName} is invalid (equals to <c>"."</c> or
1098 * <c>".."</c> or contains the separation character), then still \c true is returned,
1099 * but this cursor becomes invalid.
1100 * In addition, with debug builds, an \ref ALIB_WARNING is reported.
1101 *
1102 * @tparam TArgs Types of variadic parameters given with parameter \p{args}.
1103 * @param name The name of the desired child.
1104 * @param args Variadic parameters to be forwarded to constructor of custom type
1105 * \p{T} in the case a child is created.
1106 * @return \c false if the child was found, and \c true if one was created or the given
1107 * child name was invalid.
1108 */
1109 template<typename... TArgs>
1110 bool GoToCreateChildIfNotExistent(const NameType& name, TArgs&&... args)
1111 {
1112 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE", "Invalid StringTree::Cursor." )
1113
1114 if( !cmCursor::tree->checkChildName( name ) )
1115 {
1116 cmCursor::node= nullptr;
1117 return true;
1118 }
1119
1120 auto result= cmCursor::node->findOrCreateChild( cmCursor::tree, name,
1121 std::forward<TArgs>(args)... );
1122
1123 cmCursor::node= result.first;
1124 return result.second;
1125 }
1126
1127 /**
1128 * Follows the given \p{path} from the currently represented node to the target
1129 * node.
1130 *
1131 * The method supports absolute and relative path addressing: If \p{path} begins
1132 * with a separation character, then the transition starts with the root node of the
1133 * \b %StringTree. Furthermore, child name <c>"."</c> is ignored and just skipped
1134 * while a name of <c>".."</c> addresses the parent node during the transition.
1135 * Repeated separation characters are ignored.<br>
1136 * If, while processing the path string, the root node is found an the next
1137 * path element is "..", this element is ignored and processing continues.
1138 * As a sample, assuming that nodes \e /a and \e /b exist, the paths:
1139 *
1140 * /a/../b
1141 * and
1142 *
1143 * /a/../../b
1144 * both evaluate to
1145 *
1146 * /b
1147 *
1148 * Relative paths must not be used on \ref TCursor::IsValid "invalid" cursors. Doing so
1149 * is undefined behavior and raises an \alib assertion in debug-compilations.
1150 *
1151 * If a child along the path does not exist, the traversal is ended and the remaining
1152 * portion of the path is returned.
1153 *
1154 * \note
1155 * If parameter \p{path} is a temporary object, the resulting \b Substring must
1156 * not be used, as it refers to the given string's buffer. In any case, its
1157 * length can still be compared to \c 0 to evaluate success of the traversal.
1158 *
1159 * @param path The path to follow, starting with the node this pointer represents.
1160 *
1161 * @return A pair of a cursor pointing to last child not of the existing portion
1162 * of the given \p{path}, and a substring that contains the non-existing
1163 * portion of a path, or is empty if the complete path existed.
1164 */
1165 std::pair<TCursor, SubstringType> TraversePath( const NameType& path ) const
1166 {
1167 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE", "Invalid StringTree::Cursor." )
1168 SubstringType remainingPath(path);
1169 cmNode* grandChild= cmCursor::followPath( remainingPath );
1170 return std::make_pair( TCursor(cmCursor::tree, grandChild), remainingPath );
1171 }
1172
1173 /**
1174 * Same as #TraversePath, but moves this cursor instead of returning one.
1175 *
1176 * @param path The path to move this cursor along.
1177 * @return The unconsumed portion of the path.
1178 * An empty \b Substring if the path existed.
1179 */
1181 {
1182 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE", "Invalid StringTree::Cursor." )
1183 SubstringType remainingPath(path);
1184 cmCursor::node= cmCursor::followPath( remainingPath );
1185 return remainingPath;
1186 }
1187
1188 /**
1189 * Follows the given path and creates non-existing children along the way.
1190 *
1191 * Child names <c>"."</c> and <c>".."</c> are allowed and respected same
1192 * as documented with method #TraversePath.
1193 *
1194 * New child nodes are constructed by forwarding the given \p{args}. Existing children
1195 * remain untouched.
1196 *
1197 * @tparam TArgs Types of variadic parameters given with parameter \p{args}.
1198 * @param path The path to move along.
1199 * @param args Variadic parameters to be forwarded to constructor of each node
1200 * that is created.
1201 * @return A <c>std::pair</c> containing a resulting \b Cursor and the number of nodes
1202 * created.
1203 */
1204 template<typename... TArgs>
1205 std::pair<TCursor, integer> CreatePathIfNotExistent( const NameType& path,
1206 TArgs&&... args )
1207 {
1208 ALIB_ASSERT_ERROR( IsValid() || path.CharAtStart() == cmCursor::tree->separator,
1209 "MONOMEM/STRINGTREE",
1210 "Invalid StringTree::Cursor given with relative path addressing." )
1211
1212 auto result= cmCursor::followPathCreate( path, std::forward<TArgs>(args)... );
1213
1214 return std::make_pair( TCursor(cmCursor::tree, result.first), result.second );
1215 }
1216
1217 /**
1218 * Follows the given path and creates non-existing children along the way.
1219 *
1220 * Child names <c>"."</c> and <c>".."</c> are allowed and respected same
1221 * as in #TraversePath.
1222 *
1223 * New child nodes are constructed by forwarding the given \p{args}. Existing children
1224 * remain untouched.
1225 *
1226 * @tparam TArgs Types of variadic parameters given with parameter \p{args}.
1227 * @param path The path to move along.
1228 * @param args Variadic parameters to be forwarded to constructor of each node
1229 * that is created.
1230 * @return The number of nodes created.
1231 */
1232 template<typename... TArgs>
1234 TArgs&&... args )
1235 {
1236 ALIB_ASSERT_ERROR( IsValid() || path.CharAtStart() == cmCursor::tree->separator,
1237 "MONOMEM/STRINGTREE",
1238 "Invalid StringTree::Cursor given with relative path addressing." )
1239
1240 auto result= cmCursor::followPathCreate( path, std::forward<TArgs>(args)... );
1241 cmCursor::node= result.first;
1242 return result.second;
1243 }
1244
1245 //##### Cursor Interface #######################################################
1246 /**
1247 * Returns the name of the represented node.
1248 * Note that the concatenated names of recursive child nodes, separated by
1249 * \p{TSeparator} constitute a \e path.
1250 *
1251 * @return A constant reference to the name of the represented node.
1252 */
1253 const NameType& Name() const
1254 {
1255 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE", "Invalid StringTree::Cursor." )
1256 return cmCursor::node->name.key;
1257 }
1258
1259 /**
1260 * Returns the three that this pointer is created of.
1261 *
1262 * @return The tree that this object refers to.
1263 */
1265 {
1266 ALIB_ASSERT_ERROR( cmCursor::tree, "MONOMEM/STRINGTREE",
1267 "StringTree::Cursor is not initialized." )
1268 return *static_cast<StringTree*>(cmCursor::tree);
1269 }
1270
1271 /**
1272 * Returns the three that this pointer is created of.
1273 *
1274 * @return The tree that this object refers to.
1275 */
1276 const StringTree& Tree() const
1277 {
1278 ALIB_ASSERT_ERROR( cmCursor::tree, "MONOMEM/STRINGTREE",
1279 "StringTree::Cursor is not initialized." )
1280 return *static_cast<const StringTree*>(cmCursor::tree);
1281 }
1282
1283 #if defined(ALIB_DOX)
1284 /** Retrieves a reference to the templated value of type \p{T} stored
1285 * in the represented node.
1286 * \note This method is only available if template parameter \p{TConst} is false.
1287 * @return The current node's value. */
1288 T& Value();
1289 #else
1290 template<bool TEnableIf= !TConst>
1291 ATMP_T_IF(T&, TEnableIf)
1292 Value()
1293 {
1294 ALIB_ASSERT_ERROR( !IsRoot() || cmCursor::tree->dbgRootDataSet > 0, "MONOMEM/STRINGTREE",
1295 "Root node has no value. Either this operation is unwanted or root node's value\n"
1296 "has to be explicitly set using SetRootNode(...)" )
1297 return static_cast<baseNode*>(cmCursor::node)->data;
1298 }
1299 #endif // ALIB_DOX
1300
1301 /** Retrieves a constant reference to the templated value of type \p{T} stored in
1302 * the represented node.
1303 * @return The current node's value. */
1304 const T& Value() const
1305 {
1306 ALIB_ASSERT_ERROR( !IsRoot() || cmCursor::tree->dbgRootDataSet > 0, "MONOMEM/STRINGTREE",
1307 "Root node has no value. Either this operation is unwanted or root node's value\n"
1308 "has to be explicitly set using SetRootNode(...)" )
1309 return static_cast<const baseNode*>(cmCursor::node)->data;
1310 }
1311
1312 /**
1313 * Returns \c true if this cursor represents the root node of the
1314 * \b %StringTree, \c false otherwise.
1315 * @return \c true if this object represents the root node, \c false otherwise.
1316 */
1317 bool IsRoot() const
1318 {
1319 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE", "Invalid StringTree::Cursor." )
1320 return cmCursor::node->isRoot();
1321 }
1322
1323 /**
1324 * Determines the depth of the node represented by this object. This is done by
1325 * counting the iterations needed to reach the root node of the tree.
1326 * @return The distance from this node to the root node.
1327 */
1328 int Depth() const
1329 {
1330 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE", "Invalid StringTree::Cursor." )
1331 return cmCursor::node->depth();
1332 }
1333
1334 /**
1335 * Returns \c true if the represented node has at least one direct child.
1336 * @return \c true if the current node has children, \c false otherwise.
1337 */
1338 bool HasChildren() const
1339 {
1340 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE", "Invalid StringTree::Cursor." )
1341 return cmCursor::node->qtyChildren != 0;
1342 }
1343
1344 /**
1345 * Returns the number of direct children of the represented node.<br>
1346 * Note that this method runs in constant time.
1347 * @return The number of direct children of the represented node.
1348 */
1350 {
1351 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE", "Invalid StringTree::Cursor." )
1352 return cmCursor::node->qtyChildren;
1353 }
1354
1355 /**
1356 * Evaluates if the node represented by this object has a next sibling in its
1357 * parent's list of children.
1358 * @return \c true if a next sibling to this object's represented node exists,
1359 * \c false otherwise.
1360 */
1361 bool HasNextSibling() const
1362 {
1363 return !IsRoot()
1364 && !cmCursor::node->parent->children.isLast( cmCursor::node );
1365 }
1366
1367 /**
1368 * Evaluates if the node represented by this object has a previous sibling in its
1369 * parent's list of children.
1370 * @return \c true if a previous sibling to this object's represented node exists,
1371 * \c false otherwise.
1372 */
1374 {
1375 return !IsRoot()
1376 && !cmCursor::node->parent->children.isFirst( cmCursor::node );
1377 }
1378
1379 /**
1380 * Writes the absolute path to the represented node (including the represented node's
1381 * name) to the given \b %AString.<br>
1382 * If this node represents the root node, then nothing is written but a single
1383 * separation character.
1384 *
1385 * While the implementation of this method is as efficient as possible (to avoid
1386 * insertions at the beginning of the target string while moving to the destination/root
1387 * node, internally a local node-stack is created first, which then is traversed
1388 * top-down), still in many situations, it is recommended to search for other ways to
1389 * keep track of the current path of a node and modify and re-use such path.
1390 * For this, class \alib{monomem;StringTree::RecursiveIterator}, optionally
1391 * allows to maintain a string representing the current path with every iteration.
1392 *
1393 * \see Overloaded version <b>AssemblePath(AString&,TCursor<TConst>&,lang::CurrentData)</b>,
1394 * which allows to create a relative path from a parent node to this node.
1395 *
1396 * @param targetString The string buffer to append the path to.
1397 * @param targetData Denotes whether \p{target} should be cleared prior to
1398 * appending the path. Defaults to \b CurrentData::Clear.
1399 * @return The given \b AString to allow concatenated operations on it.
1400 */
1402 lang::CurrentData targetData
1403 = lang::CurrentData::Clear ) const
1404 {
1405 if( targetData == lang::CurrentData::Clear )
1406 targetString.Reset();
1407
1408 return cmCursor::node->assemblePath( targetString, cmCursor::node, nullptr,
1409 cmCursor::tree->separator );
1410 }
1411
1412 /**
1413 * Same as #AssemblePath but accepts a parent node to stop at, instead of the root node.
1414 * The path created is a relative path from the \p{parent} to the represented node,
1415 * hence it does \b not include the parent' name and also does \b not start with the
1416 * separation character. The latter is true even if the given \p targetParent represents
1417 * the root node. In this case the path is a relative path from the root node \c '/'
1418 * to the child.
1419 *
1420 * If the given \p{parent} is not found within the list of parent nodes, then
1421 * an absolute path from the tree's root to the represented node is returned.
1422 *
1423 *
1424 * @param targetString The string buffer to append the path to.
1425 * @param parent Denotes the parent node to start a relative path from.
1426 * @param targetData Denotes whether \p{target} should be cleared prior to
1427 * appending the path. Defaults to \b CurrentData::Clear.
1428 * @return The given \b AString to allow concatenated operations on it.
1429 */
1431 const TCursor& parent,
1432 lang::CurrentData targetData
1433 = lang::CurrentData::Clear ) const
1434 {
1435 if( targetData == lang::CurrentData::Clear )
1436 targetString.Reset();
1437
1438 return cmCursor::node->assemblePath( targetString, cmCursor::node, parent.node,
1439 cmCursor::tree->separator );
1440 }
1441
1442 //##### Cursor child creation #####################################################
1443 /**
1444 * Creates and returns a child node. If a node already exists, nothing is done and
1445 * \c nullptr is returned as this is considered an error.
1446 *
1447 * If the child name is illegal (equal to <c>"."</c> or <c>".."</c> or contains a
1448 * separation character), an \alib warning is raised and an invalid cursor
1449 * is returned.
1450 *
1451 * Template parameter \p{TCheck} may be used to suppress the search for an
1452 * existing child with the same name, as well as the check for correctness of the
1453 * given child name.
1454 * This tremendously improves the execution performance of this method.
1455 *
1456 * \attention Setting template parameter \p{TCheck} to \c false and inserting
1457 * child nodes with the same name, sets a \b %StringTree to an
1458 * undefined state.
1459 *
1460 * @tparam TCheck If \c false, no check for an existing child with the same name is
1461 * performed.
1462 * @tparam TArgs Types of variadic parameters given with parameter \p{args}.
1463 * @param childName The name of the child
1464 * @param args Variadic parameters to be forwarded to constructor of custom
1465 * type \p{T} of the child created.
1466 *
1467 * @return A new cursor object representing the created child node.
1468 * If the given \p{childName} was invalid or the child existed already,
1469 * the returned object is invalid.
1470 */
1471 template<bool TCheck =true, typename... TArgs>
1472 TCursor CreateChild( const NameType& childName, TArgs&&... args ) const
1473 {
1474 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE", "Invalid StringTree::Cursor." )
1475 if constexpr (TCheck)
1476 {
1477 // check name
1478 if( !baseCursor::tree->checkChildName( childName ) )
1479 {
1480 ALIB_WARNING( "STRINGTREE", "Illegal child name {!Q}", childName )
1481 return Cursor( baseCursor::tree, nullptr );
1482 }
1483
1484 // check existence
1485 if( baseCursor::node->qtyChildren > 0
1486 && baseCursor::tree->nodeTable.Contains( baseNodeKey( baseCursor::node, childName) ))
1487 return Cursor( baseCursor::tree, nullptr );
1488 }
1489
1490 baseNode* child= &baseCursor::tree->nodeTable.EmplaceUnique( baseCursor::node, childName,
1491 std::forward<TArgs>(args)... )
1492 .Value();
1493 TNodeMaintainer::InitializeNode( *baseCursor::tree, *child );
1494
1495 baseCursor::node->children.pushEnd( child );
1496 ++baseCursor::node->qtyChildren;
1497
1498 return TCursor( baseCursor::tree, child );
1499 }
1500
1501 //##### Cursor deletion #######################################################
1502 /**
1503 * Searches and deletes the child named \p{childName} from the node that this object
1504 * refers to. This object itself is not changed.
1505 *
1506 * \see
1507 * Overloaded version of this method that accepts a cursor referring to
1508 * the child in question.
1509 *
1510 *
1511 * @param childName The name of the desired child.
1512 * @return \c true if the child existed and was deleted, \c false otherwise.
1513 */
1514 bool DeleteChild( const NameType& childName ) const
1515 {
1516 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE", "Invalid StringTree::Cursor." )
1517 if( baseCursor::node->qtyChildren == 0 )
1518 return false;
1519
1520 auto handle= baseCursor::tree->nodeTable.Extract( baseNodeKey( baseCursor::node, childName) );
1521 if( handle.IsEmpty() )
1522 return false;
1523
1524 handle.Value().deleteChildren( baseCursor::tree );
1525
1526 TNodeMaintainer::FreeNode( *baseCursor::tree, handle.Value() );
1527 handle.Value().remove();
1528
1529 --baseCursor::node->qtyChildren;
1530 return true;
1531 }
1532
1533 /**
1534 * Deletes the child represented by the given cursor \p{child} from the
1535 * node that this cursor refers to.
1536 * After the invocation the given \p{child} refers to its next sibling. If no
1537 * such sibling exists, \p{child} becomes invalid.
1538 * This cursor itself is not changed.
1539 *
1540 * \note
1541 * This method is handy to implement forward iterations through children of
1542 * a parent node with the aim to delete certain child nodes.
1543 * No corresponding version of this method exists that moves the given
1544 * \p{child} pointer to its previous sibling. For reverse iterations, a
1545 * \ref Clone "clone" of the \p{child} argument has to be passed.
1546 * However, any overhead caused by such temporary object creation will be
1547 * optimized out by modern C++ compilers.
1548 *
1549 * @param child Deletes the child represented by the given node.
1550 */
1551 void DeleteChild( TCursor& child ) const
1552 {
1553 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE",
1554 "Invalid StringTree::Cursor." )
1555 ALIB_ASSERT_ERROR( child.IsValid(), "MONOMEM/STRINGTREE",
1556 "Invalid StringTree::Cursor given for parameter 'child'." )
1557 cmNode* nodeToDelete= child.node;
1558 child.GoToNextSibling();
1559 baseCursor::node->deleteChild( baseCursor::tree, nodeToDelete );
1560 }
1561
1562 /**
1563 * Deletes the children of the node that this cursor refers to.
1564 * This object itself is not changed.
1565 *
1566 * @return The number of children that were deleted.
1567 */
1569 {
1570 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE", "Invalid StringTree::Cursor." )
1571 return baseCursor::node->deleteChildren( baseCursor::tree );
1572 }
1573
1574 /**
1575 * Deletes the branch that this cursor refers to from the tree.
1576 * If this cursor does not represent the root node, then after the operation,
1577 * it refers to the parent of the current node.<br>
1578 * If the represented node is the root node, only the children are deleted and this
1579 * object remains representing the root node. Note that in this case any explicitly
1580 * set custom value of the root node is \b not deleted. For this, exclusively methods
1581 * #ConstructRootValue and #DeleteRootValue are to be used.
1582 *
1583 * \note
1584 * If this method is invoked on an object returned by method
1585 * #RecursiveIterator::Node, the invoking iterator becomes invalid.<br>
1586 * To avoid this, method #RecursiveIterator::DeleteNode is to be used.
1587 *
1588 * @return
1589 * The total number of nodes deleted. Can be zero, in case this object represents
1590 * the root node and this node has no children.
1591 */
1593 {
1594 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE", "Invalid StringTree::Cursor." )
1595 if( baseCursor::node->isRoot() )
1596 return baseCursor::node->deleteChildren( baseCursor::tree );
1597
1598 cmNode * child= baseCursor::node;
1599 baseCursor::node= baseCursor::node->parent;
1600 return baseCursor::node->deleteChild( baseCursor::tree, child );
1601 }
1602 }; // inner class TCursor
1603
1604 /** The mutable version of type \alib{monomem;StringTree::TCursor<TConst>}. */
1606
1607 /** The constant version of type \alib{monomem;StringTree::TCursor<TConst>}. */
1609
1610
1611 /** ********************************************************************************************
1612 * This public, inner class can be used to recursively iterate through the nodes of
1613 * outer class \b StringTree.<br>
1614 * The type does <b>not</b> apply to the concept of \c std::iterator_traits.
1615 * The rationale for this is the fact that mechanics for sorting the child nodes are
1616 * provided, which requires allocation of more resources than usual container iterators do.
1617 * Therefore, objects of this type are not supposed to be temporary and
1618 * created "on the fly", e.g. in C++ range based loops.
1619 * Instead, instances should rather be created once and then re-used with subsequent
1620 * iterations.
1621 *
1622 * The sorting of child nodes is optional and can be changed prior to each recursion.
1623 * A built-in comparison function which works on node names (path names) allows to choose
1624 * ascending and descending order and to ignore or be sensitive about letter case.
1625 * Besides this, custom comparison functions that take a combination of arbitrary node
1626 * attributes, including a node's value of template type \p{T} can be established.
1627 * See overloaded methods #SetSorting for details on this topic.
1628 *
1629 * Objects of this type can be initialized, respectively reset to distinct start nodes by
1630 * providing objects of
1631 * - type \b %StringTree,
1632 * - type \b %StringTree::Cursor or
1633 * - other objects of this type itself,
1634 *
1635 * to overloaded methods #Initialize.
1636 *
1637 * The maximum depth of recursion may be limited with optional parameter \p{depth}
1638 * found with each overloaded version of #Initialize.
1639 * During the iteration, the recursion can be individually selected per node visited.
1640 * This is done by using either of methods #Next or #NextSibling to proceed.
1641 * Furthermore, method #NextParentSibling allows to skip the rest of the current iteration
1642 * branch.<br>
1643 * The end of an iteration is detected with method #IsValid.
1644 *
1645 * The children of a node can be iterated in a sorted fashion. To enable and disable
1646 * sorting, various overloads of #SetSorting exist. These methods may be invoked any
1647 * time during the iteration. Whenever a recursion in iteration occurs, the most recent
1648 * settings of sorting are respected for the list of children of the node that is
1649 * processed with that recursion.
1650 *
1651 * Finally, the generation of a string representing the actual path to the current
1652 * iteration node, relative to the iteration's start node can be activated.
1653 * See method #SetPathGeneration for more information about this feature.
1654 *
1655 * \see
1656 * For more information on how this class is used, see paragraph
1657 * \ref alib_ns_monomem_stringtree_iterator "2.2 Inner Class RecursiveIterator"
1658 * of the description of class \b %StringTree.
1659 *
1660 * ## Friends ##
1661 * class \alib{monomem;StringTree}
1662 **********************************************************************************************/
1663 template<bool TConst>
1665 {
1666 protected:
1667
1668 /** Constant or mutable version of the base tree type, depending on template parameter
1669 * \p{TConst} */
1670 using cmTree = ATMP_IF_T_F(!TConst, StringTree , const StringTree );
1671
1672 /** Constant or mutable version of the base node type, depending on template parameter
1673 * \p{TConst} */
1674 using cmNode = ATMP_IF_T_F(!TConst, baseNodeBase, const baseNodeBase );
1675
1676 /** Constant or mutable version of the base Cursor type, depending on template parameter
1677 * \p{TConst} */
1679
1680 //######################################################################################
1681 // Inner type RecursionData
1682 //######################################################################################
1683 /** Protected, internal struct used to store the data of recursive iterations. */
1685 {
1686 /**
1687 * Combines a node hook and and a current vector index used to remember the
1688 * current child in unsorted, respectively sorted mode.
1689 */
1690 union
1691 {
1692 /** The current child of the current node in case of unsorted access
1693 * If this is pointing to the end of the child map, then
1694 * the actual node itself is selected by this RecursiveIterator. */
1696
1697 /** The current child index in case of sorted access.
1698 * A value of <c>size_t(-1)</c> indicates that
1699 * the actual node itself is selected. */
1700 size_t sorted;
1701
1702 } actChild;
1703
1704 #if defined(ALIB_DOX)
1705 /** The child hook of the parent node, used with unsorted iteration.
1706 * Note that this is declared \c const, in case template param \p{TConst} equals
1707 * \c true.*/
1709 #else
1712 childrenUnsorted;
1713 #endif
1714
1715 /** A pointer to a dynamically allocated vector of children used with sorting. */
1716 std::vector<cmNode*> childrenSorted;
1717
1718 /** Copied from
1719 * \alib{monomem::StringTree<T;TNodeMaintainer;TRecycling>;RecursiveIterator::nextCustomSorter}
1720 * with every recursion step. */
1721 bool (*customSorter)(const cmCursor&, const cmCursor&);
1722
1723 /** Copied from
1724 * \alib{monomem::StringTree<T;TNodeMaintainer;TRecycling>;RecursiveIterator::nextIsSorting}
1725 * with every recursion step. */
1727
1728 /** Copied from
1729 * \alib{monomem::StringTree<T;TNodeMaintainer;TRecycling>;RecursiveIterator::nextSortingIsDescending}
1730 * with every recursion step. */
1732
1733 /** Copied from
1734 * \alib{monomem::StringTree<T;TNodeMaintainer;TRecycling>;RecursiveIterator::nextSortingIsCaseSensitive}
1735 * with every recursion step. */
1737
1738
1739 /** Trivial default constructor. */
1740 RecursionData() noexcept = default;
1741
1742 /** Trivial default copy constructor. */
1743 RecursionData( const RecursionData& ) = default;
1744
1745 /** Trivial default move constructor. */
1746 RecursionData( RecursionData&& ) noexcept = default;
1747
1748 /** Trivial default copy assign operator.
1749 * @return A reference to \c this. */
1750 RecursionData& operator=( const RecursionData& ) = default;
1751
1752 /** Trivial default move assign operator.
1753 * @return A reference to \c this. */
1754 RecursionData& operator=( RecursionData&& ) noexcept = default;
1755
1756 /** Trival default destructor */
1757 ~RecursionData() noexcept = default;
1758 }; // inner struct RecursionData
1759
1760 //##### RecursiveIterator members #####################################################
1761
1762 /** The \b %StringTree this iterator belongs to. */
1763 cmTree* tree = nullptr;
1764
1765 /** The pointer to the actual node. */
1766 cmNode* node;
1767
1768 /**
1769 * A stack holding the recursive list of unsorted or sorted children and the
1770 * hook to the current child. Implemented as a vector in combination with member #actDepth,
1771 * to reuse allocated storage space during iteration and when this iterator is
1772 * re-used (freshly initialized).
1773 */
1774 std::vector<RecursionData> stack;
1775
1776 /**
1777 * The current depth of the iteration (and usage but not size of field #stack).
1778 * set to \c -1 to if iteration is finished, respectively this iterator was not
1779 * initialized.
1780 */
1781 size_t actDepth = size_t(-1);
1782
1783 /** The path to the actual node (excluding the name of the actual node).
1784 * If this object is \e nulled, no paths are generated. */
1785 AString actPath;
1786
1787 /** The requested depth of iteration recursion. */
1788 unsigned int recursionDepth =(std::numeric_limits<unsigned int>::max)();
1789
1790 /** A pointer to a user-defined comparison function for path names. */
1791 bool (*nextCustomSorter)(const cmCursor&, const cmCursor&) = nullptr;
1792
1793 /** Denotes if the children are iterated in a sorting fashion or not. */
1794 bool nextIsSorting = false;
1795
1796 /** The sort order (used with built-in sorting by node name). */
1797 bool nextSortingIsDescending = false;
1798
1799 /** The case sensitivity of the sort (used with built-in sorting by node name). */
1800 bool nextSortingIsCaseSensitive = false;
1801
1802 // #### RecursiveIterator Constructor/Destructor ########################################
1803 public:
1804 /** Default constructor. */
1806
1807 /** Trivial copy constructor. */
1809
1810 /** Trivial default move constructor. */
1812
1813 /** Trivial default copy assign operator.
1814 * @return A reference to \c this. */
1815 TRecursiveIterator& operator=( const TRecursiveIterator& ) = default;
1816
1817 /** Trivial default move assign operator.
1818 * @return A reference to \c this. */
1819 TRecursiveIterator& operator=( TRecursiveIterator&& ) = default;
1820
1821
1822 /** Destructor. */
1824
1825 // #### RecursiveIterator Interface ###################################################
1826 /**
1827 * With this method, the assembly of a string representing the path from the
1828 * node used to initialize this iterator to the actual node, is activated or
1829 * deactivated.<br>
1830 * If activated, the path to the current node can be received using overloaded
1831 * methods #CurrentPath and #FullPath.
1832 *
1833 * The invocation of the method invalidates this iterator. Note that the
1834 * path generation can be enabled and disabled with the optional parameter
1835 * of the overloaded #Initialize methods.
1836 *
1837 * @param pathGeneration Denotes whether the path should be generated or not.
1838 */
1839 void SetPathGeneration( lang::Switch pathGeneration )
1840 {
1841 Invalidate();
1842 actPath.Reset( pathGeneration == lang::Switch::On ? EmptyString()
1843 : NullString() );
1844 }
1845
1846 /**
1847 * Resets this iterator to work with the given \b %StringTree.
1848 * Initializes recursive iteration to the tree's root node.
1849 * Optionally, a recursion depth can be set.
1850 *
1851 * @param pTree The \b %StringTree to use.
1852 * @param depth Sets the recursion depth.
1853 * A depth of \c 0 iterates only the direct children of the root node.
1854 * Defaults to <c>std::numeric_limits<unsigned int>::max()</c>
1855 * for "unlimited" recursion.
1856 */
1857 void Initialize( cmTree& pTree,
1858 unsigned int depth= (std::numeric_limits<unsigned int>::max)() )
1859 {
1860 initialize( &pTree, &pTree.root.root, depth );
1861 }
1862
1863 /**
1864 * Resets this iterator to the first child of the node that the given cursor
1865 * object represents.
1866 * If the cursor is invalid, the root node of the tree it represents is used.
1867 *
1868 * If the given node has no children, this iterator is marked invalid when this
1869 * method returns.
1870 *
1871 * Optional parameter \p{depth} allows to limit the recursion depth.
1872 *
1873 * @param cursor The cursor to define the branch of the tree to iterate.
1874 * @param depth Sets the recursion depth.
1875 * A depth of \c 0 iterates only the direct children of the node
1876 * represented by \p{cursor}.
1877 * Defaults to <c>std::numeric_limits<unsigned int>::max()</c>
1878 * for "unlimited" recursion.
1879 */
1880 void Initialize( cmCursor cursor,
1881 unsigned int depth= (std::numeric_limits<unsigned int>::max)() )
1882 {
1883 initialize( static_cast<cmTree*>( cursor.tree ),
1884 cursor.IsValid() ? cursor.node : &cursor.tree->root.root,
1885 depth );
1886 }
1887
1888 /**
1889 * Resets this iterator to the first child of the node that the given other iterator
1890 * currently refers to. The given iterator has to be in a valid state.
1891 * Optionally, a recursion depth can be set.
1892 *
1893 * @param other The iterator whose current node becomes the start node for this
1894 * iterator.
1895 * @param depth Sets the recursion depth.
1896 * A depth of \c 0 iterates only the direct children of the node
1897 * represented by \p{other}.
1898 * Defaults to <c>std::numeric_limits<unsigned int>::max()</c>
1899 * for "unlimited" recursion.
1900 */
1901 void Initialize( const TRecursiveIterator& other,
1902 unsigned int depth= (std::numeric_limits<unsigned int>::max)() )
1903 {
1904 initialize( other.tree, other.node, depth );
1905 }
1906
1907 /**
1908 * Invalidates this object. After invoking this method, this iterator can not be
1909 * used further, until one of the overloaded methods #Initialize is invoked.
1910 * After the invocation, method #IsValid will return \c false.
1911 */
1913 {
1914 actDepth= size_t(-1);
1915 }
1916
1917 /**
1918 * Determines if this is a valid. \b RecursiveIterator instances may become invalid
1919 * after invocations of one of the methods #Next, #NextSibling or #NextParentSibling
1920 * (at the end of the iteration) and become valid with the invocation of one of the
1921 * overloaded methods #Initialize.
1922 *
1923 * @return \c true if this is a valid iterator. If invalid, \c false is returned and
1924 * the iterator must not be evaluated prior to being initialized.
1925 */
1926 bool IsValid() const
1927 {
1928 return actDepth != size_t(-1);
1929 }
1930
1931 /**
1932 * The negation of #IsValid.
1933 *
1934 * @return \c false if this is a valid iterator. If invalid, \c true is returned and
1935 * the iterator must not be evaluated prior to being initialized.
1936 */
1937 bool IsInvalid() const
1938 {
1939 return !IsValid();
1940 }
1941
1942
1943 /**
1944 * Allows to switch sorting on or off. If switched on, sorting is performed
1945 * by the node names in ascending order.
1946 *
1947 * This and the overloaded versions of this method may be invoked at any time,
1948 * even on invalid iterators and those that are not initialized.
1949 * All that the methods do is storing the given parameters for future use.
1950 * Such use happens whenever a recursive iteration over a list of child nodes is
1951 * started. In that moment the current configuration of sorting is applied to
1952 * the list of direct children.
1953 *
1954 * @param sorting The switch value.
1955 */
1956 void SetSorting( lang::Switch sorting )
1957 {
1958 if( sorting == lang::Switch::Off )
1959 nextIsSorting= false;
1960 else
1961 SetSorting(lang::SortOrder::Ascending, lang::Case::Ignore );
1962 }
1963
1964 /**
1965 * Sets the sorting of children by their path name, using the built-in comparison
1966 * methods, which in turn use method \alib{strings;TString::Equals;String::Equals}.
1967 *
1968 * \see
1969 * For more details on sorting see method \ref SetSorting(lang::Switch sorting).
1970 *
1971 *
1972 * @param order The sort order.
1973 * Defaults to \b %SortOrder::Ascending.
1974 * @param sensitivity The case sensitivity when comparing path names.
1975 * Defaults to \b %Case::Ignore.
1976 */
1977 void SetSorting( lang::SortOrder order = lang::SortOrder::Ascending,
1978 lang::Case sensitivity = lang::Case::Ignore )
1979 {
1980 nextIsSorting = true;
1981 nextCustomSorter = nullptr;
1982 nextSortingIsDescending = ( order == lang::SortOrder::Descending );
1983 nextSortingIsCaseSensitive= ( sensitivity == lang:: Case::Sensitive );
1984 }
1985
1986 /**
1987 * Sets the sorting of children by their template value, using the given
1988 * callback function.
1989 *
1990 * \see
1991 * For more details on sorting see method \ref SetSorting(lang::Switch sorting).
1992 *
1993 * @param customSorterFunction A custom comparison method used for sorting the children
1994 * of nodes.
1995 */
1996 void SetSorting( bool (*customSorterFunction)(const Cursor&, const Cursor&) )
1997 {
1998 nextIsSorting = true;
1999 nextCustomSorter = customSorterFunction;
2000 }
2001
2002 /**
2003 * Iterates to the first child of the current node. If no such child exists,
2004 * to the next sibling node. If also no sibling exists, iteration continues
2005 * with the next available node of a previous recursion level.
2006 *
2007 * @return \c true if a next node was found, \c false otherwise.
2008 * If \c false is returned, this iterator is invalid after the call. */
2009 bool Next()
2010 {
2011 return next(0);
2012 }
2013
2014 /**
2015 * Omits recursion on the current node's children, even if the current depth
2016 * is lower than #RequestedDepth.<br>
2017 *
2018 * If no sibling exists, iteration continues with the next available node of a
2019 * previous recursion level.
2020 *
2021 * @return \c true if a next node was found, \c false otherwise.
2022 * If \c false is returned, this iterator is invalid after the call.
2023 */
2025 {
2026 return next(1);
2027 }
2028
2029 /**
2030 * Skips the remaining siblings of the current recursion level and continues with
2031 * the next available sibling of a previous level.
2032 *
2033 * @return \c true if a next node was found, \c false otherwise.
2034 * If \c false is returned, this iterator is invalid after the call.
2035 */
2037 {
2038 return next(2);
2039 }
2040
2041
2042 /**
2043 * Retrieves the current path of walking as a string representation.
2044 * The path returned is relative to the start node and does not contain a leading
2045 * separator character. Also, it does not contain the name of the current node,
2046 * which can be received by invoking method #TCursor::Name on the cursor returned by
2047 * method #Node.
2048 *
2049 * Note that this method can be used only if path generation was activated
2050 * prior to the current iteration. Activation is performed with method
2051 * #SetPathGeneration.
2052 *
2053 * @return The path of the current node.
2054 */
2055 const NameType& CurrentPath() const
2056 {
2057 ALIB_ASSERT_ERROR( actPath.IsNotNull(), "MONOMEM/STRINGTREE",
2058 "Path generation not activated" )
2059 return actPath;
2060 }
2061
2062 /**
2063 * Writes the results of #CurrentPath and #TCursor::Name, separated by the separator
2064 * character \p{TSeparator}.
2065 *
2066 * Note that this method can be used only if path generation was activated
2067 * prior to the current iteration. Activation is performed with method
2068 * #SetPathGeneration.
2069 *
2070 * @param target The target to append the path to.
2071 * @param targetData Denotes whether \p{target} should be cleared prior to
2072 * appending the path. Defaults to CurrentData::Clear.
2073 * @return The given string to allow concatenated operations
2074 */
2076 lang::CurrentData targetData= lang::CurrentData::Clear ) const
2077 {
2078 ALIB_ASSERT_ERROR( actPath.IsNotNull(), "MONOMEM/STRINGTREE",
2079 "Path generation not activated" )
2080
2081 if( targetData == lang::CurrentData::Clear )
2082 target.Reset();
2083
2084 if( actPath.IsNotEmpty() )
2085 target << actPath << tree->separator;
2086
2087 return target << node->name.key;
2088 }
2089
2090
2091 /**
2092 * Returns the requested maximum depth of iteration, set with #Initialize.
2093 *
2094 * @see For the current iteration depth, use #CurrentDepth.
2095 *
2096 *
2097 * @return The distance of the current node and the node of the start of the
2098 * iteration.
2099 */
2100 int RequestedDepth() const
2101 {
2102 return int(recursionDepth);
2103 }
2104
2105 /**
2106 * Returns the depth of the current iteration. This is value is available to the
2107 * algorithm which means this method executes in constant time.
2108 *
2109 * To get the absolute depth of the current node, method #TCursor::Depth may be used.
2110 *
2111 * @return The distance of the current node and the node of the start of the
2112 * iteration.
2113 */
2114 int CurrentDepth() const
2115 {
2116 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE",
2117 "RecursiveIterator not initialized or exceeded (invalid)." )
2118 return int(actDepth);
2119 }
2120
2121 /**
2122 * Returns the current node, encapsulated in a cursor object.
2123 *
2124 * \note
2125 * It is \b not allowed to use method #TCursor::Delete on the node returned by
2126 * this method. As a replacement, use method #DeleteNode implemented in this
2127 * class.<br>
2128 * However, methods #TCursor::DeleteChild and #TCursor::DeleteChildren are allowed
2129 * to be invoked and therefore have no replacement in this class.
2130 *
2131 * @return An instance of the public node interface pointing to the currently
2132 * referenced tree node.
2133 */
2135 {
2136 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE",
2137 "RecursiveIterator not initialized or exceeded (invalid)." )
2138 return cmCursor( tree, node );
2139 }
2140
2141 //#### node deletion (RecursiveIterator) #############################################
2142
2143 /**
2144 * Deletes the node that this iterator currently refers to from the tree.
2145 * After the operation, the iterator is moved forward to the next sibling
2146 * of the current node, respectively of the first sibling found in the
2147 * recursion stack.
2148 *
2149 * \note
2150 * This method constitutes a legal alternative to method #TCursor::Delete, which is
2151 * forbidden to be invoked on the node returned by method #Node as this would
2152 * invalidate this iterator.<br>
2153 *
2154 * Methods #TCursor::DeleteChild and #TCursor::DeleteChildren are allowed with this
2155 * iterator type. Consequently, no replacement method for those is given with this
2156 * class.
2157 *
2158 * @return The total number of nodes deleted.
2159 */
2161 {
2162 ALIB_ASSERT_ERROR( IsValid(), "MONOMEM/STRINGTREE",
2163 "RecursiveIterator not initialized or exceeded (invalid)." )
2164 auto& nodeToDelete= *node;
2165 next( 1 ); // next sibling
2166 return nodeToDelete.parent->deleteChild( tree, &nodeToDelete );
2167 }
2168
2169 // #### RecursiveIterator Internals ###################################################
2170 protected:
2171 /**
2172 * Resets this iterator to represent to the given node of the given tree.
2173 *
2174 * @param pTree The tree to iterate on.
2175 * @param newnode The new node to start the iteration from.
2176 * @param depth The requested recursion depth.
2177 */
2178 void initialize( cmTree* pTree, cmNode* newnode, unsigned int depth )
2179 {
2180 this->tree= pTree;
2181 if( actPath.IsNotNull() )
2182 {
2183 actPath.Reset();
2184 if( newnode->isRoot() )
2185 actPath << tree->separator;
2186 }
2187
2188 node= newnode;
2189 if( newnode->qtyChildren )
2190 {
2191 recursionDepth= depth;
2192 actDepth= size_t(-1);
2193 recursion();
2194 }
2195 else
2196 actDepth= size_t( -1 );
2197 }
2198
2199 /**
2200 * Sets this iterator to point to the first child of the actual node.
2201 * If sorting is enabled, copies all children from the map to a vector and sorts
2202 * them there.
2203 */
2205 {
2206 ++actDepth;
2207 if( stack.size() == actDepth )
2208 stack.emplace_back();
2209
2210 auto& rd= stack[actDepth];
2211 rd.customSorter = nextCustomSorter;
2212 rd.isSorting = nextIsSorting;
2213 rd.sortingIsDescending = nextSortingIsDescending;
2214 rd.sortingIsCaseSensitive= nextSortingIsCaseSensitive;
2215
2216 // no sorting: set link to node's child hook
2217 if (!rd.isSorting)
2218 {
2219 rd.childrenUnsorted= &node->children;
2220 node= (rd.actChild.unsorted= rd.childrenUnsorted->first());
2221 return;
2222 }
2223
2224 // sorting: copy children to a sortable vector
2225 rd.childrenSorted.clear();
2226 rd.childrenSorted.reserve( size_t( node->qtyChildren ) );
2227 auto* copyIt= node->children.first();
2228 while( copyIt != &node->children.hook )
2229 {
2230 rd.childrenSorted.emplace_back( copyIt );
2231 copyIt= copyIt->next();
2232 }
2233
2234 // sort
2235 if( rd.customSorter )
2236 {
2237 std::sort( rd.childrenSorted.begin(), rd.childrenSorted.end(),
2238 [this,&rd]( cmNode* lhs,
2239 cmNode* rhs )
2240 {
2241 return rd.customSorter( cmCursor(tree, lhs),
2242 cmCursor(tree, rhs) );
2243 }
2244 );
2245 }
2246 else
2247 {
2248 std::sort( rd.childrenSorted.begin(), rd.childrenSorted.end(),
2249 [&rd]( cmNode* lhs, cmNode* rhs)
2250 {
2251 int compResult= rd.sortingIsCaseSensitive
2252 ? lhs->name.key. template CompareTo<true, lang::Case::Sensitive>(rhs->name.key)
2253 : lhs->name.key. template CompareTo<true, lang::Case::Ignore >(rhs->name.key);
2254 return rd.sortingIsDescending ? compResult > 0
2255 : compResult < 0;
2256 }
2257 );
2258 }
2259
2260 // set to first child
2261 rd.actChild.sorted= 0;
2262 node= rd.childrenSorted[0];
2263 }
2264
2265
2266 /**
2267 * Goes to the next node.
2268 * This method is used with interface methods #Next, #NextSibling and
2269 * #NextParentSibling, as well as with #DeleteNode}.
2270 *
2271 * @param skipMode \c 0 iterates to the first child (if available),
2272 * \c 1 iterates to the next sibling (if available) and
2273 * \c 2 to the next available sibling of the parent, respectively the
2274 * current recursion stack.
2275 * @return \c true if this iterator is valid (a next node was found), \c false
2276 * otherwise. */
2277 bool next(int skipMode)
2278 {
2279 ALIB_ASSERT_ERROR( actDepth != size_t(-1), "MONOMEM/STRINGTREE",
2280 "Invalid iterator" )
2281
2282 // recursion to first child of actual node?
2283 if( skipMode == 0
2284 && static_cast<unsigned int>( actDepth ) < recursionDepth
2285 && node->qtyChildren )
2286 {
2287 if( actPath.IsNotNull() )
2288 {
2289 if( actPath.IsNotEmpty()
2290 && (actPath.Length() != 1 || actPath.CharAtStart() != tree->separator ) )
2291 actPath << tree->separator;
2292
2293 actPath << node->name.key;
2294 }
2295
2296 // increase stack capacity
2297 if( stack.size() == actDepth + 1 )
2298 stack.emplace_back();
2299
2300 recursion();
2301
2302 return true;
2303 }
2304
2305 for(;;)
2306 {
2307 if( skipMode != 2 )
2308 {
2309 // next sibling
2310 bool foundNextChild;
2311 {
2312 RecursionData& rd= stack[ actDepth ];
2313 if( rd.isSorting )
2314 {
2315 ++rd.actChild.sorted;
2316
2317 if( (foundNextChild= rd.actChild.sorted < rd.childrenSorted.size())
2318 ==true )
2319 node= rd.childrenSorted[rd.actChild.sorted];
2320 }
2321 else
2322 {
2323 node = (rd.actChild.unsorted= rd.actChild.unsorted->next());
2324 foundNextChild= (node != &rd.childrenUnsorted->hook);
2325 }
2326 }
2327
2328 if( foundNextChild )
2329 break;
2330 }
2331 skipMode= 0;
2332
2333 // climb down
2334 if( actDepth > 0 )
2335 {
2336 --actDepth;
2337
2338 // remove separator from path
2339 if( actPath.IsNotEmpty() )
2340 {
2341 character lastChar;
2342 do
2343 {
2344 lastChar= actPath.CharAtEnd<false>();
2345 actPath.DeleteEnd<false>( 1 );
2346 }
2347 while( lastChar != tree->separator && actPath.IsNotEmpty() );
2348 }
2349 }
2350 else
2351 {
2352 actDepth= size_t(-1);
2353 ALIB_ASSERT( actPath.IsEmpty()
2354 || (actPath.Length() == 1 && actPath.CharAtStart() == tree->separator) )
2355 break;
2356 }
2357 }
2358
2359 return actDepth != size_t(-1);
2360 }
2361
2362 }; // inner class "TRecursiveIterator"
2363
2364 /** The mutable version of type \alib{monomem;StringTree::TRecursiveIterator<TConst>}. */
2366
2367 /** The constant version of type \alib{monomem;StringTree::TRecursiveIterator<TConst>}. */
2369
2370
2371 // #############################################################################################
2372 // StringTree Main
2373 // #############################################################################################
2374
2375 /** ********************************************************************************************
2376 * Constructor.
2377 * @param allocator The monotonic allocator to use.
2378 * @param pathSeparator The separation character used with path strings.
2379 **********************************************************************************************/
2380 StringTree( MonoAllocator* allocator, CharacterType pathSeparator )
2381 : basetree( allocator, pathSeparator )
2382 {}
2383
2384 /** ********************************************************************************************
2385 * Constructor taking a shared recycler.
2386 * @param allocator The monotonic allocator to use.
2387 * @param pRecycler The shared recycler.
2388 * @param pathSeparator The separation character used with path strings.
2389 **********************************************************************************************/
2390 StringTree( MonoAllocator* allocator, CharacterType pathSeparator, TSharedRecycler& pRecycler )
2391 : basetree( allocator, pRecycler, pathSeparator )
2392 {}
2393
2394 /** ********************************************************************************************
2395 * Destructor.
2396 * Raises a warning if \alib{monomem::StringTree;ConstructRootValue;a root value was} but
2397 * not deleted accordingly.
2398 **********************************************************************************************/
2400 {
2401 for( auto& node : basetree::nodeTable )
2402 TNodeMaintainer::FreeNode( *this, *static_cast<baseNode*>(&node) );
2403
2404 ALIB_ASSERT_WARNING( basetree::dbgRootDataSet == 0, "MONOMEM/STRINGTREE",
2405 "The root node's value object was set but not deleted before destruction of this StringTree.\n"
2406 "Possible memory leak! To suppress this warning call DeleteRootValue() prior to destruction.\n"
2407 "In case this is not necessary (because the value type does not leak if not destructed),\n"
2408 " emplace it in macro ALIB_DBG() to remove the call in release compilations." )
2409 }
2410
2411 /** ********************************************************************************************
2412 * In some situations, the allocator object to use might not be available with construction
2413 * of an instance. This method may be used to attach an external allocator at a later
2414 * point in time - but prior to this instance's first use.
2415 *
2416 * @param pAllocator The allocator that was omitted in the constructor.
2417 **********************************************************************************************/
2419 {
2420 basetree::nodeTable.SetAllocatorPostConstruction( pAllocator );
2421 }
2422
2423 /** ********************************************************************************************
2424 * Shortcut to \alib{monomem;HashTable::GetAllocator;NodeTable().GetAllocator}.
2425 * @return The allocator that was provided in the constructor and stored in the internal
2426 * #NodeTable.
2427 **********************************************************************************************/
2429 {
2430 return basetree::nodeTable.GetAllocator();
2431 }
2432
2433
2434
2435 /** ********************************************************************************************
2436 * Depending on the use case, it might be appropriate to attach a value of template type \p{T}
2437 * to the root node of the tree. If so, this can be done with this method. If not done, in debug
2438 * compilations, method #TCursor::Value will
2439 * raise an \alib assertion if called on the root node.
2440 *
2441 * Custom data that is explicitly attached to the root node with this method has to be
2442 * deleted explicitly by calling #DeleteRootValue prior to deletion of the tree.
2443 *
2444 * @tparam TArgs Types of variadic parameters given with parameter \p{args}.
2445 * @param args Variadic parameters to be forwarded to constructor of custom
2446 * type \p{T} of the child created.
2447 **********************************************************************************************/
2448 template<typename... TArgs>
2449 void ConstructRootValue( TArgs&&... args )
2450 {
2451 #if ALIB_DEBUG
2452 ALIB_ASSERT_WARNING( basetree::dbgRootDataSet != 1, "MONOMEM/STRINGTREE",
2453 "Root node value is set without prior deletion. Possible memory leak (depending on allocation \n"
2454 "of template type T). This warning is only printed on the first overwrite." )
2455 ++basetree::dbgRootDataSet;
2456 #endif
2457
2458 new (&basetree::root.root.data) T( std::forward<TArgs>(args)... );
2459 }
2460
2461 /** ********************************************************************************************
2462 * Deletes the custom data object of type \p{T}, which may explicitly set using #ConstructRootValue.\n
2463 * If not done, in debug-compilations, an \alib warning is raised in the destructor
2464 * of this tree.
2465 **********************************************************************************************/
2467 {
2468 #if ALIB_DEBUG
2469 ALIB_ASSERT_WARNING( basetree::dbgRootDataSet != 0, "MONOMEM/STRINGTREE",
2470 "Deletion of root node data without prior setting (our double deletion)." )
2471 --basetree::dbgRootDataSet;
2472 #endif
2473 basetree::root.root.data.~T();
2474 }
2475
2476 /** ********************************************************************************************
2477 * Removes all elements from this container. The use of this method is more efficient than
2478 * deleting the children of the root node.
2479 *
2480 * Invokes \alib{monomem;HashTable::Clear} on field
2481 * \alib{monomem::detail::StringTreeBase;nodeTable}. As documented with that method, the
2482 * allocated nodes will be preserved for "recycling" with future insertions.
2483 *
2484 * The custom data of the root node is preserved.
2485 **********************************************************************************************/
2486 void Clear()
2487 {
2488 for( auto& node : basetree::nodeTable )
2489 TNodeMaintainer::FreeNode( *this, *static_cast<baseNode*>(&node) );
2490
2491 basetree::nodeTable.Clear();
2492
2493 // re-initialize root node
2494 basetree::root.root.children.reset();
2495 basetree::root.root.qtyChildren= 0;
2496 }
2497
2498 /** ********************************************************************************************
2499 * Clears all nodes and values. The use of this method is more efficient than deleting the
2500 * children of the root node.<br>
2501 * In addition, depending on template type \p{TNodeMaintainer}, it may also declare allocated
2502 * memory for future reuse.<br>
2503 * The latter is true for type \alib{monomem;StringTreeNamesMonoAlloc}.
2504 *
2505 * In case of \alib{monomem;Recycling::Private;private recycling} disposes all previously
2506 * allocated recyclable instances of internal element type.
2507 *
2508 * \note The value of the root-node, set with #ConstructRootValue is not deleted.
2509 **********************************************************************************************/
2510 void Reset()
2511 {
2512 for( auto& node : basetree::nodeTable )
2513 TNodeMaintainer::FreeNode( *this, *static_cast<baseNode*>(&node) );
2514
2515 basetree::nodeTable.Reset();
2516
2517 // re-initialize root node
2518 basetree::root.root.children.reset();
2519 basetree::root.root.qtyChildren= 0;
2520 }
2521
2522 /** ********************************************************************************************
2523 * Counts the number of currently allocated but unused (not contained) element nodes
2524 * that will be recycled with upcoming insertions.
2525 *
2526 * \note
2527 * This method is provided for completeness and unit-testing. It should not be of
2528 * relevance for common usage.
2529 * Furthermore, this method is not available (aka does not compile) with instantiations
2530 * that specify template parameter \p{TRecycling} as \alib{monomem;Recycling::None}.
2531 *
2532 * @return The number of removed and not yet recycled elements.
2533 **********************************************************************************************/
2535 {
2536 return basetree::nodeTable.RecyclablesCount();
2537 }
2538
2539 /** ********************************************************************************************
2540 * Returns the overall number of elements contained in this tree.
2541 *
2542 * \note
2543 * This method performs in constant time.
2544 *
2545 * @return The number elements contained in this tree.
2546 **********************************************************************************************/
2548 {
2549 return basetree::nodeTable.Size();
2550 }
2551
2552 /** ********************************************************************************************
2553 * Tests for emptiness.
2554 *
2555 * @return \c true if this tree is empty, \c false otherwise.
2556 **********************************************************************************************/
2557 bool IsEmpty() const
2558 {
2559 return basetree::nodeTable.Size() == 0;
2560 }
2561
2562 /** ********************************************************************************************
2563 * Allocates the required space for the number of elements expected.
2564 *
2565 * \note
2566 * If the definite number of stored elements that is never exceeded is known,
2567 * a \alib{monomem;MonoAllocator::TakeSnapshot;snapshot} of the monotonic allocator could
2568 * be taken after the invocation of this method and then used to reset the monotonic
2569 * allocator with preserving the memory used by this container.
2570 *
2571 * @param expected The expected number or increase of elements to be stored in the hash table.
2572 * @param reference Denotes whether \p{expected} is meant as an absolute size or an increase .
2573 **********************************************************************************************/
2575 {
2576 basetree::nodeTable.ReserveRecyclables( expected, reference );
2577 }
2578
2579 /** ********************************************************************************************
2580 * Returns the internal \alib{monomem;HashTable} used for storing the tree nodes.
2581 * This may be used to manipulate load factors, for direct iteration over all nodes, etc.<br>
2582 * \note The returned object should be used with caution to keep the tree and its data
2583 * consistent.
2584 * @return The internal node table.
2585 **********************************************************************************************/
2587 {
2588 return basetree::nodeTable;
2589 }
2590
2591 /** ********************************************************************************************
2592 * Returns the internal \alib{monomem;HashTable} used for storing the tree nodes.
2593 * This may be used to manipulate load factors, for direct iteration over all nodes, etc.<br>
2594 * \note The returned object should be used with caution to keep the tree and its data
2595 * consistent.
2596 * @return The internal node table.
2597 **********************************************************************************************/
2598 const auto& NodeTable() const
2599 {
2600 return basetree::nodeTable;
2601 }
2602
2603 /** ********************************************************************************************
2604 * Creates a cursor instance representing the root node.
2605 * @return A cursor pointing to the root node of this \b %StringTree.
2606 **********************************************************************************************/
2608 {
2609 return Cursor( this, &(basetree::root.root) );
2610 }
2611
2612 /** ********************************************************************************************
2613 * Creates a \c const cursor instance representing the root node.
2614 * @return A read-only pointer, pointing to the root node of this \b %StringTree.
2615 **********************************************************************************************/
2616 const ConstCursor Root() const
2617 {
2618 return ConstCursor( this, &(basetree::root.root) );
2619 }
2620}; // StringTree
2621
2622
2623
2624} // namespace alib::[monomem]
2625
2626/// Type alias in namespace \b alib.
2627template<typename TChar, integer TLocalCapacity= 32>
2629
2630/// Type alias in namespace \b alib.
2631template<typename TChar>
2633
2634/// Type alias in namespace \b alib.
2635template<typename TChar>
2637
2638/// Type alias in namespace \b alib.
2639template<typename T,
2640 typename TNodeMaintainer= StringTreeNamesDynamic<character>,
2641 typename TRecycling = Recycling::Private >
2643
2644
2645} // namespace [alib]
2646
2647
2648#endif // HPP_ALIB_MONOMEM_STRINGTREE
TCursor CreateChild(const NameType &childName, TArgs &&... args) const
ATMP_IF_T_F(!TConst, baseNodeBase, const baseNodeBase) cmNode
const StringTree & Tree() const
TCursor(const TCursor &src) noexcept
TCursor & operator=(TCursor &&) noexcept=default
bool DeleteChild(const NameType &childName) const
std::pair< TCursor, bool > CreateChildIfNotExistent(const NameType &name, TArgs &&... args)
AString & AssemblePath(AString &targetString, const TCursor &parent, lang::CurrentData targetData=lang::CurrentData::Clear) const
const NameType & Name() const
AString & AssemblePath(AString &targetString, lang::CurrentData targetData=lang::CurrentData::Clear) const
ATMP_IF_T_F(!TConst, StringTree, const StringTree) TStringTree
bool operator!=(const TCursor &other) const
bool GoToCreateChildIfNotExistent(const NameType &name, TArgs &&... args)
ATMP_IF_T_F(!TConst, basetree, const basetree) cmTree
TCursor & operator=(const TCursor &) noexcept=default
TCursor(cmTree *pTree, cmNode *pNode) noexcept
TCursor Child(const NameType &name) const
std::pair< TCursor, integer > CreatePathIfNotExistent(const NameType &path, TArgs &&... args)
bool operator==(const TCursor &other) const
integer GoToCreatedPathIfNotExistent(const NameType &path, TArgs &&... args)
SubstringType GoToTraversedPath(const NameType &path)
bool GoToChild(const NameType &name)
std::pair< TCursor, SubstringType > TraversePath(const NameType &path) const
TCursor(TCursor &&src) noexcept
void DeleteChild(TCursor &child) const
ATMP_IF_T_F(!TConst, baseCursor, baseConstCursor) cmCursor
void Initialize(cmCursor cursor, unsigned int depth=(std::numeric_limits< unsigned int >::max)())
ATMP_IF_T_F(!TConst, baseNodeBase, const baseNodeBase) cmNode
ATMP_IF_T_F(!TConst, Cursor, ConstCursor) cmCursor
void SetSorting(lang::SortOrder order=lang::SortOrder::Ascending, lang::Case sensitivity=lang::Case::Ignore)
AString & FullPath(AString &target, lang::CurrentData targetData=lang::CurrentData::Clear) const
void initialize(cmTree *pTree, cmNode *newnode, unsigned int depth)
void Initialize(cmTree &pTree, unsigned int depth=(std::numeric_limits< unsigned int >::max)())
ATMP_IF_T_F(!TConst, StringTree, const StringTree) cmTree
void Initialize(const TRecursiveIterator &other, unsigned int depth=(std::numeric_limits< unsigned int >::max)())
void SetSorting(bool(*customSorterFunction)(const Cursor &, const Cursor &))
const auto & NodeTable() const
MonoAllocator * GetAllocator()
integer RecyclablesCount() const
StringTree(MonoAllocator *allocator, CharacterType pathSeparator, TSharedRecycler &pRecycler)
typename TNodeMaintainer::CharacterType CharacterType
void ConstructRootValue(TArgs &&... args)
const ConstCursor Root() const
void SetAllocatorPostConstruction(MonoAllocator *pAllocator)
StringTree(MonoAllocator *allocator, CharacterType pathSeparator)
TCursor< true > ConstCursor
typename strings::TSubstring< CharacterType > SubstringType
typename strings::TString< CharacterType > NameType
void ReserveRecyclables(integer expected, lang::ValueReference reference)
typename basetree::TSharedRecycler TSharedRecycler
#define ATMP_IF_T_F( Cond, T, F)
Definition tmp.hpp:54
#define ALIB_WARNING(...)
Definition alib.hpp:981
#define ALIB_ASSERT_MODULE(modulename)
Definition alib.hpp:190
#define ALIB_API
Definition alib.hpp:538
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:984
#define ALIB_ASSERT_WARNING(cond,...)
Definition alib.hpp:985
#define ALIB_DBG(...)
Definition alib.hpp:457
#define ALIB_ASSERT(cond)
Definition alib.hpp:983
#define ATMP_T_IF(T, Cond)
Definition tmp.hpp:53
@ Clear
Chooses to clear existing data.
ALIB_API uinteger DbgStatsStringTreeNameOverflows
ALIB_API uinteger DbgStatsStringTreeNames
Definition alib.cpp:57
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.hpp:289
constexpr CString EmptyString()
Definition cstring.hpp:502
constexpr String NullString()
Definition string.hpp:2498
characters::character character
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
Definition integers.hpp:286
static void InitializeNode(TTree &tree, typename TTree::Node &node)
ATMP_IF_T_F((TLocalCapacity > 0), strings::TLocalString< TChar ALIB_COMMA TLocalCapacity >, strings::TString< TChar >) NameStringType
static void FreeNode(TTree &tree, typename TTree::Node &node)
static void InitializeNode(TTree &tree, typename TTree::Node &node)
static void FreeNode(TTree &tree, typename TTree::baseNode &node)
static void InitializeNode(TTree &tree, typename TTree::Node &node)
static void FreeNode(TTree &tree, typename TTree::Node &node)
union alib::monomem::StringTree::TRecursiveIterator::RecursionData::@5 actChild
lang::BidiListHelper< baseNodeBase > * childrenUnsorted
bool checkChildName(const NameType &name) const
monomem::HashTable< Node, Node, NodeKey, void, typename NodeKey::Hash, typename NodeKey::EqualTo, typename NodeKey::Access, lang::Caching::Enabled, TRecycling > nodeTable
Node root
Full version of the root node, without initialization of member T.