ucx/tree.c

branch
dav-2
changeset 891
4d58cbcc9efa
parent 889
42cdbf9bbd49
equal deleted inserted replaced
890:e77ccf1c4bb3 891:4d58cbcc9efa
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29 #include "cx/tree.h" 29 #include "cx/tree.h"
30
31 #include "cx/array_list.h"
32 30
33 #include <assert.h> 31 #include <assert.h>
34 32
35 #define CX_TREE_PTR(cur, off) (*(void**)(((char*)(cur))+(off))) 33 #define CX_TREE_PTR(cur, off) (*(void**)(((char*)(cur))+(off)))
36 #define tree_parent(node) CX_TREE_PTR(node, loc_parent) 34 #define tree_parent(node) CX_TREE_PTR(node, loc_parent)
350 iter->stack[iter->depth - 1] = next; 348 iter->stack[iter->depth - 1] = next;
351 } 349 }
352 } 350 }
353 } else { 351 } else {
354 // node has children, push the first child onto the stack and enter it 352 // node has children, push the first child onto the stack and enter it
355 cx_array_simple_add(iter->stack, children); 353 if (iter->stack_size >= iter->stack_capacity) {
354 const size_t newcap = iter->stack_capacity + 8;
355 if (cxReallocArrayDefault(&iter->stack, newcap, sizeof(void*))) {
356 // we cannot return an error in this function
357 abort(); // LCOV_EXCL_LINE
358 }
359 iter->stack_capacity = newcap;
360 }
361 iter->stack[iter->stack_size] = children;
362 iter->stack_size++;
356 iter->node = children; 363 iter->node = children;
357 iter->counter++; 364 iter->counter++;
358 } 365 }
359 } 366 }
360 367
564 ptrdiff_t loc_last_child, 571 ptrdiff_t loc_last_child,
565 ptrdiff_t loc_prev, 572 ptrdiff_t loc_prev,
566 ptrdiff_t loc_next 573 ptrdiff_t loc_next
567 ) { 574 ) {
568 *cnode = cfunc(src, cdata); 575 *cnode = cfunc(src, cdata);
569 if (*cnode == NULL) return 1; 576 if (*cnode == NULL) return 1; // LCOV_EXCL_LINE
570 cx_tree_zero_pointers(*cnode, cx_tree_ptr_locations); 577 cx_tree_zero_pointers(*cnode, cx_tree_ptr_locations);
571 578
572 void *match = NULL; 579 void *match = NULL;
573 int result = cx_tree_search( 580 int result = cx_tree_search(
574 root, 581 root,
625 iter->next(iter)) { 632 iter->next(iter)) {
626 elem = *eptr; 633 elem = *eptr;
627 634
628 // create the new node 635 // create the new node
629 void *new_node = cfunc(elem, cdata); 636 void *new_node = cfunc(elem, cdata);
630 if (new_node == NULL) return processed; 637 if (new_node == NULL) return processed; // LCOV_EXCL_LINE
631 cx_tree_zero_pointers(new_node, cx_tree_ptr_locations); 638 cx_tree_zero_pointers(new_node, cx_tree_ptr_locations);
632 639
633 // start searching from current node 640 // start searching from current node
634 void *match; 641 void *match;
635 int result; 642 int result;
715 return 0; 722 return 0;
716 } 723 }
717 } 724 }
718 725
719 // otherwise, create iterator and hand over to other function 726 // otherwise, create iterator and hand over to other function
720 CxIterator iter = cxIterator(src, elem_size, num, false); 727 CxIterator iter = cxIterator(src, elem_size, num);
721 return cx_tree_add_iter(cxIteratorRef(iter), num, sfunc, 728 return cx_tree_add_iter(cxIteratorRef(iter), num, sfunc,
722 cfunc, cdata, failed, root, 729 cfunc, cdata, failed, root,
723 loc_parent, loc_children, loc_last_child, 730 loc_parent, loc_children, loc_last_child,
724 loc_prev, loc_next); 731 loc_prev, loc_next);
725 } 732 }
729 const void *data 736 const void *data
730 ) { 737 ) {
731 void *node; 738 void *node;
732 if (tree->root == NULL) { 739 if (tree->root == NULL) {
733 node = tree->node_create(data, tree); 740 node = tree->node_create(data, tree);
734 if (node == NULL) return 1; 741 if (node == NULL) return 1; // LCOV_EXCL_LINE
735 cx_tree_zero_pointers(node, cx_tree_node_layout(tree)); 742 cx_tree_zero_pointers(node, cx_tree_node_layout(tree));
736 tree->root = node; 743 tree->root = node;
737 tree->size = 1; 744 tree->collection.size = 1;
738 return 0; 745 return 0;
739 } 746 }
740 int result = cx_tree_add(data, tree->search, tree->node_create, 747 int result = cx_tree_add(data, tree->search, tree->node_create,
741 tree, &node, tree->root, cx_tree_node_layout(tree)); 748 tree, &node, tree->root, cx_tree_node_layout(tree));
742 if (0 == result) { 749 if (0 == result) {
743 tree->size++; 750 tree->collection.size++;
744 } else { 751 } else {
745 cxFree(tree->allocator, node); 752 cxFree(tree->collection.allocator, node);
746 } 753 }
747 return result; 754 return result;
748 } 755 }
749 756
750 static size_t cx_tree_default_insert_many( 757 static size_t cx_tree_default_insert_many(
756 if (!iter->valid(iter)) return 0; 763 if (!iter->valid(iter)) return 0;
757 if (tree->root == NULL) { 764 if (tree->root == NULL) {
758 // use the first element from the iter to create the root node 765 // use the first element from the iter to create the root node
759 void **eptr = iter->current(iter); 766 void **eptr = iter->current(iter);
760 void *node = tree->node_create(*eptr, tree); 767 void *node = tree->node_create(*eptr, tree);
761 if (node == NULL) return 0; 768 if (node == NULL) return 0; // LCOV_EXCL_LINE
762 cx_tree_zero_pointers(node, cx_tree_node_layout(tree)); 769 cx_tree_zero_pointers(node, cx_tree_node_layout(tree));
763 tree->root = node; 770 tree->root = node;
764 ins = 1; 771 ins = 1;
765 iter->next(iter); 772 iter->next(iter);
766 } 773 }
767 void *failed; 774 void *failed;
768 ins += cx_tree_add_iter(iter, n, tree->search, tree->node_create, 775 ins += cx_tree_add_iter(iter, n, tree->search, tree->node_create,
769 tree, &failed, tree->root, cx_tree_node_layout(tree)); 776 tree, &failed, tree->root, cx_tree_node_layout(tree));
770 tree->size += ins; 777 tree->collection.size += ins;
771 if (ins < n) { 778 if (ins < n) {
772 cxFree(tree->allocator, failed); 779 cxFree(tree->collection.allocator, failed);
773 } 780 }
774 return ins; 781 return ins;
775 } 782 }
776 783
777 static void *cx_tree_default_find( 784 static void *cx_tree_default_find(
778 CxTree *tree, 785 CxTree *tree,
779 const void *subtree, 786 const void *subtree,
780 const void *data, 787 const void *data,
781 size_t depth 788 size_t depth
782 ) { 789 ) {
783 if (tree->root == NULL) return NULL; 790 if (tree->root == NULL) return NULL; // LCOV_EXCL_LINE
784 791
785 void *found; 792 void *found;
786 if (0 == cx_tree_search_data( 793 if (0 == cx_tree_search_data(
787 subtree, 794 subtree,
788 depth, 795 depth,
816 } 823 }
817 assert(create_func != NULL); 824 assert(create_func != NULL);
818 assert(search_func != NULL); 825 assert(search_func != NULL);
819 assert(search_data_func != NULL); 826 assert(search_data_func != NULL);
820 827
821 CxTree *tree = cxMalloc(allocator, sizeof(CxTree)); 828 CxTree *tree = cxZalloc(allocator, sizeof(CxTree));
822 if (tree == NULL) return NULL; 829 if (tree == NULL) return NULL; // LCOV_EXCL_LINE
823 830
824 tree->cl = &cx_tree_default_class; 831 tree->cl = &cx_tree_default_class;
825 tree->allocator = allocator; 832 tree->collection.allocator = allocator;
826 tree->node_create = create_func; 833 tree->node_create = create_func;
827 tree->search = search_func; 834 tree->search = search_func;
828 tree->search_data = search_data_func; 835 tree->search_data = search_data_func;
829 tree->simple_destructor = NULL; 836 tree->collection.advanced_destructor = (cx_destructor_func2) cxFree;
830 tree->advanced_destructor = (cx_destructor_func2) cxFree; 837 tree->collection.destructor_data = (void *) allocator;
831 tree->destructor_data = (void *) allocator;
832 tree->loc_parent = loc_parent; 838 tree->loc_parent = loc_parent;
833 tree->loc_children = loc_children; 839 tree->loc_children = loc_children;
834 tree->loc_last_child = loc_last_child; 840 tree->loc_last_child = loc_last_child;
835 tree->loc_prev = loc_prev; 841 tree->loc_prev = loc_prev;
836 tree->loc_next = loc_next; 842 tree->loc_next = loc_next;
837 tree->root = NULL;
838 tree->size = 0;
839 843
840 return tree; 844 return tree;
841 } 845 }
842 846
843 void cxTreeFree(CxTree *tree) { 847 void cxTreeFree(CxTree *tree) {
844 if (tree == NULL) return; 848 if (tree == NULL) return;
845 if (tree->root != NULL) { 849 if (tree->root != NULL) {
846 cxTreeClear(tree); 850 cxTreeClear(tree);
847 } 851 }
848 cxFree(tree->allocator, tree); 852 cxFree(tree->collection.allocator, tree);
849 } 853 }
850 854
851 CxTree *cxTreeCreateWrapped(const CxAllocator *allocator, void *root, 855 CxTree *cxTreeCreateWrapped(const CxAllocator *allocator, void *root,
852 ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child, 856 ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
853 ptrdiff_t loc_prev, ptrdiff_t loc_next) { 857 ptrdiff_t loc_prev, ptrdiff_t loc_next) {
854 if (allocator == NULL) { 858 if (allocator == NULL) {
855 allocator = cxDefaultAllocator; 859 allocator = cxDefaultAllocator;
856 } 860 }
857 assert(root != NULL); 861 assert(root != NULL);
858 862
859 CxTree *tree = cxMalloc(allocator, sizeof(CxTree)); 863 CxTree *tree = cxZalloc(allocator, sizeof(CxTree));
860 if (tree == NULL) return NULL; 864 if (tree == NULL) return NULL; // LCOV_EXCL_LINE
861 865
862 tree->cl = &cx_tree_default_class; 866 tree->cl = &cx_tree_default_class;
863 // set the allocator anyway, just in case... 867 // set the allocator anyway, just in case...
864 tree->allocator = allocator; 868 tree->collection.allocator = allocator;
865 tree->node_create = NULL;
866 tree->search = NULL;
867 tree->search_data = NULL;
868 tree->simple_destructor = NULL;
869 tree->advanced_destructor = NULL;
870 tree->destructor_data = NULL;
871 tree->loc_parent = loc_parent; 869 tree->loc_parent = loc_parent;
872 tree->loc_children = loc_children; 870 tree->loc_children = loc_children;
873 tree->loc_last_child = loc_last_child; 871 tree->loc_last_child = loc_last_child;
874 tree->loc_prev = loc_prev; 872 tree->loc_prev = loc_prev;
875 tree->loc_next = loc_next; 873 tree->loc_next = loc_next;
876 tree->root = root; 874 tree->root = root;
877 tree->size = cxTreeSubtreeSize(tree, root); 875 tree->collection.size = cxTreeSubtreeSize(tree, root);
878 return tree; 876 return tree;
879 } 877 }
880 878
881 void cxTreeSetParent(CxTree *tree, void *parent, void *child) { 879 void cxTreeSetParent(CxTree *tree, void *parent, void *child) {
882 size_t loc_parent = tree->loc_parent; 880 size_t loc_parent = tree->loc_parent;
883 if (tree_parent(child) == NULL) { 881 if (tree_parent(child) == NULL) {
884 tree->size++; 882 tree->collection.size++;
885 } 883 }
886 cx_tree_link(parent, child, cx_tree_node_layout(tree)); 884 cx_tree_link(parent, child, cx_tree_node_layout(tree));
887 } 885 }
888 886
889 void cxTreeAddChildNode(CxTree *tree, void *parent, void *child) { 887 void cxTreeAddChildNode(CxTree *tree, void *parent, void *child) {
890 cx_tree_link(parent, child, cx_tree_node_layout(tree)); 888 cx_tree_link(parent, child, cx_tree_node_layout(tree));
891 tree->size++; 889 tree->collection.size++;
892 } 890 }
893 891
894 int cxTreeAddChild(CxTree *tree, void *parent, const void *data) { 892 int cxTreeAddChild(CxTree *tree, void *parent, const void *data) {
895 void *node = tree->node_create(data, tree); 893 void *node = tree->node_create(data, tree);
896 if (node == NULL) return 1; 894 if (node == NULL) return 1; // LCOV_EXCL_LINE
897 cx_tree_zero_pointers(node, cx_tree_node_layout(tree)); 895 cx_tree_zero_pointers(node, cx_tree_node_layout(tree));
898 cx_tree_link(parent, node, cx_tree_node_layout(tree)); 896 cx_tree_link(parent, node, cx_tree_node_layout(tree));
899 tree->size++; 897 tree->collection.size++;
900 return 0; 898 return 0;
901 } 899 }
902 900
903 int cxTreeInsert(CxTree *tree, const void *data) { 901 int cxTreeInsert(CxTree *tree, const void *data) {
904 return tree->cl->insert_element(tree, data); 902 return tree->cl->insert_element(tree, data);
909 } 907 }
910 908
911 size_t cxTreeInsertArray(CxTree *tree, const void *data, size_t elem_size, size_t n) { 909 size_t cxTreeInsertArray(CxTree *tree, const void *data, size_t elem_size, size_t n) {
912 if (n == 0) return 0; 910 if (n == 0) return 0;
913 if (n == 1) return 0 == cxTreeInsert(tree, data) ? 1 : 0; 911 if (n == 1) return 0 == cxTreeInsert(tree, data) ? 1 : 0;
914 CxIterator iter = cxIterator(data, elem_size, n, false); 912 CxIterator iter = cxIterator(data, elem_size, n);
915 return cxTreeInsertIter(tree, cxIteratorRef(iter), n); 913 return cxTreeInsertIter(tree, cxIteratorRef(iter), n);
916 } 914 }
917 915
918 void *cxTreeFind( CxTree *tree, const void *data) { 916 void *cxTreeFind( CxTree *tree, const void *data) {
919 return tree->cl->find(tree, tree->root, data, 0); 917 return tree->cl->find(tree, tree->root, data, 0);
946 } 944 }
947 return visitor.depth; 945 return visitor.depth;
948 } 946 }
949 947
950 size_t cxTreeSize(CxTree *tree) { 948 size_t cxTreeSize(CxTree *tree) {
951 return tree->size; 949 return tree->collection.size;
952 } 950 }
953 951
954 size_t cxTreeDepth(CxTree *tree) { 952 size_t cxTreeDepth(CxTree *tree) {
955 CxTreeVisitor visitor = cx_tree_visitor( 953 CxTreeVisitor visitor = cx_tree_visitor(
956 tree->root, tree->loc_children, tree->loc_next 954 tree->root, tree->loc_children, tree->loc_next
1000 tree_children(node) = NULL; 998 tree_children(node) = NULL;
1001 ptrdiff_t loc_last_child = tree->loc_last_child; 999 ptrdiff_t loc_last_child = tree->loc_last_child;
1002 if (loc_last_child >= 0) tree_last_child(node) = NULL; 1000 if (loc_last_child >= 0) tree_last_child(node) = NULL;
1003 1001
1004 // the tree now has one member less 1002 // the tree now has one member less
1005 tree->size--; 1003 tree->collection.size--;
1006 1004
1007 return 0; 1005 return 0;
1008 } 1006 }
1009 1007
1010 void cxTreeRemoveSubtree(CxTree *tree, void *node) { 1008 void cxTreeRemoveSubtree(CxTree *tree, void *node) {
1011 if (node == tree->root) { 1009 if (node == tree->root) {
1012 tree->root = NULL; 1010 tree->root = NULL;
1013 tree->size = 0; 1011 tree->collection.size = 0;
1014 return; 1012 return;
1015 } 1013 }
1016 size_t subtree_size = cxTreeSubtreeSize(tree, node); 1014 size_t subtree_size = cxTreeSubtreeSize(tree, node);
1017 cx_tree_unlink(node, cx_tree_node_layout(tree)); 1015 cx_tree_unlink(node, cx_tree_node_layout(tree));
1018 tree->size -= subtree_size; 1016 tree->collection.size -= subtree_size;
1019 } 1017 }
1020 1018
1021 int cxTreeDestroyNode( 1019 int cxTreeDestroyNode(
1022 CxTree *tree, 1020 CxTree *tree,
1023 void *node, 1021 void *node,
1024 cx_tree_relink_func relink_func 1022 cx_tree_relink_func relink_func
1025 ) { 1023 ) {
1026 int result = cxTreeRemoveNode(tree, node, relink_func); 1024 int result = cxTreeRemoveNode(tree, node, relink_func);
1027 if (result == 0) { 1025 if (result == 0) {
1028 if (tree->simple_destructor) { 1026 cx_invoke_destructor(tree, node);
1029 tree->simple_destructor(node);
1030 }
1031 if (tree->advanced_destructor) {
1032 tree->advanced_destructor(tree->destructor_data, node);
1033 }
1034 return 0; 1027 return 0;
1035 } else { 1028 } else {
1036 return result; 1029 return result;
1037 } 1030 }
1038 } 1031 }
1043 node, true, 1036 node, true,
1044 tree->loc_children, tree->loc_next 1037 tree->loc_children, tree->loc_next
1045 ); 1038 );
1046 cx_foreach(void *, child, iter) { 1039 cx_foreach(void *, child, iter) {
1047 if (iter.exiting) { 1040 if (iter.exiting) {
1048 if (tree->simple_destructor) { 1041 cx_invoke_destructor(tree, child);
1049 tree->simple_destructor(child); 1042 }
1050 } 1043 }
1051 if (tree->advanced_destructor) { 1044 tree->collection.size -= iter.counter;
1052 tree->advanced_destructor(tree->destructor_data, child);
1053 }
1054 }
1055 }
1056 tree->size -= iter.counter;
1057 if (node == tree->root) { 1045 if (node == tree->root) {
1058 tree->root = NULL; 1046 tree->root = NULL;
1059 } 1047 }
1060 } 1048 }
1061 1049
1069 while (q != NULL) { 1057 while (q != NULL) {
1070 struct cx_tree_visitor_queue_s *next = q->next; 1058 struct cx_tree_visitor_queue_s *next = q->next;
1071 cxFreeDefault(q); 1059 cxFreeDefault(q);
1072 q = next; 1060 q = next;
1073 } 1061 }
1062 visitor->queue_next = visitor->queue_last = NULL;
1074 } 1063 }
1075 1064
1076 CxTreeIterator cxTreeIterateSubtree(CxTree *tree, void *node, bool visit_on_exit) { 1065 CxTreeIterator cxTreeIterateSubtree(CxTree *tree, void *node, bool visit_on_exit) {
1077 return cx_tree_iterator( 1066 return cx_tree_iterator(
1078 node, visit_on_exit, 1067 node, visit_on_exit,

mercurial