| 207 |
207 |
| 208 /** |
208 /** |
| 209 * Releases internal memory of the given tree iterator. |
209 * Releases internal memory of the given tree iterator. |
| 210 * @param iter the iterator |
210 * @param iter the iterator |
| 211 */ |
211 */ |
| 212 __attribute__((__nonnull__)) |
212 cx_attr_nonnull |
| 213 static inline void cxTreeIteratorDispose(CxTreeIterator *iter) { |
213 static inline void cxTreeIteratorDispose(CxTreeIterator *iter) { |
| 214 free(iter->stack); |
214 free(iter->stack); |
| 215 iter->stack = NULL; |
215 iter->stack = NULL; |
| 216 } |
216 } |
| 217 |
217 |
| 218 /** |
218 /** |
| 219 * Releases internal memory of the given tree visitor. |
219 * Releases internal memory of the given tree visitor. |
| 220 * @param visitor the visitor |
220 * @param visitor the visitor |
| 221 */ |
221 */ |
| 222 __attribute__((__nonnull__)) |
222 cx_attr_nonnull |
| 223 static inline void cxTreeVisitorDispose(CxTreeVisitor *visitor) { |
223 static inline void cxTreeVisitorDispose(CxTreeVisitor *visitor) { |
| 224 struct cx_tree_visitor_queue_s *q = visitor->queue_next; |
224 struct cx_tree_visitor_queue_s *q = visitor->queue_next; |
| 225 while (q != NULL) { |
225 while (q != NULL) { |
| 226 struct cx_tree_visitor_queue_s *next = q->next; |
226 struct cx_tree_visitor_queue_s *next = q->next; |
| 227 free(q); |
227 free(q); |
| 260 * the last child in the linked list (negative if there is no such pointer) |
260 * the last child in the linked list (negative if there is no such pointer) |
| 261 * @param loc_prev optional offset in the node struct for the prev pointer |
261 * @param loc_prev optional offset in the node struct for the prev pointer |
| 262 * @param loc_next offset in the node struct for the next pointer |
262 * @param loc_next offset in the node struct for the next pointer |
| 263 * @see cx_tree_unlink() |
263 * @see cx_tree_unlink() |
| 264 */ |
264 */ |
| 265 __attribute__((__nonnull__)) |
265 cx_attr_nonnull |
| 266 void cx_tree_link( |
266 void cx_tree_link( |
| 267 void *restrict parent, |
267 void *restrict parent, |
| 268 void *restrict node, |
268 void *restrict node, |
| 269 ptrdiff_t loc_parent, |
269 ptrdiff_t loc_parent, |
| 270 ptrdiff_t loc_children, |
270 ptrdiff_t loc_children, |
| 285 * the last child in the linked list (negative if there is no such pointer) |
285 * the last child in the linked list (negative if there is no such pointer) |
| 286 * @param loc_prev optional offset in the node struct for the prev pointer |
286 * @param loc_prev optional offset in the node struct for the prev pointer |
| 287 * @param loc_next offset in the node struct for the next pointer |
287 * @param loc_next offset in the node struct for the next pointer |
| 288 * @see cx_tree_link() |
288 * @see cx_tree_link() |
| 289 */ |
289 */ |
| 290 __attribute__((__nonnull__)) |
290 cx_attr_nonnull |
| 291 void cx_tree_unlink( |
291 void cx_tree_unlink( |
| 292 void *node, |
292 void *node, |
| 293 ptrdiff_t loc_parent, |
293 ptrdiff_t loc_parent, |
| 294 ptrdiff_t loc_children, |
294 ptrdiff_t loc_children, |
| 295 ptrdiff_t loc_last_child, |
295 ptrdiff_t loc_last_child, |
| 326 * |
326 * |
| 327 * @return 0 if the node contains the data, |
327 * @return 0 if the node contains the data, |
| 328 * positive if one of the children might contain the data, |
328 * positive if one of the children might contain the data, |
| 329 * negative if neither the node, nor the children contains the data |
329 * negative if neither the node, nor the children contains the data |
| 330 */ |
330 */ |
| |
331 cx_attr_nonnull |
| 331 typedef int (*cx_tree_search_data_func)(const void *node, const void *data); |
332 typedef int (*cx_tree_search_data_func)(const void *node, const void *data); |
| 332 |
333 |
| 333 |
334 |
| 334 /** |
335 /** |
| 335 * Function pointer for a search function. |
336 * Function pointer for a search function. |
| 355 * |
356 * |
| 356 * @return 0 if \p node contains the same data as \p new_node, |
357 * @return 0 if \p node contains the same data as \p new_node, |
| 357 * positive if one of the children might contain the data, |
358 * positive if one of the children might contain the data, |
| 358 * negative if neither the node, nor the children contains the data |
359 * negative if neither the node, nor the children contains the data |
| 359 */ |
360 */ |
| |
361 cx_attr_nonnull |
| 360 typedef int (*cx_tree_search_func)(const void *node, const void *new_node); |
362 typedef int (*cx_tree_search_func)(const void *node, const void *new_node); |
| 361 |
363 |
| 362 /** |
364 /** |
| 363 * Searches for data in a tree. |
365 * Searches for data in a tree. |
| 364 * |
366 * |
| 381 * @param loc_next offset in the node struct for the next pointer |
383 * @param loc_next offset in the node struct for the next pointer |
| 382 * @return zero if the node was found exactly, positive if a node was found that |
384 * @return zero if the node was found exactly, positive if a node was found that |
| 383 * could contain the node (but doesn't right now), negative if the tree does not |
385 * could contain the node (but doesn't right now), negative if the tree does not |
| 384 * contain any node that might be related to the searched data |
386 * contain any node that might be related to the searched data |
| 385 */ |
387 */ |
| 386 __attribute__((__nonnull__)) |
388 cx_attr_nonnull |
| |
389 cx_attr_access_w(5) |
| 387 int cx_tree_search_data( |
390 int cx_tree_search_data( |
| 388 const void *root, |
391 const void *root, |
| 389 size_t depth, |
392 size_t depth, |
| 390 const void *data, |
393 const void *data, |
| 391 cx_tree_search_data_func sfunc, |
394 cx_tree_search_data_func sfunc, |
| 416 * @param loc_next offset in the node struct for the next pointer |
419 * @param loc_next offset in the node struct for the next pointer |
| 417 * @return zero if the node was found exactly, positive if a node was found that |
420 * @return zero if the node was found exactly, positive if a node was found that |
| 418 * could contain the node (but doesn't right now), negative if the tree does not |
421 * could contain the node (but doesn't right now), negative if the tree does not |
| 419 * contain any node that might be related to the searched data |
422 * contain any node that might be related to the searched data |
| 420 */ |
423 */ |
| 421 __attribute__((__nonnull__)) |
424 cx_attr_nonnull |
| |
425 cx_attr_access_w(5) |
| 422 int cx_tree_search( |
426 int cx_tree_search( |
| 423 const void *root, |
427 const void *root, |
| 424 size_t depth, |
428 size_t depth, |
| 425 const void *node, |
429 const void *node, |
| 426 cx_tree_search_func sfunc, |
430 cx_tree_search_func sfunc, |
| 447 * @param loc_children offset in the node struct for the children linked list |
451 * @param loc_children offset in the node struct for the children linked list |
| 448 * @param loc_next offset in the node struct for the next pointer |
452 * @param loc_next offset in the node struct for the next pointer |
| 449 * @return the new tree iterator |
453 * @return the new tree iterator |
| 450 * @see cxTreeIteratorDispose() |
454 * @see cxTreeIteratorDispose() |
| 451 */ |
455 */ |
| |
456 cx_attr_nodiscard |
| 452 CxTreeIterator cx_tree_iterator( |
457 CxTreeIterator cx_tree_iterator( |
| 453 void *root, |
458 void *root, |
| 454 bool visit_on_exit, |
459 bool visit_on_exit, |
| 455 ptrdiff_t loc_children, |
460 ptrdiff_t loc_children, |
| 456 ptrdiff_t loc_next |
461 ptrdiff_t loc_next |
| 472 * @param loc_children offset in the node struct for the children linked list |
477 * @param loc_children offset in the node struct for the children linked list |
| 473 * @param loc_next offset in the node struct for the next pointer |
478 * @param loc_next offset in the node struct for the next pointer |
| 474 * @return the new tree visitor |
479 * @return the new tree visitor |
| 475 * @see cxTreeVisitorDispose() |
480 * @see cxTreeVisitorDispose() |
| 476 */ |
481 */ |
| |
482 cx_attr_nodiscard |
| 477 CxTreeVisitor cx_tree_visitor( |
483 CxTreeVisitor cx_tree_visitor( |
| 478 void *root, |
484 void *root, |
| 479 ptrdiff_t loc_children, |
485 ptrdiff_t loc_children, |
| 480 ptrdiff_t loc_next |
486 ptrdiff_t loc_next |
| 481 ); |
487 ); |
| 488 * created node or \c NULL when allocation fails. |
494 * created node or \c NULL when allocation fails. |
| 489 * |
495 * |
| 490 * \note the function may leave the node pointers in the struct uninitialized. |
496 * \note the function may leave the node pointers in the struct uninitialized. |
| 491 * The caller is responsible to set them according to the intended use case. |
497 * The caller is responsible to set them according to the intended use case. |
| 492 */ |
498 */ |
| |
499 cx_attr_nonnull_arg(1) |
| 493 typedef void *(*cx_tree_node_create_func)(const void *, void *); |
500 typedef void *(*cx_tree_node_create_func)(const void *, void *); |
| 494 |
501 |
| 495 /** |
502 /** |
| 496 * The local search depth for a new subtree when adding multiple elements. |
503 * The local search depth for a new subtree when adding multiple elements. |
| 497 * The default value is 3. |
504 * The default value is 3. |
| 536 * @param loc_prev optional offset in the node struct for the prev pointer |
543 * @param loc_prev optional offset in the node struct for the prev pointer |
| 537 * @param loc_next offset in the node struct for the next pointer |
544 * @param loc_next offset in the node struct for the next pointer |
| 538 * @return the number of nodes created and added |
545 * @return the number of nodes created and added |
| 539 * @see cx_tree_add() |
546 * @see cx_tree_add() |
| 540 */ |
547 */ |
| 541 __attribute__((__nonnull__(1, 3, 4, 6, 7))) |
548 cx_attr_nonnull_arg(1, 3, 4, 6, 7) |
| |
549 cx_attr_access_w(6) |
| 542 size_t cx_tree_add_iter( |
550 size_t cx_tree_add_iter( |
| 543 struct cx_iterator_base_s *iter, |
551 struct cx_iterator_base_s *iter, |
| 544 size_t num, |
552 size_t num, |
| 545 cx_tree_search_func sfunc, |
553 cx_tree_search_func sfunc, |
| 546 cx_tree_node_create_func cfunc, |
554 cx_tree_node_create_func cfunc, |
| 589 * @param loc_prev optional offset in the node struct for the prev pointer |
597 * @param loc_prev optional offset in the node struct for the prev pointer |
| 590 * @param loc_next offset in the node struct for the next pointer |
598 * @param loc_next offset in the node struct for the next pointer |
| 591 * @return the number of array elements successfully processed |
599 * @return the number of array elements successfully processed |
| 592 * @see cx_tree_add() |
600 * @see cx_tree_add() |
| 593 */ |
601 */ |
| 594 __attribute__((__nonnull__(1, 4, 5, 7, 8))) |
602 cx_attr_nonnull_arg(1, 4, 5, 7, 8) |
| |
603 cx_attr_access_w(7) |
| 595 size_t cx_tree_add_array( |
604 size_t cx_tree_add_array( |
| 596 const void *src, |
605 const void *src, |
| 597 size_t num, |
606 size_t num, |
| 598 size_t elem_size, |
607 size_t elem_size, |
| 599 cx_tree_search_func sfunc, |
608 cx_tree_search_func sfunc, |
| 651 * @param loc_prev optional offset in the node struct for the prev pointer |
660 * @param loc_prev optional offset in the node struct for the prev pointer |
| 652 * @param loc_next offset in the node struct for the next pointer |
661 * @param loc_next offset in the node struct for the next pointer |
| 653 * @return zero when a new node was created and added to the tree, |
662 * @return zero when a new node was created and added to the tree, |
| 654 * non-zero otherwise |
663 * non-zero otherwise |
| 655 */ |
664 */ |
| 656 __attribute__((__nonnull__(1, 2, 3, 5, 6))) |
665 cx_attr_nonnull_arg(1, 2, 3, 5, 6) |
| |
666 cx_attr_access_w(5) |
| 657 int cx_tree_add( |
667 int cx_tree_add( |
| 658 const void *src, |
668 const void *src, |
| 659 cx_tree_search_func sfunc, |
669 cx_tree_search_func sfunc, |
| 660 cx_tree_node_create_func cfunc, |
670 cx_tree_node_create_func cfunc, |
| 661 void *cdata, |
671 void *cdata, |
| 838 * Member function for inserting multiple elements. |
849 * Member function for inserting multiple elements. |
| 839 * |
850 * |
| 840 * Implementations SHALL avoid to perform a full search in the tree for |
851 * Implementations SHALL avoid to perform a full search in the tree for |
| 841 * every element even though the source data MAY be unsorted. |
852 * every element even though the source data MAY be unsorted. |
| 842 */ |
853 */ |
| |
854 cx_attr_nonnull |
| 843 size_t (*insert_many)( |
855 size_t (*insert_many)( |
| 844 struct cx_tree_s *tree, |
856 struct cx_tree_s *tree, |
| 845 struct cx_iterator_base_s *iter, |
857 struct cx_iterator_base_s *iter, |
| 846 size_t n |
858 size_t n |
| 847 ); |
859 ); |
| 848 |
860 |
| 849 /** |
861 /** |
| 850 * Member function for finding a node. |
862 * Member function for finding a node. |
| 851 */ |
863 */ |
| |
864 cx_attr_nonnull |
| 852 void *(*find)( |
865 void *(*find)( |
| 853 struct cx_tree_s *tree, |
866 struct cx_tree_s *tree, |
| 854 const void *subtree, |
867 const void *subtree, |
| 855 const void *data, |
868 const void *data, |
| 856 size_t depth |
869 size_t depth |
| 859 |
872 |
| 860 /** |
873 /** |
| 861 * Common type for all tree implementations. |
874 * Common type for all tree implementations. |
| 862 */ |
875 */ |
| 863 typedef struct cx_tree_s CxTree; |
876 typedef struct cx_tree_s CxTree; |
| |
877 |
| |
878 |
| |
879 /** |
| |
880 * Destroys a node and it's subtree. |
| |
881 * |
| |
882 * It is guaranteed that the simple destructor is invoked before |
| |
883 * the advanced destructor, starting with the leaf nodes of the subtree. |
| |
884 * |
| |
885 * When this function is invoked on the root node of the tree, it destroys the |
| |
886 * tree contents, but - in contrast to #cxTreeDestroy() - not the tree |
| |
887 * structure, leaving an empty tree behind. |
| |
888 * |
| |
889 * \note The destructor function, if any, will \em not be invoked. That means |
| |
890 * you will need to free the removed subtree by yourself, eventually. |
| |
891 * |
| |
892 * \attention This function will not free the memory of the nodes with the |
| |
893 * tree's allocator, because that is usually done by the advanced destructor |
| |
894 * and would therefore result in a double-free. |
| |
895 * |
| |
896 * @param tree the tree |
| |
897 * @param node the node to remove |
| |
898 * @see cxTreeDestroy() |
| |
899 */ |
| |
900 cx_attr_nonnull |
| |
901 void cxTreeDestroySubtree(CxTree *tree, void *node); |
| |
902 |
| |
903 |
| |
904 /** |
| |
905 * Destroys the tree contents. |
| |
906 * |
| |
907 * It is guaranteed that the simple destructor is invoked before |
| |
908 * the advanced destructor, starting with the leaf nodes of the subtree. |
| |
909 * |
| |
910 * This is a convenience macro for invoking #cxTreeDestroySubtree() on the |
| |
911 * root node of the tree. |
| |
912 * |
| |
913 * \attention Be careful when calling this function when no destructor function |
| |
914 * is registered that actually frees the memory of nodes. In that case you will |
| |
915 * need a reference to the (former) root node of the tree somewhere or |
| |
916 * otherwise you will be leaking memory. |
| |
917 * |
| |
918 * @param tree the tree |
| |
919 * @see cxTreeDestroySubtree() |
| |
920 */ |
| |
921 #define cxTreeClear(tree) cxTreeDestroySubtree(tree, tree->root) |
| |
922 |
| |
923 /** |
| |
924 * Destroys the tree structure. |
| |
925 * |
| |
926 * The destructor functions are invoked for each node, starting with the leaf |
| |
927 * nodes. |
| |
928 * It is guaranteed that for each node the simple destructor is invoked before |
| |
929 * the advanced destructor. |
| |
930 * |
| |
931 * \attention This function will only invoke the destructor functions |
| |
932 * on the nodes. |
| |
933 * It will NOT additionally free the nodes with the tree's allocator, because |
| |
934 * that would cause a double-free in most scenarios where the advanced |
| |
935 * destructor is already freeing the memory. |
| |
936 * |
| |
937 * @param tree the tree to destroy |
| |
938 */ |
| |
939 static inline void cxTreeDestroy(CxTree *tree) { |
| |
940 if (tree == NULL) return; |
| |
941 if (tree->root != NULL) { |
| |
942 cxTreeClear(tree); |
| |
943 } |
| |
944 cxFree(tree->allocator, tree); |
| |
945 } |
| 864 |
946 |
| 865 /** |
947 /** |
| 866 * Creates a new tree structure based on the specified layout. |
948 * Creates a new tree structure based on the specified layout. |
| 867 * |
949 * |
| 868 * The specified \p allocator will be used for creating the tree struct |
950 * The specified \p allocator will be used for creating the tree struct |
| 883 * @param loc_next offset in the node struct for the next pointer |
965 * @param loc_next offset in the node struct for the next pointer |
| 884 * @return the new tree |
966 * @return the new tree |
| 885 * @see cxTreeCreateSimple() |
967 * @see cxTreeCreateSimple() |
| 886 * @see cxTreeCreateWrapped() |
968 * @see cxTreeCreateWrapped() |
| 887 */ |
969 */ |
| 888 __attribute__((__nonnull__, __warn_unused_result__)) |
970 cx_attr_nonnull |
| |
971 cx_attr_nodiscard |
| |
972 cx_attr_malloc |
| |
973 cx_attr_dealloc(cxTreeDestroy, 1) |
| 889 CxTree *cxTreeCreate( |
974 CxTree *cxTreeCreate( |
| 890 const CxAllocator *allocator, |
975 const CxAllocator *allocator, |
| 891 cx_tree_node_create_func create_func, |
976 cx_tree_node_create_func create_func, |
| 892 cx_tree_search_func search_func, |
977 cx_tree_search_func search_func, |
| 893 cx_tree_search_data_func search_data_func, |
978 cx_tree_search_data_func search_data_func, |
| 913 * @param search_func a function that compares two nodes |
998 * @param search_func a function that compares two nodes |
| 914 * @param search_data_func a function that compares a node with data |
999 * @param search_data_func a function that compares a node with data |
| 915 * @return the new tree |
1000 * @return the new tree |
| 916 * @see cxTreeCreate() |
1001 * @see cxTreeCreate() |
| 917 */ |
1002 */ |
| 918 __attribute__((__nonnull__, __warn_unused_result__)) |
1003 #define cxTreeCreateSimple(\ |
| 919 static inline CxTree *cxTreeCreateSimple( |
1004 allocator, create_func, search_func, search_data_func \ |
| 920 const CxAllocator *allocator, |
1005 ) cxTreeCreate(allocator, create_func, search_func, search_data_func, \ |
| 921 cx_tree_node_create_func create_func, |
1006 cx_tree_node_base_layout) |
| 922 cx_tree_search_func search_func, |
|
| 923 cx_tree_search_data_func search_data_func |
|
| 924 ) { |
|
| 925 return cxTreeCreate( |
|
| 926 allocator, |
|
| 927 create_func, |
|
| 928 search_func, |
|
| 929 search_data_func, |
|
| 930 cx_tree_node_base_layout |
|
| 931 ); |
|
| 932 } |
|
| 933 |
1007 |
| 934 /** |
1008 /** |
| 935 * Creates a new tree structure based on an existing tree. |
1009 * Creates a new tree structure based on an existing tree. |
| 936 * |
1010 * |
| 937 * The specified \p allocator will be used for creating the tree struct. |
1011 * The specified \p allocator will be used for creating the tree struct. |
| 950 * @param loc_prev optional offset in the node struct for the prev pointer |
1024 * @param loc_prev optional offset in the node struct for the prev pointer |
| 951 * @param loc_next offset in the node struct for the next pointer |
1025 * @param loc_next offset in the node struct for the next pointer |
| 952 * @return the new tree |
1026 * @return the new tree |
| 953 * @see cxTreeCreate() |
1027 * @see cxTreeCreate() |
| 954 */ |
1028 */ |
| 955 __attribute__((__nonnull__, __warn_unused_result__)) |
1029 cx_attr_nonnull |
| |
1030 cx_attr_nodiscard |
| |
1031 cx_attr_malloc |
| |
1032 cx_attr_dealloc(cxTreeDestroy, 1) |
| 956 CxTree *cxTreeCreateWrapped( |
1033 CxTree *cxTreeCreateWrapped( |
| 957 const CxAllocator *allocator, |
1034 const CxAllocator *allocator, |
| 958 void *root, |
1035 void *root, |
| 959 ptrdiff_t loc_parent, |
1036 ptrdiff_t loc_parent, |
| 960 ptrdiff_t loc_children, |
1037 ptrdiff_t loc_children, |
| 992 * @param tree the tree |
1069 * @param tree the tree |
| 993 * @param iter the iterator providing the elements |
1070 * @param iter the iterator providing the elements |
| 994 * @param n the maximum number of elements to insert |
1071 * @param n the maximum number of elements to insert |
| 995 * @return the number of elements that could be successfully inserted |
1072 * @return the number of elements that could be successfully inserted |
| 996 */ |
1073 */ |
| 997 __attribute__((__nonnull__)) |
1074 cx_attr_nonnull |
| 998 static inline size_t cxTreeInsertIter( |
1075 static inline size_t cxTreeInsertIter( |
| 999 CxTree *tree, |
1076 CxTree *tree, |
| 1000 struct cx_iterator_base_s *iter, |
1077 struct cx_iterator_base_s *iter, |
| 1001 size_t n |
1078 size_t n |
| 1002 ) { |
1079 ) { |
| 1038 * |
1115 * |
| 1039 * @param tree the tree |
1116 * @param tree the tree |
| 1040 * @param data the data to search for |
1117 * @param data the data to search for |
| 1041 * @return the first matching node, or \c NULL when the data cannot be found |
1118 * @return the first matching node, or \c NULL when the data cannot be found |
| 1042 */ |
1119 */ |
| 1043 __attribute__((__nonnull__)) |
1120 cx_attr_nonnull |
| |
1121 cx_attr_nodiscard |
| 1044 static inline void *cxTreeFind( |
1122 static inline void *cxTreeFind( |
| 1045 CxTree *tree, |
1123 CxTree *tree, |
| 1046 const void *data |
1124 const void *data |
| 1047 ) { |
1125 ) { |
| 1048 return tree->cl->find(tree, tree->root, data, 0); |
1126 return tree->cl->find(tree, tree->root, data, 0); |
| 1082 * |
1161 * |
| 1083 * @param tree the tree |
1162 * @param tree the tree |
| 1084 * @param subtree_root the root node of the subtree |
1163 * @param subtree_root the root node of the subtree |
| 1085 * @return the number of nodes in the specified subtree |
1164 * @return the number of nodes in the specified subtree |
| 1086 */ |
1165 */ |
| 1087 __attribute__((__nonnull__)) |
1166 cx_attr_nonnull |
| |
1167 cx_attr_nodiscard |
| 1088 size_t cxTreeSubtreeSize(CxTree *tree, void *subtree_root); |
1168 size_t cxTreeSubtreeSize(CxTree *tree, void *subtree_root); |
| 1089 |
1169 |
| 1090 /** |
1170 /** |
| 1091 * Determines the depth of the specified subtree. |
1171 * Determines the depth of the specified subtree. |
| 1092 * |
1172 * |
| 1093 * @param tree the tree |
1173 * @param tree the tree |
| 1094 * @param subtree_root the root node of the subtree |
1174 * @param subtree_root the root node of the subtree |
| 1095 * @return the tree depth including the \p subtree_root |
1175 * @return the tree depth including the \p subtree_root |
| 1096 */ |
1176 */ |
| 1097 __attribute__((__nonnull__)) |
1177 cx_attr_nonnull |
| |
1178 cx_attr_nodiscard |
| 1098 size_t cxTreeSubtreeDepth(CxTree *tree, void *subtree_root); |
1179 size_t cxTreeSubtreeDepth(CxTree *tree, void *subtree_root); |
| 1099 |
1180 |
| 1100 /** |
1181 /** |
| 1101 * Determines the depth of the entire tree. |
1182 * Determines the depth of the entire tree. |
| 1102 * |
1183 * |
| 1103 * @param tree the tree |
1184 * @param tree the tree |
| 1104 * @return the tree depth, counting the root as one |
1185 * @return the tree depth, counting the root as one |
| 1105 */ |
1186 */ |
| 1106 __attribute__((__nonnull__)) |
1187 cx_attr_nonnull |
| |
1188 cx_attr_nodiscard |
| 1107 size_t cxTreeDepth(CxTree *tree); |
1189 size_t cxTreeDepth(CxTree *tree); |
| 1108 |
1190 |
| 1109 /** |
1191 /** |
| 1110 * Creates a depth-first iterator for the specified tree starting in \p node. |
1192 * Creates a depth-first iterator for the specified tree starting in \p node. |
| 1111 * |
1193 * |
| 1138 * @param tree the tree to iterate |
1221 * @param tree the tree to iterate |
| 1139 * @param node the node where to start |
1222 * @param node the node where to start |
| 1140 * @return a tree visitor (a.k.a. breadth-first iterator) |
1223 * @return a tree visitor (a.k.a. breadth-first iterator) |
| 1141 * @see cxTreeIterate() |
1224 * @see cxTreeIterate() |
| 1142 */ |
1225 */ |
| 1143 __attribute__((__nonnull__, __warn_unused_result__)) |
1226 cx_attr_nonnull |
| |
1227 cx_attr_nodiscard |
| 1144 static inline CxTreeVisitor cxTreeVisitSubtree(CxTree *tree, void *node) { |
1228 static inline CxTreeVisitor cxTreeVisitSubtree(CxTree *tree, void *node) { |
| 1145 return cx_tree_visitor( |
1229 return cx_tree_visitor( |
| 1146 node, tree->loc_children, tree->loc_next |
1230 node, tree->loc_children, tree->loc_next |
| 1147 ); |
1231 ); |
| 1148 } |
1232 } |
| 1154 * @param visit_on_exit true, if the iterator shall visit a node again when |
1238 * @param visit_on_exit true, if the iterator shall visit a node again when |
| 1155 * leaving the subtree |
1239 * leaving the subtree |
| 1156 * @return a tree iterator (depth-first) |
1240 * @return a tree iterator (depth-first) |
| 1157 * @see cxTreeVisit() |
1241 * @see cxTreeVisit() |
| 1158 */ |
1242 */ |
| 1159 __attribute__((__nonnull__, __warn_unused_result__)) |
1243 cx_attr_nonnull |
| |
1244 cx_attr_nodiscard |
| 1160 static inline CxTreeIterator cxTreeIterate( |
1245 static inline CxTreeIterator cxTreeIterate( |
| 1161 CxTree *tree, |
1246 CxTree *tree, |
| 1162 bool visit_on_exit |
1247 bool visit_on_exit |
| 1163 ) { |
1248 ) { |
| 1164 return cxTreeIterateSubtree(tree, tree->root, visit_on_exit); |
1249 return cxTreeIterateSubtree(tree, tree->root, visit_on_exit); |
| 1270 * @param node the node to remove (must not be the root node) |
1357 * @param node the node to remove (must not be the root node) |
| 1271 * @param relink_func optional callback to update the content of each re-linked |
1358 * @param relink_func optional callback to update the content of each re-linked |
| 1272 * node |
1359 * node |
| 1273 * @return zero on success, non-zero if \p node is the root node of the tree |
1360 * @return zero on success, non-zero if \p node is the root node of the tree |
| 1274 */ |
1361 */ |
| 1275 __attribute__((__nonnull__(1,2))) |
1362 cx_attr_nonnull_arg(1, 2) |
| 1276 int cxTreeRemoveNode( |
1363 int cxTreeRemoveNode( |
| 1277 CxTree *tree, |
1364 CxTree *tree, |
| 1278 void *node, |
1365 void *node, |
| 1279 cx_tree_relink_func relink_func |
1366 cx_tree_relink_func relink_func |
| 1280 ); |
1367 ); |
| 1309 * @param node the node to destroy (must not be the root node) |
1396 * @param node the node to destroy (must not be the root node) |
| 1310 * @param relink_func optional callback to update the content of each re-linked |
1397 * @param relink_func optional callback to update the content of each re-linked |
| 1311 * node |
1398 * node |
| 1312 * @return zero on success, non-zero if \p node is the root node of the tree |
1399 * @return zero on success, non-zero if \p node is the root node of the tree |
| 1313 */ |
1400 */ |
| 1314 __attribute__((__nonnull__(1,2))) |
1401 cx_attr_nonnull_arg(1, 2) |
| 1315 int cxTreeDestroyNode( |
1402 int cxTreeDestroyNode( |
| 1316 CxTree *tree, |
1403 CxTree *tree, |
| 1317 void *node, |
1404 void *node, |
| 1318 cx_tree_relink_func relink_func |
1405 cx_tree_relink_func relink_func |
| 1319 ); |
1406 ); |
| 1320 |
1407 |
| 1321 /** |
|
| 1322 * Destroys a node and it's subtree. |
|
| 1323 * |
|
| 1324 * It is guaranteed that the simple destructor is invoked before |
|
| 1325 * the advanced destructor, starting with the leaf nodes of the subtree. |
|
| 1326 * |
|
| 1327 * When this function is invoked on the root node of the tree, it destroys the |
|
| 1328 * tree contents, but - in contrast to #cxTreeDestroy() - not the tree |
|
| 1329 * structure, leaving an empty tree behind. |
|
| 1330 * |
|
| 1331 * \note The destructor function, if any, will \em not be invoked. That means |
|
| 1332 * you will need to free the removed subtree by yourself, eventually. |
|
| 1333 * |
|
| 1334 * \attention This function will not free the memory of the nodes with the |
|
| 1335 * tree's allocator, because that is usually done by the advanced destructor |
|
| 1336 * and would therefore result in a double-free. |
|
| 1337 * |
|
| 1338 * @param tree the tree |
|
| 1339 * @param node the node to remove |
|
| 1340 * @see cxTreeDestroy() |
|
| 1341 */ |
|
| 1342 __attribute__((__nonnull__)) |
|
| 1343 void cxTreeDestroySubtree(CxTree *tree, void *node); |
|
| 1344 |
|
| 1345 |
|
| 1346 /** |
|
| 1347 * Destroys the tree contents. |
|
| 1348 * |
|
| 1349 * It is guaranteed that the simple destructor is invoked before |
|
| 1350 * the advanced destructor, starting with the leaf nodes of the subtree. |
|
| 1351 * |
|
| 1352 * This is a convenience macro for invoking #cxTreeDestroySubtree() on the |
|
| 1353 * root node of the tree. |
|
| 1354 * |
|
| 1355 * \attention Be careful when calling this function when no destructor function |
|
| 1356 * is registered that actually frees the memory of nodes. In that case you will |
|
| 1357 * need a reference to the (former) root node of the tree somewhere or |
|
| 1358 * otherwise you will be leaking memory. |
|
| 1359 * |
|
| 1360 * @param tree the tree |
|
| 1361 * @see cxTreeDestroySubtree() |
|
| 1362 */ |
|
| 1363 #define cxTreeClear(tree) cxTreeDestroySubtree(tree, tree->root) |
|
| 1364 |
|
| 1365 /** |
|
| 1366 * Destroys the tree structure. |
|
| 1367 * |
|
| 1368 * The destructor functions are invoked for each node, starting with the leaf |
|
| 1369 * nodes. |
|
| 1370 * It is guaranteed that for each node the simple destructor is invoked before |
|
| 1371 * the advanced destructor. |
|
| 1372 * |
|
| 1373 * \attention This function will only invoke the destructor functions |
|
| 1374 * on the nodes. |
|
| 1375 * It will NOT additionally free the nodes with the tree's allocator, because |
|
| 1376 * that would cause a double-free in most scenarios where the advanced |
|
| 1377 * destructor is already freeing the memory. |
|
| 1378 * |
|
| 1379 * @param tree the tree to destroy |
|
| 1380 */ |
|
| 1381 __attribute__((__nonnull__)) |
|
| 1382 static inline void cxTreeDestroy(CxTree *tree) { |
|
| 1383 if (tree->root != NULL) { |
|
| 1384 cxTreeDestroySubtree(tree, tree->root); |
|
| 1385 } |
|
| 1386 cxFree(tree->allocator, tree); |
|
| 1387 } |
|
| 1388 |
|
| 1389 #ifdef __cplusplus |
1408 #ifdef __cplusplus |
| 1390 } // extern "C" |
1409 } // extern "C" |
| 1391 #endif |
1410 #endif |
| 1392 |
1411 |
| 1393 #endif //UCX_TREE_H |
1412 #endif //UCX_TREE_H |