docs/Writerside/topics/tree.h.md

changeset 1694
a2757c6427cc
parent 1690
7d41291b3095
equal deleted inserted replaced
1693:c2d05cf1a062 1694:a2757c6427cc
1 # Tree 1 # Tree
2 2
3 UCX provides several low-level functions for working with arbitrary tree structures, 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. 4 as well as some high-level functions for trees with a configurable node layout.
5 5
6 The following convenience macro allows you to declare and use simple tree structures. 6 The following convenience macro allows you to declare and use simple tree structures.
7 7
8 ```C 8 ```C
9 #define CX_TREE_NODE(Type) 9 #define CX_TREE_NODE(Type)
137 void cxTreeSetParent(CxTree *tree, void *parent, void *child); 137 void cxTreeSetParent(CxTree *tree, void *parent, void *child);
138 138
139 void *cxTreeSetRoot(CxTree *tree, void *root); 139 void *cxTreeSetRoot(CxTree *tree, void *root);
140 ``` 140 ```
141 141
142 The above functions are used to add nodes to a tree.
143
142 The low-level function `cx_tree_add()` adds a `node` to a new `parent`, unlinking it from its previous parent, if required. 144 The low-level function `cx_tree_add()` adds a `node` to a new `parent`, unlinking it from its previous parent, if required.
143 145
144 When you have created a high-level tree that is still empty, you can create a root node with `cxTreeCreateRoot()` or `cxTreeCreateRootData()`. 146 When you have created a high-level tree that is still empty, you can create a root node with `cxTreeCreateRoot()` or `cxTreeCreateRootData()`.
145 Both functions return an existing root node, if present, and `NULL` when the allocation of a new node failed. 147 Both functions return an existing root node, if present, and `NULL` when the allocation of a new node failed.
146 148
147 The functions `cxTreeAddData()`, `cxTreeAddNode()`, and `cxTreeSetParent()` are similar to `cx_tree_add()`. 149 The functions `cxTreeAddData()`, `cxTreeAddNode()`, and `cxTreeSetParent()` are similar to `cx_tree_add()`.
148 The difference between `cxTreeAddData()` and `cxTreeAddNode()` is, 150 The difference between `cxTreeAddData()` and `cxTreeAddNode()` is
149 that `cxTreeAddData()` uses the allocator of the `CxTree` to create the node first, before adding it. 151 that `cxTreeAddData()` uses the allocator of the `CxTree` to create the node first before adding it.
150 The function returns `NULL` in case the creation of the node fails, or the created node when creation was successful. 152 The function returns `NULL` in case the creation of the node fails, or the created node when creation was successful.
151 The difference between `cxTreeSetParent()` and `cxTreeAddNode()` is, 153 The difference between `cxTreeSetParent()` and `cxTreeAddNode()` is
152 that `cxTreeSetParent()` does not increase the tree size, when `child` already had a parent. 154 that `cxTreeSetParent()` does not increase the tree size when `child` already had a parent.
153 155
154 When you want to use `cxTreeCreateRootData()` or `cxTreeAddData()`, 156 When you want to use `cxTreeCreateRootData()` or `cxTreeAddData()`,
155 the `loc_data` parameter of `cxTreeCreate()` must have been set to a non-negative value. 157 the `loc_data` parameter of `cxTreeCreate()` must have been set to a non-negative value.
156 Otherwise, the functions will return `NULL`. 158 Otherwise, the functions will return `NULL`.
157 159
213 const void *data, cx_tree_search_func sfunc, void **result, 215 const void *data, cx_tree_search_func sfunc, void **result,
214 bool use_dfs, ptrdiff_t loc_children, ptrdiff_t loc_next); 216 bool use_dfs, ptrdiff_t loc_children, ptrdiff_t loc_next);
215 217
216 void *cxTreeFindFast(CxTree *tree, const void *data, 218 void *cxTreeFindFast(CxTree *tree, const void *data,
217 cx_tree_search_func sfunc); 219 cx_tree_search_func sfunc);
220
221 void *cxTreeFindFastInSubtree(CxTree *tree, const void *data,
222 cx_tree_search_func sfunc,
223 void *subtree_root, size_t max_depth);
218 224
219 void *cxTreeFind(CxTree *tree, const void *data, bool use_dfs); 225 void *cxTreeFind(CxTree *tree, const void *data, bool use_dfs);
220 226
221 void *cxTreeFindInSubtree(CxTree *tree, const void *data, 227 void *cxTreeFindInSubtree(CxTree *tree, const void *data,
222 void *subtree_root, size_t max_depth, bool use_dfs); 228 void *subtree_root, size_t max_depth, bool use_dfs);
225 The function `cx_tree_search()` efficiently finds a node in the tree. 231 The function `cx_tree_search()` efficiently finds a node in the tree.
226 232
227 The search proceeds as follows, starting with the `root` node: 233 The search proceeds as follows, starting with the `root` node:
228 234
229 1. The current node is compared with `data` using the `sfunc`. 235 1. The current node is compared with `data` using the `sfunc`.
230 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`. 236 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`.
231 3. If `sfunc` returns a negative number, the entire subtree is skipped. 237 3. If `sfunc` returns a negative number, the entire subtree is skipped.
232 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`. 238 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`.
233 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 239 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
234 240
235 > If the `sfunc` implements some kind of metric, the search functions will return the best match in the tree with respect to that metric. 241 > If the `sfunc` implements some kind of metric, the search functions will return the best match in the tree with respect to that metric.
236 > 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. 242 > 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.
237 243
238 The function `cxTreeFindFast()` uses the `sfunc` to find the `data` in the tree, and returns a pointer to the node when the data was found (or `NULL`, otherwise). 244 The function `cxTreeFindFast()` uses the `sfunc` to find the `data` in the tree and returns a pointer to the node when the data was found (or `NULL`, otherwise).
239 245
240 The function `cxTreeFind()` instead traverses the entire tree (either with breadth-first search or depth-first search) 246 The function `cxTreeFind()` instead traverses the entire tree (either with breadth-first search or depth-first search)
241 and compares the `data` with the collections [comparator function](collection.h.md#comparator-functions). 247 and compares the `data` with the collections [comparator function](collection.h.md#comparator-functions).
242 For this it is necessary that the `loc_data` was specified when creating the tree, or the function will immediately return `NULL`. 248 For this it is necessary that the `loc_data` was specified when creating the tree, or the function will immediately return `NULL`.
243 249
244 The functions `cxTreeFindFastInSubtree()` and `cxTreeFindInSubtree()` are similar, except that they restrict the search to nodes 250 The functions `cxTreeFindFastInSubtree()` and `cxTreeFindInSubtree()` are similar, except that they restrict the search to nodes
245 in the subtree starting with (and including) `subtree_root`, and skipping all nodes below the `max_depth`. 251 in the subtree starting with (and including) `subtree_root`, and skipping all nodes below the `max_depth`.
246 Note, that the `max_depth` is specified in relation to the `subtree_root` and not in relation to the entire tree. 252 Note that the `max_depth` is specified in relation to the `subtree_root` and not in relation to the entire tree.
247 253
248 ## Iterator and Visitor 254 ## Iterator and Visitor
249 255
250 ```C 256 ```C
251 #include <cx/tree.h> 257 #include <cx/tree.h>
288 294
289 > It is recommended to always invoke the dispose functions, even when it seems not necessary. 295 > It is recommended to always invoke the dispose functions, even when it seems not necessary.
290 > 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. 296 > 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.
291 >{style="note"} 297 >{style="note"}
292 298
293 The macro `cxTreeIteratorContinue()` instruct the iterator to skip the subtree below the currently inspected node. 299 The macro `cxTreeIteratorContinue()` instructs the iterator to skip the subtree below the currently inspected node.
294 300
295 > In contrast to iterators over [lists](list.h.md#iterators) or [maps](map.h.md#iterators), 301 > In contrast to iterators over [lists](list.h.md#iterators) or [maps](map.h.md#iterators),
296 > a tree iterator is _always_ iterating over the nodes. 302 > a tree iterator is _always_ iterating over the nodes.
297 > That means, the pointer in a `cx_foreach` loop is always expected to be a pointer to a node and not a pointer to 303 > That means, the pointer in a `cx_foreach` loop is always expected to be a pointer to a node and not a pointer to
298 > the element / payload within the node. 304 > the element / payload within the node.
322 The high-level counterpart is `cxTreeRemoveSubtree()`. 328 The high-level counterpart is `cxTreeRemoveSubtree()`.
323 329
324 The function `cxTreeRemoveNode()`, on the other hand, _only_ removes the `node` from the tree, 330 The function `cxTreeRemoveNode()`, on the other hand, _only_ removes the `node` from the tree,
325 links all children of `node` to the former parent of `node`, 331 links all children of `node` to the former parent of `node`,
326 and calls the optional `relink_func` for every former child of `node` which will be relinked to a new parent. 332 and calls the optional `relink_func` for every former child of `node` which will be relinked to a new parent.
327 Therefore, calling `cxTreeRemoveNode()` on the `root` node is an error and the function returns non-zero. 333 Therefore, calling `cxTreeRemoveNode()` on the `root` node is an error, and the function returns non-zero.
328 In all other cases, the function returns zero. 334 In all other cases, the function returns zero.
329 335
330 > When your tree is storing a scene graph, for example, a possible use-case for the `relink_func` might be updating 336 > When your tree is storing a scene graph, for example, a possible use-case for the `relink_func` might be updating
331 > the world transform matrices in the subtree of the removed node. 337 > the world transform matrices in the subtree of the removed node.
332 338
355 That means this function does not deallocate the memory for the node on its own and leaves that entirely to the destructor functions. 361 That means this function does not deallocate the memory for the node on its own and leaves that entirely to the destructor functions.
356 362
357 The function `cxTreeDestroySubtree()` performs the above actions for the entire subtree starting with `node`. 363 The function `cxTreeDestroySubtree()` performs the above actions for the entire subtree starting with `node`.
358 The order in which the destructor functions for the nodes of the subtree are called is determined by a [tree iterator](#iterator-and-visitor). 364 The order in which the destructor functions for the nodes of the subtree are called is determined by a [tree iterator](#iterator-and-visitor).
359 365
360 The function `cxTreeClear()` is a shorthand for invoking `cxTreeDestroySubtree()` on the root node of the tree. 366 The function `cxTreeClear()` is short for invoking `cxTreeDestroySubtree()` on the root node of the tree if it exists.
361 367
362 The function `cxTreeFree()` behaves like `cxTreeClear()` and then deallocates the memory for the `CxTree` structure. 368 The function `cxTreeFree()` behaves like `cxTreeClear()` and then deallocates the memory for the `CxTree` structure.
363 369
364 > In contrast to other collections, the destructor functions of a `CxTree` are _always_ invoked with pointers to the _nodes_ 370 > In contrast to other collections, the destructor functions of a `CxTree` are _always_ invoked with pointers to the _nodes_
365 > and not to pointers to the elements / the payload of the nodes. 371 > and not to pointers to the elements / the payload of the nodes.

mercurial