1 # Tree
2
3 UCX provides several low-level functions for working with arbitrary tree structures,
4 as well as some high-level functions for trees that induce a certain order on the data they store.
5
6 The following convenience macros allow you to declare and use simple tree structures.
7
8 ```C
9 #define CX_TREE_NODE_BASE(Type)
10
11 #define cx_tree_node_base_layout
12 ```
13
14 The `CX_TREE_NODE_BASE` macro declares four pointers of type `Type*`:
15 `parent`, `children`, `last_child`, `prev`, and `next`,
16 which must be placed as first member into your struct.
17
18 You can use it, for example, like this:
19 ```C
20 typedef struct my_tree_node_s {
21 CX_TREE_NODE_BASE(struct my_tree_node_s);
22 int value;
23 char *desc;
24 } MyTreeNode;
25 ```
26
27 The macro `cx_tree_node_base_layout` expands to the offsets of the above-mentioned pointers.
28 It will become handy when calling the low-level tree functions which expect all offsets to be passed as arguments.
29
30 > In all functions, the `last_child` and `prev` pointers are completely optional.
31 > If your tree structure does not contain the `last_child` pointer, the last child will be determined by
32 > traversing all children from the first child.
33 > The same happens when it does not have a `prev` pointer, and the left sibling of a child is needed.
34 > The `children` pointer (which points to the first child), and the `next` pointer are mandatory,
35 > and so is the `parent` pointer.
36
37 Before diving into the function definitions, there are four function pointer declarations you should know.
38
39 ```C
40 #include <cx/tree.h>
41
42 typedef void *(*cx_tree_node_create_func)(
43 const void *data, void *context);
44
45 typedef int (*cx_tree_search_data_func)(
46 const void *node, const void *data);
47
48 typedef int (*cx_tree_search_func)(
49 const void *node, const void *new_node);
50
51 typedef void (*cx_tree_relink_func)(
52 void *node, const void *old_parent, const void *new_parent);
53 ```
54
55 A `cx_tree_node_create_func` takes a pointer to the `data` the new node shall contain, and a `context` (which might be an allocator, for example).
56 It shall allocate and return the created node, or `NULL` when node creation is not possible.
57
58 A `cx_tree_search_data_func` shall check if the `node` contains the `data`, or if a child node might contain the data.
59 It shall return zero, when `node` contains the `data`.
60 When a child node _might_ contain the data, the returned positive number shall indicate how close the match is.
61 It is _not_ relevant if the data can actually be found in the subtree - the positive number also indicates that the data could be inserted in that subtree.
62 Only when the entire subtree starting with `node` cannot contain the `data`, a negative number is supposed to be returned.
63
64 A `cx_tree_search_func` behaves exactly the same, except that it does expect a pointer to the `data` but a pointer to a node structure.
65 In combination with the `cx_tree_node_create_func`, when inserting nodes with the high-level functions, a `new_node` is created first,
66 and then an appropriate insertion point is searched with the `cx_tree_search_func`.
67
68 A `cx_tree_relink_func` is called when an intermediate node was removed from the tree and it's children need to be detached from
69 the removed `old_parent` and attached to a `new_parent`.
70 The function is called for every child of the removed node and can be used, for example, to update the contents of the node when needed.
71
72 ## Create
73
74 ```C
75 #include <cx/tree.h>
76
77 CxTree *cxTreeCreate(const CxAllocator *allocator,
78 cx_tree_node_create_func create_func,
79 cx_tree_search_func search_func,
80 cx_tree_search_data_func search_data_func,
81 ptrdiff_t loc_parent,
82 ptrdiff_t loc_children, ptrdiff_t loc_last_child,
83 ptrdiff_t loc_prev, ptrdiff_t loc_next);
84
85 CxTree *cxTreeCreateSimple(const CxAllocator *allocator,
86 cx_tree_node_create_func create_func,
87 cx_tree_search_func search_func,
88 cx_tree_search_data_func search_data_func);
89
90 CxTree *cxTreeCreateWrapped(const CxAllocator *allocator,
91 void *root,
92 ptrdiff_t loc_parent,
93 ptrdiff_t loc_children, ptrdiff_t loc_last_child,
94 ptrdiff_t loc_prev, ptrdiff_t loc_next);
95 ```
96
97 The function `cxTreeCreate()` creates a `CxTree` structure
98 where each node created by the `create_func` has the layout specified by the offset arguments.
99 The function `cxTreeCreateSimple()` is exactly the same, except that it assumes the `cx_tree_node_base_layout`.
100
101 In both cases the tree will be created empty, that is with no nodes, not even a root node.
102 On the other hand, `cxTreeCreateWrapped()` creates a `CxTree` structure with the specified layout and `root` node
103 where `root` may already be the root of a larger tree.
104
105 If your wrapped tree structure does not have a `last_child` or a `prev` pointer,
106 you may specify a negative location to indicate the missing pointer.
107 All other pointers are mandatory and a non-negative location is expected.
108
109 Note that a wrapped tree by default has no create or search functions assigned.
110 Therefore, if you wish to use one of the functions below that needs those function pointers set,
111 you will have to set them manually by assigning to the respective fields in the `CxTree` structure.
112
113 ### Example for wrapping a libxml2 tree
114
115 In this example we wrap the XML tree of the commonly used libxml2 library.
116
117 ```C
118 #include <libxml/tree.h>
119 #include <cx/tree.h>
120
121 CxTree *wrap_xml_tree(xmlNode *root) {
122 return cxTreeCreateWrapped(
123 cxDefaultAllocator, // or you can just write NULL
124 root,
125 offsetof(xmlNode, parent),
126 offsetof(xmlNode, children),
127 offsetof(xmlNode, last),
128 offsetof(xmlNode, prev),
129 offsetof(xmlNode, next)
130 );
131 }
132 ```
133
134 You do not need to specify any function pointers or destructors in the `CxTree` structure,
135 if you just want to use the resulting `CxTree` for [iterating](#iterator-and-visitor) over the nodes.
136
137 You can, for example, print the XML structure with the following code:
138
139 ```C
140 // continued from above
141
142 void print_xml_structure(CxTree *tree) {
143 // specify visit_on_exit argument = true
144 // so that we are visiting each node twice: on enter and on exit
145 CxTreeIterator iter = cxTreeIterate(tree, true);
146
147 cx_foreach(xmlNode*, node, iter) {
148 if (node->type == XML_ELEMENT_NODE) {
149 // the exiting field from the iterator indicates
150 // whether we are entring or leaving the subtree
151 // of the current element
152 printf("%s - %s\n",
153 node->name,
154 iter.exiting ? "start" : "end"
155 );
156 }
157 }
158 cxTreeIteratorDispose(&iter);
159 }
160 ```
161
162 ## Add Nodes
163
164 ```C
165 #include <cx/tree.h>
166
167 void cx_tree_link(void *parent, void *node, ptrdiff_t loc_parent,
168 ptrdiff_t loc_children, ptrdiff_t loc_last_child,
169 ptrdiff_t loc_prev, ptrdiff_t loc_next);
170
171 extern unsigned int cx_tree_add_look_around_depth;
172
173 size_t cx_tree_add_iter(struct cx_iterator_base_s *iter, size_t n,
174 cx_tree_search_func sfunc, cx_tree_node_create_func cfunc,
175 void *cdata, void **failed, void *root,
176 ptrdiff_t loc_parent,
177 ptrdiff_t loc_children, ptrdiff_t loc_last_child,
178 ptrdiff_t loc_prev, ptrdiff_t loc_next);
179
180 size_t cx_tree_add_array(const void *src, size_t n, size_t elem_size,
181 cx_tree_search_func sfunc, cx_tree_node_create_func cfunc,
182 void *cdata, void **failed, void *root,
183 ptrdiff_t loc_parent,
184 ptrdiff_t loc_children, ptrdiff_t loc_last_child,
185 ptrdiff_t loc_prev, ptrdiff_t loc_next);
186
187 int cx_tree_add(const void *src,
188 cx_tree_search_func sfunc, cx_tree_node_create_func cfunc,
189 void *cdata, void **cnode, void *root,
190 ptrdiff_t loc_parent,
191 ptrdiff_t loc_children, ptrdiff_t loc_last_child,
192 ptrdiff_t loc_prev, ptrdiff_t loc_next);
193 ```
194
195 The low-level function `cx_tree_link()` adds a `node` to a new `parent`, unlinking it from its previous parent, if required.
196
197 The functions `cx_tree_add_array()` and `cx_tree_add_iter()` are equivalent,
198 except that the former adds `n` items of size `elem_size` from the `src` array,
199 and the latter adds _up to_ `n` items from the iterator `iter`.
200 For each element, the `cfun` is called with the element as first argument and the `cdata` context as second argument.
201 The `cfun` function is supposed to return a node for which then the `sfunc` is used to find the location where to insert the node.
202 If a node could not be added, because `sfunc` always returns a negative number, it is stored at the location where `failed` points to.
203
204 > The functions `cx_tree_add_array()` and `cx_tree_add_iter()` are optimized for adding multiple nodes to
205 > the same subtree without starting the search all over from the root node.
206 > This behavior can be controlled with `cx_tree_add_look_around_depth`, which specifies for how many parent nodes
207 > the algorithm backtracks in the current subtree before restarting the search from the root node.
208
209 The function `cx_tree_add()` is similar to the other add-functions,
210 except that it does only add one single item to the tree and always stores the created node at the location where `cnode` points to.
211
212 > By design, the add-functions can only be used to add children to the tree.
213 > If you want to add a new root node, this is much easier by simply calling `cx_tree_link(newroot, oldroot, layout...)` .
214
215 The following high-level functions can be used to add nodes to a `CxTree`.
216
217 ```C
218 #include <cx/tree.h>
219
220 int cxTreeAddChild(CxTree *tree, void *parent, const void *data);
221
222 void cxTreeAddChildNode(CxTree *tree, void *parent, void *child);
223
224 void cxTreeSetParent(CxTree *tree, void *parent, void *child);
225
226 int cxTreeInsert(CxTree *tree, const void *data);
227
228 size_t cxTreeInsertIter(CxTree *tree, CxIteratorBase *iter, size_t n);
229
230 size_t cxTreeInsertArray(CxTree *tree, const void *data,
231 size_t elem_size, size_t n);
232 ```
233
234 The functions `cxTreeAddChild()`, `cxTreeAddChildNode()`, and `cxTreeSetParent()` are similar to `cx_tree_link()`.
235 The difference between `cxTreeAddChild()` and `cxTreeAddChildNode()` is,
236 that `cxTreeAddChild()` uses the `cx_tree_node_create_func` of the `CxTree` to create the node first, before adding it.
237 The function returns non-zero in case the creation of the node fails.
238 The difference between `cxTreeSetParent()` and `cxTreeAddChildNode()` is,
239 that `cxTreeSetParent()` does not increase the tree size, when `child` already had a parent.
240
241 > Use `cxTreeAddChildNode()` to add _new_ nodes to the tree and `cxTreeSetParent()`
242 > to relink a subtree of the `tree` with a new parent.
243 >
244 > Using `cxTreeSetParent()` on a `child` which already has a parent in a _different_ tree is a mistake.
245
246 The functions `cxTreeInsert()`, `cxTreeInsertIter()`, and `cxTreeInsertArray()` behave
247 like `cx_tree_add()`, `cx_tree_add_iter()`, and `cx_tree_add_array()`.
248 As creation context `cdata` for the `cx_tree_node_create_func` a pointer to the `CxTree` is passed.
249 Instead of returning a `failed` node, like the low-level functions, the high-level functions automatically free the memory for the failed node.
250
251 ## Size and Depth
252
253 ```C
254 #include <cx/tree.h>
255
256 size_t cxTreeSubtreeSize(CxTree *tree, void *subtree_root);
257
258 size_t cxTreeSubtreeDepth(CxTree *tree, void *subtree_root);
259
260 size_t cxTreeSize(CxTree *tree);
261
262 size_t cxTreeDepth(CxTree *tree);
263 ```
264
265 The function `cxTreeSubtreeSize()` counts all nodes belonging to the subtree starting with `subtree_root`.
266
267 The function `cxTreeSubtreeDepth()` reports the maximum depth of the subtree starting with `subtree_root`.
268 If the `subtree_root` does not have any children, this results in a depth of one.
269
270 The functions `cxTreeSize()` and `cxTreeDepth()` are equivalent to `cxTreeSubtreeSize()` and `cxTreeSubtreeDepth()`, respectively, where `subtree_root` is the root node of the entire tree.
271
272 > Passing a `NULL` pointer as `subtree_root` makes those functions return zero.
273
274 ## Search
275
276 ```C
277 #include <cx/tree.h>
278
279 #define CX_TREE_SEARCH_INFINITE_DEPTH
280
281 int cx_tree_search_data(const void *root, size_t max_depth,
282 const void *data, cx_tree_search_data_func sfunc,
283 void **result, ptrdiff_t loc_children, ptrdiff_t loc_next);
284
285 int cx_tree_search(const void *root, size_t max_depth,
286 const void *node, cx_tree_search_func sfunc,
287 void **result, ptrdiff_t loc_children, ptrdiff_t loc_next);
288
289 void *cxTreeFind(CxTree *tree, const void *data);
290
291 void *cxTreeFindInSubtree(CxTree *tree, const void *data,
292 void *subtree_root, size_t max_depth);
293 ```
294
295 The functions `cx_tree_search_data()` and `cx_tree_search()` are equivalent,
296 except that `cx_tree_search_data()` compares a currently investigated node against the `data` with the specified `cx_tree_search_data_func`,
297 and `cx_tree_search()` compares against a `node` with the specified `cx_tree_search_func`.
298
299 Usually you the latter is rarely needed.
300 It is used, for example, by `cx_tree_add()` to find the correct position where to add a freshly created node.
301
302 The search proceeds as follows, starting with the `root` node:
303
304 1. The current node is compared with `data` / `node` using the `sfunc`.
305 2. If `sfunc` returns zero, a matching node has been found and the pointer to that node is stored at the location given by `result`.
306 3. If `sfunc` returns a negative number, the entire subtree is skipped.
307 4. If `sfunc` returns a positive number, the subtree is searched, unless the number is larger than the number of an already searched subtree. The best match will be stored at the location given by `result`.
308 5. The return value will be the return value of the `sfunc` for node that was stored in the `result`, or a negative number when no match was found
309
310 > If the `sfunc` implements some kind of metric, the search functions will return the best match in the tree with respect to that metric.
311 > When a positive number is returned, it means that a new node with the searched data could be added as a child of the found node.
312 > This is exactly how `cx_tree_add()` finds the best position to add a node to the tree.
313
314 The function `cxTreeFind()` uses the `search_data_func` of the `CxTree`
315 to find the `data` in the tree, and returns a pointer to the node when the data was found (or `NULL`, otherwise).
316
317 The function `cxTreeFindInSubtree()` is equivalent, except that it restricts the search to nodes
318 in the subtree starting with (and including) `subtree_root`, and skipping all nodes below the `max_depth`.
319 Note, that the `max_depth` is specified in relation to the `subtree_root` and not in relation to the entire tree.
320
321 ## Iterator and Visitor
322
323 ```C
324 #include <cx/tree.h>
325
326 CxTreeIterator cx_tree_iterator(void *root, bool visit_on_exit,
327 ptrdiff_t loc_children, ptrdiff_t loc_next);
328
329 CxTreeIterator cxTreeIterate(CxTree *tree, bool visit_on_exit);
330
331 CxTreeIterator cxTreeIterateSubtree(CxTree *tree,
332 void *node, bool visit_on_exit);
333
334 #define cxTreeIteratorContinue(iter)
335
336 void cxTreeIteratorDispose(CxTreeIterator *iter);
337
338
339 CxTreeVisitor cx_tree_visitor(void *root,
340 ptrdiff_t loc_children, ptrdiff_t loc_next);
341
342 CxTreeVisitor cxTreeVisit(CxTree *tree);
343
344 CxTreeVisitor cxTreeVisitSubtree(CxTree *tree, void *node)
345
346 #define cxTreeVisitorContinue(visitor)
347
348 void cxTreeVisitorDispose(CxTreeVisitor *visitor);
349 ```
350
351 There are two different kinds of iterators for trees: one for depth-first iteration and one for breadth-first iteration.
352
353 The `CxTreeIterator` is performing a depth-first iteration with the capability of visiting a node twice:
354 first when the iterator enters the node coming from its parent, and secondly when the iterator tracks back from its last child.
355 This behavior is controlled via the `visit_on_exit` argument.
356 When set to `true`, the iterators `exiting` flag can be checked during iteration to see whether the iterator is currently entering or leaving the node.
357 The above [example](#example-for-wrapping-a-libxml2-tree) for iterating through an XML tree illustrates this.
358
359 On the other hand, the `CxTreeVisitor` performs a breadth-first iteration and visits every node only once.
360
361 Both iterators do not support the removal of nodes.
362
363 Since tree iteration needs to keep track of a stack (depth-first) or queue (breadth-first), internal memory is allocated.
364 This memory is _automatically_ disposed of when the iteration _completes_.
365 If you break from the iteration early, you must call `cxTreeIteratorDispose()` or `cxTreeVisitorDispose()`, respectively, to deallocate the memory.
366
367 > It is recommended to always invoke the dispose functions, even when it seems not necessary.
368 > In the best case it just does nothing, but calling them guarantees that no memory can be leaking, even when your code will change in the future.
369 >{style="note"}
370
371 The macros `cxTreeIteratorContinue()` and `cxTreeVisitorContinue()` equivalently instruct the iterator/visitor to skip the subtree below the currently inspected node.
372
373 ## Remove
374
375 ```C
376 #include <cx/tree.h>
377
378 void cx_tree_unlink(void *node, ptrdiff_t loc_parent,
379 ptrdiff_t loc_children, ptrdiff_t loc_last_child,
380 ptrdiff_t loc_prev, ptrdiff_t loc_next);
381
382 int cxTreeRemoveNode(CxTree *tree, void *node,
383 cx_tree_relink_func relink_func);
384
385 void cxTreeRemoveSubtree(CxTree *tree, void *node);
386 ```
387
388 The low-level function `cx_tree_unlink()` removes the specified `node`,
389 as well as the entire subtree beneath that node, from its parent.
390 The high-level counterpart is `cxTreeRemoveSubtree()`.
391
392 The function `cxTreeRemoveNode()`, on the other hand, _only_ removes the `node` from the tree,
393 links all children of `node` to the former parent of `node`,
394 and calls the optional `relink_func` for every former child of `node` which will be relinked to a new parent.
395 Therefore, calling `cxTreeRemoveNode()` on the `root` node is an error and the function returns non-zero.
396 In all other cases, the function returns zero.
397
398 > When your tree is storing a scene graph, for example, a possible use-case for the `relink_func` might be updating
399 > the world transform matrices in the subtree of the removed node.
400
401 ## Dispose
402
403 ```C
404 #include <cx/tree.h>
405
406 int cxTreeDestroyNode(CxTree *tree, void *node,
407 cx_tree_relink_func relink_func);
408
409 void cxTreeDestroySubtree(CxTree *tree, void *node);
410
411 void cxTreeClear(CxTree *tree);
412
413 void cxTreeFree(CxTree *tree);
414 ```
415
416 The function `cxTreeDestroyNode()` first [removes](#remove) the `node` from the tree, like `cxTreeRemoveNode()`,
417 and then invokes the [destructor functions](collection.h.md#destructor-functions).
418 It is guaranteed that the simple destructor is called before the advanced destructor.
419 If no destructor function is registered at all, the behavior is identical to `cxTreeRemoveNode()`.
420 That means this function does not deallocate the memory for the node on its own and leaves that entirely to the destructor functions.
421
422 The function `cxTreeDestroySubtree()` performs the above actions for the entire subtree starting with `node`.
423 The order in which the destructor functions for the nodes of the subtree are called is determined by a [tree iterator](#iterator-and-visitor).
424
425 The function `cxTreeClear()` is a shorthand for invoking `cxTreeDestroySubtree()` on the root node of the tree.
426
427 The function `cxTreeFree()` behaves like `cxTreeClear()` and then deallocates the memory for the `CxTree` structure.
428
429 > Although `CxTree` supports the general concept of [destructor functions](collection.h.md#destructor-functions),
430 > it is not based on `CX_COLLECTION_BASE`.
431 > Therefore, the `cxDefineDestructor()` and `cxDefineAdvancedDestructor()` macros cannot be used on a `CxTree` and
432 > the fields must be set manually.
433 >{style="note"}
434
435 <seealso>
436 <category ref="apidoc">
437 <a href="https://ucx.sourceforge.io/api/tree_8h.html">tree.h</a>
438 </category>
439 </seealso>
440
441