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 |