| 63 i < index ? i++ : i--; |
63 i < index ? i++ : i--; |
| 64 } |
64 } |
| 65 return (void *) cur; |
65 return (void *) cur; |
| 66 } |
66 } |
| 67 |
67 |
| |
68 void *cx_linked_list_find_c( |
| |
69 const void *start, |
| |
70 ptrdiff_t loc_advance, |
| |
71 ptrdiff_t loc_data, |
| |
72 const void *elem, |
| |
73 size_t *found_index, |
| |
74 cx_compare_func2 cmp_func, |
| |
75 void *context |
| |
76 ) { |
| |
77 assert(start != NULL); |
| |
78 assert(loc_advance >= 0); |
| |
79 assert(loc_data >= 0); |
| |
80 assert(cmp_func); |
| |
81 |
| |
82 void *node = (void*) start; |
| |
83 size_t index = 0; |
| |
84 do { |
| |
85 void *current = ll_data(node); |
| |
86 if (cmp_func(current, elem, context) == 0) { |
| |
87 if (found_index != NULL) { |
| |
88 *found_index = index; |
| |
89 } |
| |
90 return node; |
| |
91 } |
| |
92 node = ll_advance(node); |
| |
93 index++; |
| |
94 } while (node != NULL); |
| |
95 return NULL; |
| |
96 } |
| |
97 |
| 68 void *cx_linked_list_find( |
98 void *cx_linked_list_find( |
| 69 const void *start, |
99 const void *start, |
| 70 ptrdiff_t loc_advance, |
100 ptrdiff_t loc_advance, |
| 71 ptrdiff_t loc_data, |
101 ptrdiff_t loc_data, |
| 72 cx_compare_func cmp_func, |
|
| 73 const void *elem, |
102 const void *elem, |
| 74 size_t *found_index |
103 size_t *found_index, |
| 75 ) { |
104 cx_compare_func cmp_func |
| 76 assert(start != NULL); |
105 ) { |
| 77 assert(loc_advance >= 0); |
106 cx_compare_func_wrapper wrapper = {cmp_func}; |
| 78 assert(loc_data >= 0); |
107 return cx_linked_list_find_c(start, loc_advance, loc_data, |
| 79 assert(cmp_func); |
108 elem, found_index, cx_acmp_wrap, &wrapper); |
| 80 |
|
| 81 void *node = (void*) start; |
|
| 82 size_t index = 0; |
|
| 83 do { |
|
| 84 void *current = ll_data(node); |
|
| 85 if (cmp_func(current, elem) == 0) { |
|
| 86 if (found_index != NULL) { |
|
| 87 *found_index = index; |
|
| 88 } |
|
| 89 return node; |
|
| 90 } |
|
| 91 node = ll_advance(node); |
|
| 92 index++; |
|
| 93 } while (node != NULL); |
|
| 94 return NULL; |
|
| 95 } |
109 } |
| 96 |
110 |
| 97 void *cx_linked_list_first( |
111 void *cx_linked_list_first( |
| 98 const void *node, |
112 const void *node, |
| 99 ptrdiff_t loc_prev |
113 ptrdiff_t loc_prev |
| 354 cx_linked_list_link(new_end, source_argument, loc_prev, loc_next); |
369 cx_linked_list_link(new_end, source_argument, loc_prev, loc_next); |
| 355 new_end = cx_linked_list_last(source_argument, loc_next); |
370 new_end = cx_linked_list_last(source_argument, loc_next); |
| 356 } else { |
371 } else { |
| 357 // otherwise we must check one-by-one |
372 // otherwise we must check one-by-one |
| 358 while (source_argument != NULL) { |
373 while (source_argument != NULL) { |
| 359 if (cmp_func(new_end, source_argument) == 0) { |
374 if (cmp_func(new_end, source_argument, context) == 0) { |
| 360 if (dup_end == NULL) { |
375 if (dup_end == NULL) { |
| 361 dup_begin = dup_end = source_argument; |
376 dup_begin = dup_end = source_argument; |
| 362 } else { |
377 } else { |
| 363 cx_linked_list_link(dup_end, source_argument, loc_prev, loc_next); |
378 cx_linked_list_link(dup_end, source_argument, loc_prev, loc_next); |
| 364 dup_end = source_argument; |
379 dup_end = source_argument; |
| 600 if (le != NULL) { |
619 if (le != NULL) { |
| 601 void *rc; |
620 void *rc; |
| 602 size_t rn = 1; |
621 size_t rn = 1; |
| 603 rc = le; |
622 rc = le; |
| 604 // skip already sorted elements |
623 // skip already sorted elements |
| 605 while (ll_next(rc) != NULL && cmp_func(ll_data(ll_next(rc)), ll_data(rc)) > 0) { |
624 while (ll_next(rc) != NULL && cmp_func(ll_data(ll_next(rc)), ll_data(rc), context) > 0) { |
| 606 rc = ll_next(rc); |
625 rc = ll_next(rc); |
| 607 rn++; |
626 rn++; |
| 608 } |
627 } |
| 609 re = ll_next(rc); |
628 re = ll_next(rc); |
| 610 |
629 |
| 611 // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them |
630 // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them |
| 612 void *sorted_begin, *sorted_end; |
631 void *sorted_begin, *sorted_end; |
| 613 cx_linked_list_sort_merge(loc_prev, loc_next, loc_data, |
632 cx_linked_list_sort_merge(&sorted_begin, &sorted_end, |
| |
633 loc_prev, loc_next, loc_data, |
| 614 ln + rn, ls, le, re, cmp_func, |
634 ln + rn, ls, le, re, cmp_func, |
| 615 &sorted_begin, &sorted_end); |
635 context); |
| 616 |
636 |
| 617 // Something left? Sort it! |
637 // Something left? Sort it! |
| 618 size_t remainder_length = cx_linked_list_size(re, loc_next); |
638 size_t remainder_length = cx_linked_list_size(re, loc_next); |
| 619 if (remainder_length > 0) { |
639 if (remainder_length > 0) { |
| 620 void *remainder = re; |
640 void *remainder = re; |
| 621 cx_linked_list_sort(&remainder, NULL, loc_prev, loc_next, loc_data, cmp_func); |
641 cx_linked_list_sort_c(&remainder, NULL, loc_prev, loc_next, loc_data, cmp_func, context); |
| 622 |
642 |
| 623 // merge sorted list with (also sorted) remainder |
643 // merge sorted list with (also sorted) remainder |
| 624 cx_linked_list_sort_merge(loc_prev, loc_next, loc_data, |
644 cx_linked_list_sort_merge(&sorted_begin, &sorted_end, |
| |
645 loc_prev, loc_next, loc_data, |
| 625 ln + rn + remainder_length, |
646 ln + rn + remainder_length, |
| 626 sorted_begin, remainder, NULL, cmp_func, |
647 sorted_begin, remainder, NULL, cmp_func, |
| 627 &sorted_begin, &sorted_end); |
648 context); |
| 628 } |
649 } |
| 629 *begin = sorted_begin; |
650 *begin = sorted_begin; |
| 630 if (end) *end = sorted_end; |
651 if (end) *end = sorted_end; |
| 631 } |
652 } |
| |
653 } |
| |
654 |
| |
655 void cx_linked_list_sort( |
| |
656 void **begin, |
| |
657 void **end, |
| |
658 ptrdiff_t loc_prev, |
| |
659 ptrdiff_t loc_next, |
| |
660 ptrdiff_t loc_data, |
| |
661 cx_compare_func cmp_func |
| |
662 ) { |
| |
663 cx_compare_func_wrapper wrapper = {cmp_func}; |
| |
664 cx_linked_list_sort_c(begin, end, loc_prev, loc_next, loc_data, cx_acmp_wrap, &wrapper); |
| |
665 } |
| |
666 |
| |
667 int cx_linked_list_compare_c( |
| |
668 const void *begin_left, |
| |
669 const void *begin_right, |
| |
670 ptrdiff_t loc_advance, |
| |
671 ptrdiff_t loc_data, |
| |
672 cx_compare_func2 cmp_func, |
| |
673 void *context |
| |
674 ) { |
| |
675 const void *left = begin_left, *right = begin_right; |
| |
676 |
| |
677 while (left != NULL && right != NULL) { |
| |
678 const void *left_data = ll_data(left); |
| |
679 const void *right_data = ll_data(right); |
| |
680 int result = cmp_func(left_data, right_data, context); |
| |
681 if (result != 0) return result; |
| |
682 left = ll_advance(left); |
| |
683 right = ll_advance(right); |
| |
684 } |
| |
685 |
| |
686 if (left != NULL) { return 1; } |
| |
687 else if (right != NULL) { return -1; } |
| |
688 else { return 0; } |
| 632 } |
689 } |
| 633 |
690 |
| 634 int cx_linked_list_compare( |
691 int cx_linked_list_compare( |
| 635 const void *begin_left, |
692 const void *begin_left, |
| 636 const void *begin_right, |
693 const void *begin_right, |
| 637 ptrdiff_t loc_advance, |
694 ptrdiff_t loc_advance, |
| 638 ptrdiff_t loc_data, |
695 ptrdiff_t loc_data, |
| 639 cx_compare_func cmp_func |
696 cx_compare_func cmp_func |
| 640 ) { |
697 ) { |
| 641 const void *left = begin_left, *right = begin_right; |
698 cx_compare_func_wrapper wrapper = {cmp_func}; |
| 642 |
699 return cx_linked_list_compare_c(begin_left, begin_right, |
| 643 while (left != NULL && right != NULL) { |
700 loc_advance, loc_data, cx_acmp_wrap, &wrapper); |
| 644 const void *left_data = ll_data(left); |
|
| 645 const void *right_data = ll_data(right); |
|
| 646 int result = cmp_func(left_data, right_data); |
|
| 647 if (result != 0) return result; |
|
| 648 left = ll_advance(left); |
|
| 649 right = ll_advance(right); |
|
| 650 } |
|
| 651 |
|
| 652 if (left != NULL) { return 1; } |
|
| 653 else if (right != NULL) { return -1; } |
|
| 654 else { return 0; } |
|
| 655 } |
701 } |
| 656 |
702 |
| 657 void cx_linked_list_reverse( |
703 void cx_linked_list_reverse( |
| 658 void **begin, |
704 void **begin, |
| 659 void **end, |
705 void **end, |
| 796 char *next = CX_LL_PTR(node, ll->loc_next); |
842 char *next = CX_LL_PTR(node, ll->loc_next); |
| 797 return next + ll->loc_data; |
843 return next + ll->loc_data; |
| 798 } |
844 } |
| 799 } |
845 } |
| 800 |
846 |
| 801 static _Thread_local cx_compare_func cx_ll_insert_sorted_cmp_func; |
847 static int cx_ll_insert_sorted_cmp_helper(const void *l, const void *r, void *c) { |
| 802 static _Thread_local off_t cx_ll_insert_sorted_loc_data; |
848 cx_linked_list *list = c; |
| 803 |
849 const char *left = (const char*)l + list->loc_data; |
| 804 static int cx_ll_insert_sorted_cmp_helper(const void *l, const void *r) { |
850 const char *right = (const char*)r + list->loc_data; |
| 805 const char *left = (const char*)l + cx_ll_insert_sorted_loc_data; |
851 return cx_list_compare_wrapper(left, right, list); |
| 806 const char *right = (const char*)r + cx_ll_insert_sorted_loc_data; |
|
| 807 return cx_ll_insert_sorted_cmp_func(left, right); |
|
| 808 } |
852 } |
| 809 |
853 |
| 810 static size_t cx_ll_insert_sorted_impl( |
854 static size_t cx_ll_insert_sorted_impl( |
| 811 struct cx_list_s *list, |
855 struct cx_list_s *list, |
| 812 const void *array, |
856 const void *array, |
| 837 CX_LL_PTR(next, ll->loc_prev) = prev; |
881 CX_LL_PTR(next, ll->loc_prev) = prev; |
| 838 prev = next; |
882 prev = next; |
| 839 } |
883 } |
| 840 CX_LL_PTR(prev, ll->loc_next) = NULL; |
884 CX_LL_PTR(prev, ll->loc_next) = NULL; |
| 841 |
885 |
| 842 // invoke the low level function |
886 // invoke the low-level function |
| 843 cx_ll_insert_sorted_cmp_func = list->collection.cmpfunc; |
887 void *duplicates = cx_linked_list_insert_sorted_chain_impl( |
| 844 cx_ll_insert_sorted_loc_data = ll->loc_data; |
888 &ll->begin, |
| 845 if (allow_duplicates) { |
889 &ll->end, |
| 846 cx_linked_list_insert_sorted_chain( |
890 ll->loc_prev, |
| 847 &ll->begin, |
891 ll->loc_next, |
| 848 &ll->end, |
892 chain, |
| 849 ll->loc_prev, |
893 cx_ll_insert_sorted_cmp_helper, |
| 850 ll->loc_next, |
894 list, |
| 851 chain, |
895 allow_duplicates |
| 852 cx_ll_insert_sorted_cmp_helper |
896 ); |
| 853 ); |
897 list->collection.size += inserted; |
| 854 list->collection.size += inserted; |
898 if (!allow_duplicates) { |
| 855 } else { |
|
| 856 void *duplicates = cx_linked_list_insert_unique_chain( |
|
| 857 &ll->begin, |
|
| 858 &ll->end, |
|
| 859 ll->loc_prev, |
|
| 860 ll->loc_next, |
|
| 861 chain, |
|
| 862 cx_ll_insert_sorted_cmp_helper |
|
| 863 ); |
|
| 864 list->collection.size += inserted; |
|
| 865 // free the nodes that did not make it into the list |
899 // free the nodes that did not make it into the list |
| 866 while (duplicates != NULL) { |
900 while (duplicates != NULL) { |
| 867 void *next = CX_LL_PTR(duplicates, ll->loc_next); |
901 void *next = CX_LL_PTR(duplicates, ll->loc_next); |
| 868 cxFree(list->collection.allocator, duplicates); |
902 cxFree(list->collection.allocator, duplicates); |
| 869 duplicates = next; |
903 duplicates = next; |
| 1127 ) { |
1161 ) { |
| 1128 cx_linked_list *left = (cx_linked_list *) list; |
1162 cx_linked_list *left = (cx_linked_list *) list; |
| 1129 cx_linked_list *right = (cx_linked_list *) other; |
1163 cx_linked_list *right = (cx_linked_list *) other; |
| 1130 assert(left->loc_next == right->loc_next); |
1164 assert(left->loc_next == right->loc_next); |
| 1131 assert(left->loc_data == right->loc_data); |
1165 assert(left->loc_data == right->loc_data); |
| 1132 return cx_linked_list_compare(left->begin, right->begin, |
1166 return cx_linked_list_compare_c(left->begin, right->begin, |
| 1133 left->loc_next, left->loc_data, |
1167 left->loc_next, left->loc_data, |
| 1134 list->collection.cmpfunc); |
1168 cx_list_compare_wrapper, (void*)list); |
| 1135 } |
1169 } |
| 1136 |
1170 |
| 1137 static bool cx_ll_iter_valid(const void *it) { |
1171 static bool cx_ll_iter_valid(const void *it) { |
| 1138 const struct cx_iterator_s *iter = it; |
1172 const struct cx_iterator_s *iter = it; |
| 1139 return iter->elem_handle != NULL; |
1173 return iter->elem_handle != NULL; |