src/cx/tree.h

changeset 985
68754c7de906
parent 930
6540096c17b7
equal deleted inserted replaced
984:e8f354a25ac8 985:68754c7de906
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,
827 * Member function for inserting a single element. 837 * Member function for inserting a single element.
828 * 838 *
829 * Implementations SHALL NOT simply invoke \p insert_many as this comes 839 * Implementations SHALL NOT simply invoke \p insert_many as this comes
830 * with too much overhead. 840 * with too much overhead.
831 */ 841 */
842 cx_attr_nonnull
832 int (*insert_element)( 843 int (*insert_element)(
833 struct cx_tree_s *tree, 844 struct cx_tree_s *tree,
834 const void *data 845 const void *data
835 ); 846 );
836 847
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,
972 * 1049 *
973 * @param tree the tree 1050 * @param tree the tree
974 * @param data the data to insert 1051 * @param data the data to insert
975 * @return zero on success, non-zero on failure 1052 * @return zero on success, non-zero on failure
976 */ 1053 */
977 __attribute__((__nonnull__)) 1054 cx_attr_nonnull
978 static inline int cxTreeInsert( 1055 static inline int cxTreeInsert(
979 CxTree *tree, 1056 CxTree *tree,
980 const void *data 1057 const void *data
981 ) { 1058 ) {
982 return tree->cl->insert_element(tree, data); 1059 return tree->cl->insert_element(tree, data);
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 ) {
1014 * @param data the array of data to insert 1091 * @param data the array of data to insert
1015 * @param elem_size the size of each element in the array 1092 * @param elem_size the size of each element in the array
1016 * @param n the number of elements in the array 1093 * @param n the number of elements in the array
1017 * @return the number of elements that could be successfully inserted 1094 * @return the number of elements that could be successfully inserted
1018 */ 1095 */
1019 __attribute__((__nonnull__)) 1096 cx_attr_nonnull
1020 static inline size_t cxTreeInsertArray( 1097 static inline size_t cxTreeInsertArray(
1021 CxTree *tree, 1098 CxTree *tree,
1022 const void *data, 1099 const void *data,
1023 size_t elem_size, 1100 size_t elem_size,
1024 size_t n 1101 size_t n
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);
1065 * @param data the data to search for 1143 * @param data the data to search for
1066 * @param subtree_root the node where to start 1144 * @param subtree_root the node where to start
1067 * @param max_depth the maximum search depth 1145 * @param max_depth the maximum search depth
1068 * @return the first matching node, or \c NULL when the data cannot be found 1146 * @return the first matching node, or \c NULL when the data cannot be found
1069 */ 1147 */
1070 __attribute__((__nonnull__)) 1148 cx_attr_nonnull
1149 cx_attr_nodiscard
1071 static inline void *cxTreeFindInSubtree( 1150 static inline void *cxTreeFindInSubtree(
1072 CxTree *tree, 1151 CxTree *tree,
1073 const void *data, 1152 const void *data,
1074 void *subtree_root, 1153 void *subtree_root,
1075 size_t max_depth 1154 size_t max_depth
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 *
1116 * @param visit_on_exit true, if the iterator shall visit a node again when 1198 * @param visit_on_exit true, if the iterator shall visit a node again when
1117 * leaving the subtree 1199 * leaving the subtree
1118 * @return a tree iterator (depth-first) 1200 * @return a tree iterator (depth-first)
1119 * @see cxTreeVisit() 1201 * @see cxTreeVisit()
1120 */ 1202 */
1121 __attribute__((__nonnull__, __warn_unused_result__)) 1203 cx_attr_nonnull
1204 cx_attr_nodiscard
1122 static inline CxTreeIterator cxTreeIterateSubtree( 1205 static inline CxTreeIterator cxTreeIterateSubtree(
1123 CxTree *tree, 1206 CxTree *tree,
1124 void *node, 1207 void *node,
1125 bool visit_on_exit 1208 bool visit_on_exit
1126 ) { 1209 ) {
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);
1169 * 1254 *
1170 * @param tree the tree to iterate 1255 * @param tree the tree to iterate
1171 * @return a tree visitor (a.k.a. breadth-first iterator) 1256 * @return a tree visitor (a.k.a. breadth-first iterator)
1172 * @see cxTreeIterate() 1257 * @see cxTreeIterate()
1173 */ 1258 */
1174 __attribute__((__nonnull__, __warn_unused_result__)) 1259 cx_attr_nonnull
1260 cx_attr_nodiscard
1175 static inline CxTreeVisitor cxTreeVisit(CxTree *tree) { 1261 static inline CxTreeVisitor cxTreeVisit(CxTree *tree) {
1176 return cxTreeVisitSubtree(tree, tree->root); 1262 return cxTreeVisitSubtree(tree, tree->root);
1177 } 1263 }
1178 1264
1179 /** 1265 /**
1185 * @param tree the tree 1271 * @param tree the tree
1186 * @param parent the (new) parent of the child 1272 * @param parent the (new) parent of the child
1187 * @param child the node to add 1273 * @param child the node to add
1188 * @see cxTreeAddChildNode() 1274 * @see cxTreeAddChildNode()
1189 */ 1275 */
1190 __attribute__((__nonnull__)) 1276 cx_attr_nonnull
1191 void cxTreeSetParent( 1277 void cxTreeSetParent(
1192 CxTree *tree, 1278 CxTree *tree,
1193 void *parent, 1279 void *parent,
1194 void *child 1280 void *child
1195 ); 1281 );
1207 * @param tree the tree 1293 * @param tree the tree
1208 * @param parent the parent of the node to add 1294 * @param parent the parent of the node to add
1209 * @param child the node to add 1295 * @param child the node to add
1210 * @see cxTreeSetParent() 1296 * @see cxTreeSetParent()
1211 */ 1297 */
1212 __attribute__((__nonnull__)) 1298 cx_attr_nonnull
1213 void cxTreeAddChildNode( 1299 void cxTreeAddChildNode(
1214 CxTree *tree, 1300 CxTree *tree,
1215 void *parent, 1301 void *parent,
1216 void *child 1302 void *child
1217 ); 1303 );
1231 * @param parent the parent node of the new node 1317 * @param parent the parent node of the new node
1232 * @param data the data that will be submitted to the create function 1318 * @param data the data that will be submitted to the create function
1233 * @return zero when the new node was created, non-zero on allocation failure 1319 * @return zero when the new node was created, non-zero on allocation failure
1234 * @see cxTreeInsert() 1320 * @see cxTreeInsert()
1235 */ 1321 */
1236 __attribute__((__nonnull__)) 1322 cx_attr_nonnull
1237 int cxTreeAddChild( 1323 int cxTreeAddChild(
1238 CxTree *tree, 1324 CxTree *tree,
1239 void *parent, 1325 void *parent,
1240 const void *data 1326 const void *data
1241 ); 1327 );
1250 * 1336 *
1251 * @param node the affected node 1337 * @param node the affected node
1252 * @param old_parent the old parent of the node 1338 * @param old_parent the old parent of the node
1253 * @param new_parent the new parent of the node 1339 * @param new_parent the new parent of the node
1254 */ 1340 */
1341 cx_attr_nonnull
1255 typedef void (*cx_tree_relink_func)( 1342 typedef void (*cx_tree_relink_func)(
1256 void *node, 1343 void *node,
1257 const void *old_parent, 1344 const void *old_parent,
1258 const void *new_parent 1345 const void *new_parent
1259 ); 1346 );
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 );
1288 * you will need to free the removed subtree by yourself, eventually. 1375 * you will need to free the removed subtree by yourself, eventually.
1289 * 1376 *
1290 * @param tree the tree 1377 * @param tree the tree
1291 * @param node the node to remove 1378 * @param node the node to remove
1292 */ 1379 */
1293 __attribute__((__nonnull__)) 1380 cx_attr_nonnull
1294 void cxTreeRemoveSubtree(CxTree *tree, void *node); 1381 void cxTreeRemoveSubtree(CxTree *tree, void *node);
1295 1382
1296 /** 1383 /**
1297 * Destroys a node and re-links its children to its former parent. 1384 * Destroys a node and re-links its children to its former parent.
1298 * 1385 *
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

mercurial