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