13 |
13 |
14 The `CX_TREE_NODE_BASE` macro declares four pointers of type `Type*`: |
14 The `CX_TREE_NODE_BASE` macro declares four pointers of type `Type*`: |
15 `parent`, `children`, `last_child`, `prev`, and `next`, |
15 `parent`, `children`, `last_child`, `prev`, and `next`, |
16 which must be placed as first member into your struct. |
16 which must be placed as first member into your struct. |
17 |
17 |
18 You can use it for example like this: |
18 You can use it, for example, like this: |
19 ```C |
19 ```C |
20 typedef struct my_tree_node_s { |
20 typedef struct my_tree_node_s { |
21 CX_TREE_NODE_BASE(struct my_tree_node_s); |
21 CX_TREE_NODE_BASE(struct my_tree_node_s); |
22 int value; |
22 int value; |
23 char *desc; |
23 char *desc; |
104 |
104 |
105 If your wrapped tree structure does not have a `last_child` or a `prev` pointer, |
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. |
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. |
107 All other pointers are mandatory and a non-negative location is expected. |
108 |
108 |
109 Note, that a wrapped tree by default has no create or search functions assigned. |
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, |
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. |
111 you will have to set them manually by assigning to the respective fields in the `CxTree` structure. |
112 |
112 |
113 ### Example for wrapping a libxml2 tree |
113 ### Example for wrapping a libxml2 tree |
114 |
114 |
302 The search proceeds as follows, starting with the `root` node: |
302 The search proceeds as follows, starting with the `root` node: |
303 |
303 |
304 1. The current node is compared with `data` / `node` using the `sfunc`. |
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`. |
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. |
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`. |
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 |
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 |
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. |
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. |
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. |
312 > This is exactly how `cx_tree_add()` finds the best position to add a node to the tree. |
313 |
313 |
314 The function `cxTreeFind()` uses the `search_data_func` of the `CxTree` |
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). |
315 to find the `data` in the tree, and returns a pointer to the node when the data was found (or `NULL`, otherwise). |
316 |
316 |
346 #define cxTreeVisitorContinue(visitor) |
346 #define cxTreeVisitorContinue(visitor) |
347 |
347 |
348 void cxTreeVisitorDispose(CxTreeVisitor *visitor); |
348 void cxTreeVisitorDispose(CxTreeVisitor *visitor); |
349 ``` |
349 ``` |
350 |
350 |
351 There are two different kind of iterators for trees. |
351 There are two different kinds of iterators for trees. |
352 The `CxTreeIterator` is performing a depth-first iteration with the capability of visiting a node twice: |
352 The `CxTreeIterator` is performing a depth-first iteration with the capability of visiting a node twice: |
353 first when the iterator enters the node coming from its parent, and secondly when the iterator tracks back from its last child. |
353 first when the iterator enters the node coming from its parent, and secondly when the iterator tracks back from its last child. |
354 This behavior is controlled via the `visit_on_exit` argument. |
354 This behavior is controlled via the `visit_on_exit` argument. |
355 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. |
355 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. |
356 The above [example](#example-for-wrapping-a-libxml2-tree) for iterating through an XML tree illustrates this. |
356 The above [example](#example-for-wrapping-a-libxml2-tree) for iterating through an XML tree illustrates this. |
357 |
357 |
358 On the other hand, the `CxTreeVisitor` performs a breadth-first iteration and visits every node only once. |
358 On the other hand, the `CxTreeVisitor` performs a breadth-first iteration and visits every node only once. |
359 |
359 |
360 Since tree iteration needs to keep track of a stack (depth-first) or queue (breadth-frist), internal memory is allocated. |
360 Since tree iteration needs to keep track of a stack (depth-first) or queue (breadth-first), internal memory is allocated. |
361 This memory is _automatically_ disposed when the iteration _completes_. |
361 This memory is _automatically_ disposed of when the iteration _completes_. |
362 If you break from the iteration early, you must call `cxTreeIteratorDispose()` or `cxTreeVisitorDispose()`, respectively, to deallocate the memory. |
362 If you break from the iteration early, you must call `cxTreeIteratorDispose()` or `cxTreeVisitorDispose()`, respectively, to deallocate the memory. |
363 |
363 |
364 > It is recommended to always invoke the dispose functions, even when it seems not necessary. |
364 > It is recommended to always invoke the dispose functions, even when it seems not necessary. |
365 > In the best case it just does nothing, but calling them guarantees that no memory can be leaking, even when your code changes in the future. |
365 > 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. |
366 >{style="note"} |
366 >{style="note"} |
367 |
367 |
368 The macros `cxTreeIteratorContinue()` and `cxTreeVisitorContinue()` equivalently instruct the iterator/visitor to skip the subtree below the currently inspected node. |
368 The macros `cxTreeIteratorContinue()` and `cxTreeVisitorContinue()` equivalently instruct the iterator/visitor to skip the subtree below the currently inspected node. |
369 |
369 |
370 ## Remove |
370 ## Remove |
410 void cxTreeFree(CxTree *tree); |
410 void cxTreeFree(CxTree *tree); |
411 ``` |
411 ``` |
412 |
412 |
413 The function `cxTreeDestroyNode()` first [removes](#remove) the `node` from the tree, like `cxTreeRemoveNode()`, |
413 The function `cxTreeDestroyNode()` first [removes](#remove) the `node` from the tree, like `cxTreeRemoveNode()`, |
414 and then invokes the [destructor functions](collection.h.md#destructor-functions). |
414 and then invokes the [destructor functions](collection.h.md#destructor-functions). |
415 It is guaranteed, that the simple destructor is called before the advanced destructor. |
415 It is guaranteed that the simple destructor is called before the advanced destructor. |
416 If no destructor function is registered at all, the behavior is identical to `cxTreeRemoveNode()`. |
416 If no destructor function is registered at all, the behavior is identical to `cxTreeRemoveNode()`. |
417 That means, this function does not deallocate the memory for the node on its own and leaves that entirely to the destructor functions. |
417 That means this function does not deallocate the memory for the node on its own and leaves that entirely to the destructor functions. |
418 |
418 |
419 The function `cxTreeDestroySubtree()` performs the above actions for the entire subtree starting with `node`. |
419 The function `cxTreeDestroySubtree()` performs the above actions for the entire subtree starting with `node`. |
420 The order in which the destructor functions for the nodes of the subtree are called are determined by a [tree iterator](#iterator-and-visitor). |
420 The order in which the destructor functions for the nodes of the subtree are called is determined by a [tree iterator](#iterator-and-visitor). |
421 |
421 |
422 The function `cxTreeClear()` is a shorthand for invoking `cxTreeDestroySubtree()` on the root node of the tree. |
422 The function `cxTreeClear()` is a shorthand for invoking `cxTreeDestroySubtree()` on the root node of the tree. |
423 |
423 |
424 The function `cxTreeFree()` behaves like `cxTreeClear()` and then deallocates the memory for the `CxTree` structure. |
424 The function `cxTreeFree()` behaves like `cxTreeClear()` and then deallocates the memory for the `CxTree` structure. |
425 |
425 |