| 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_ccmp_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); |
356 cx_linked_list_link(new_end, source_argument, loc_prev, loc_next); |
| 355 new_end = cx_linked_list_last(source_argument, loc_next); |
357 new_end = cx_linked_list_last(source_argument, loc_next); |
| 356 } else { |
358 } else { |
| 357 // otherwise we must check one-by-one |
359 // otherwise we must check one-by-one |
| 358 while (source_argument != NULL) { |
360 while (source_argument != NULL) { |
| 359 if (cmp_func(new_end, source_argument) == 0) { |
361 if (cmp_func(new_end, source_argument, context) == 0) { |
| 360 if (dup_end == NULL) { |
362 if (dup_end == NULL) { |
| 361 dup_begin = dup_end = source_argument; |
363 dup_begin = dup_end = source_argument; |
| 362 } else { |
364 } else { |
| 363 cx_linked_list_link(dup_end, source_argument, loc_prev, loc_next); |
365 cx_linked_list_link(dup_end, source_argument, loc_prev, loc_next); |
| 364 dup_end = source_argument; |
366 dup_end = source_argument; |
| 392 *end = new_end; |
394 *end = new_end; |
| 393 } |
395 } |
| 394 return dup_begin; |
396 return dup_begin; |
| 395 } |
397 } |
| 396 |
398 |
| |
399 void cx_linked_list_insert_sorted( |
| |
400 void **begin, |
| |
401 void **end, |
| |
402 ptrdiff_t loc_prev, |
| |
403 ptrdiff_t loc_next, |
| |
404 void *new_node, |
| |
405 cx_compare_func cmp_func |
| |
406 ) { |
| |
407 assert(ll_next(new_node) == NULL); |
| |
408 cx_linked_list_insert_sorted_chain( |
| |
409 begin, end, loc_prev, loc_next, new_node, cmp_func); |
| |
410 } |
| |
411 |
| 397 void cx_linked_list_insert_sorted_chain( |
412 void cx_linked_list_insert_sorted_chain( |
| 398 void **begin, |
413 void **begin, |
| 399 void **end, |
414 void **end, |
| 400 ptrdiff_t loc_prev, |
415 ptrdiff_t loc_prev, |
| 401 ptrdiff_t loc_next, |
416 ptrdiff_t loc_next, |
| 402 void *insert_begin, |
417 void *insert_begin, |
| 403 cx_compare_func cmp_func |
418 cx_compare_func cmp_func |
| 404 ) { |
419 ) { |
| |
420 cx_compare_func_wrapper wrapper = {cmp_func}; |
| 405 cx_linked_list_insert_sorted_chain_impl( |
421 cx_linked_list_insert_sorted_chain_impl( |
| 406 begin, end, loc_prev, loc_next, |
422 begin, end, loc_prev, loc_next, |
| 407 insert_begin, cmp_func, true); |
423 insert_begin, cx_ccmp_wrap, &wrapper, true); |
| 408 } |
424 } |
| 409 |
425 |
| 410 int cx_linked_list_insert_unique( |
426 int cx_linked_list_insert_unique( |
| 411 void **begin, |
427 void **begin, |
| 412 void **end, |
428 void **end, |
| 426 ptrdiff_t loc_prev, |
442 ptrdiff_t loc_prev, |
| 427 ptrdiff_t loc_next, |
443 ptrdiff_t loc_next, |
| 428 void *insert_begin, |
444 void *insert_begin, |
| 429 cx_compare_func cmp_func |
445 cx_compare_func cmp_func |
| 430 ) { |
446 ) { |
| |
447 cx_compare_func_wrapper wrapper = {cmp_func}; |
| 431 return cx_linked_list_insert_sorted_chain_impl( |
448 return cx_linked_list_insert_sorted_chain_impl( |
| 432 begin, end, loc_prev, loc_next, |
449 begin, end, loc_prev, loc_next, |
| 433 insert_begin, cmp_func, false); |
450 insert_begin, cx_ccmp_wrap, &wrapper, false); |
| |
451 } |
| |
452 |
| |
453 void cx_linked_list_insert_sorted_c( |
| |
454 void **begin, |
| |
455 void **end, |
| |
456 ptrdiff_t loc_prev, |
| |
457 ptrdiff_t loc_next, |
| |
458 void *new_node, |
| |
459 cx_compare_func2 cmp_func, |
| |
460 void *context |
| |
461 ) { |
| |
462 assert(ll_next(new_node) == NULL); |
| |
463 cx_linked_list_insert_sorted_chain_c( |
| |
464 begin, end, loc_prev, loc_next, new_node, cmp_func, context); |
| |
465 } |
| |
466 |
| |
467 void cx_linked_list_insert_sorted_chain_c( |
| |
468 void **begin, |
| |
469 void **end, |
| |
470 ptrdiff_t loc_prev, |
| |
471 ptrdiff_t loc_next, |
| |
472 void *insert_begin, |
| |
473 cx_compare_func2 cmp_func, |
| |
474 void *context |
| |
475 ) { |
| |
476 cx_linked_list_insert_sorted_chain_impl( |
| |
477 begin, end, loc_prev, loc_next, |
| |
478 insert_begin, cmp_func, context, true); |
| |
479 } |
| |
480 |
| |
481 int cx_linked_list_insert_unique_c( |
| |
482 void **begin, |
| |
483 void **end, |
| |
484 ptrdiff_t loc_prev, |
| |
485 ptrdiff_t loc_next, |
| |
486 void *new_node, |
| |
487 cx_compare_func2 cmp_func, |
| |
488 void *context |
| |
489 ) { |
| |
490 assert(ll_next(new_node) == NULL); |
| |
491 return NULL != cx_linked_list_insert_unique_chain_c( |
| |
492 begin, end, loc_prev, loc_next, new_node, cmp_func, context); |
| |
493 } |
| |
494 |
| |
495 void *cx_linked_list_insert_unique_chain_c( |
| |
496 void **begin, |
| |
497 void **end, |
| |
498 ptrdiff_t loc_prev, |
| |
499 ptrdiff_t loc_next, |
| |
500 void *insert_begin, |
| |
501 cx_compare_func2 cmp_func, |
| |
502 void *context |
| |
503 ) { |
| |
504 return cx_linked_list_insert_sorted_chain_impl( |
| |
505 begin, end, loc_prev, loc_next, |
| |
506 insert_begin, cmp_func, context, false); |
| 434 } |
507 } |
| 435 |
508 |
| 436 size_t cx_linked_list_remove_chain( |
509 size_t cx_linked_list_remove_chain( |
| 437 void **begin, |
510 void **begin, |
| 438 void **end, |
511 void **end, |
| 600 if (le != NULL) { |
675 if (le != NULL) { |
| 601 void *rc; |
676 void *rc; |
| 602 size_t rn = 1; |
677 size_t rn = 1; |
| 603 rc = le; |
678 rc = le; |
| 604 // skip already sorted elements |
679 // skip already sorted elements |
| 605 while (ll_next(rc) != NULL && cmp_func(ll_data(ll_next(rc)), ll_data(rc)) > 0) { |
680 while (ll_next(rc) != NULL && cmp_func(ll_data(ll_next(rc)), ll_data(rc), context) > 0) { |
| 606 rc = ll_next(rc); |
681 rc = ll_next(rc); |
| 607 rn++; |
682 rn++; |
| 608 } |
683 } |
| 609 re = ll_next(rc); |
684 re = ll_next(rc); |
| 610 |
685 |
| 611 // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them |
686 // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them |
| 612 void *sorted_begin, *sorted_end; |
687 void *sorted_begin, *sorted_end; |
| 613 cx_linked_list_sort_merge(loc_prev, loc_next, loc_data, |
688 cx_linked_list_sort_merge(&sorted_begin, &sorted_end, |
| |
689 loc_prev, loc_next, loc_data, |
| 614 ln + rn, ls, le, re, cmp_func, |
690 ln + rn, ls, le, re, cmp_func, |
| 615 &sorted_begin, &sorted_end); |
691 context); |
| 616 |
692 |
| 617 // Something left? Sort it! |
693 // Something left? Sort it! |
| 618 size_t remainder_length = cx_linked_list_size(re, loc_next); |
694 size_t remainder_length = cx_linked_list_size(re, loc_next); |
| 619 if (remainder_length > 0) { |
695 if (remainder_length > 0) { |
| 620 void *remainder = re; |
696 void *remainder = re; |
| 621 cx_linked_list_sort(&remainder, NULL, loc_prev, loc_next, loc_data, cmp_func); |
697 cx_linked_list_sort_c(&remainder, NULL, loc_prev, loc_next, loc_data, cmp_func, context); |
| 622 |
698 |
| 623 // merge sorted list with (also sorted) remainder |
699 // merge sorted list with (also sorted) remainder |
| 624 cx_linked_list_sort_merge(loc_prev, loc_next, loc_data, |
700 cx_linked_list_sort_merge(&sorted_begin, &sorted_end, |
| |
701 loc_prev, loc_next, loc_data, |
| 625 ln + rn + remainder_length, |
702 ln + rn + remainder_length, |
| 626 sorted_begin, remainder, NULL, cmp_func, |
703 sorted_begin, remainder, NULL, cmp_func, |
| 627 &sorted_begin, &sorted_end); |
704 context); |
| 628 } |
705 } |
| 629 *begin = sorted_begin; |
706 *begin = sorted_begin; |
| 630 if (end) *end = sorted_end; |
707 if (end) *end = sorted_end; |
| 631 } |
708 } |
| |
709 } |
| |
710 |
| |
711 void cx_linked_list_sort( |
| |
712 void **begin, |
| |
713 void **end, |
| |
714 ptrdiff_t loc_prev, |
| |
715 ptrdiff_t loc_next, |
| |
716 ptrdiff_t loc_data, |
| |
717 cx_compare_func cmp_func |
| |
718 ) { |
| |
719 cx_compare_func_wrapper wrapper = {cmp_func}; |
| |
720 cx_linked_list_sort_c(begin, end, loc_prev, loc_next, loc_data, cx_ccmp_wrap, &wrapper); |
| |
721 } |
| |
722 |
| |
723 int cx_linked_list_compare_c( |
| |
724 const void *begin_left, |
| |
725 const void *begin_right, |
| |
726 ptrdiff_t loc_advance, |
| |
727 ptrdiff_t loc_data, |
| |
728 cx_compare_func2 cmp_func, |
| |
729 void *context |
| |
730 ) { |
| |
731 const void *left = begin_left, *right = begin_right; |
| |
732 |
| |
733 while (left != NULL && right != NULL) { |
| |
734 const void *left_data = ll_data(left); |
| |
735 const void *right_data = ll_data(right); |
| |
736 int result = cmp_func(left_data, right_data, context); |
| |
737 if (result != 0) return result; |
| |
738 left = ll_advance(left); |
| |
739 right = ll_advance(right); |
| |
740 } |
| |
741 |
| |
742 if (left != NULL) { return 1; } |
| |
743 else if (right != NULL) { return -1; } |
| |
744 else { return 0; } |
| 632 } |
745 } |
| 633 |
746 |
| 634 int cx_linked_list_compare( |
747 int cx_linked_list_compare( |
| 635 const void *begin_left, |
748 const void *begin_left, |
| 636 const void *begin_right, |
749 const void *begin_right, |
| 637 ptrdiff_t loc_advance, |
750 ptrdiff_t loc_advance, |
| 638 ptrdiff_t loc_data, |
751 ptrdiff_t loc_data, |
| 639 cx_compare_func cmp_func |
752 cx_compare_func cmp_func |
| 640 ) { |
753 ) { |
| 641 const void *left = begin_left, *right = begin_right; |
754 cx_compare_func_wrapper wrapper = {cmp_func}; |
| 642 |
755 return cx_linked_list_compare_c(begin_left, begin_right, |
| 643 while (left != NULL && right != NULL) { |
756 loc_advance, loc_data, cx_ccmp_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 } |
757 } |
| 656 |
758 |
| 657 void cx_linked_list_reverse( |
759 void cx_linked_list_reverse( |
| 658 void **begin, |
760 void **begin, |
| 659 void **end, |
761 void **end, |
| 796 char *next = CX_LL_PTR(node, ll->loc_next); |
898 char *next = CX_LL_PTR(node, ll->loc_next); |
| 797 return next + ll->loc_data; |
899 return next + ll->loc_data; |
| 798 } |
900 } |
| 799 } |
901 } |
| 800 |
902 |
| 801 static _Thread_local cx_compare_func cx_ll_insert_sorted_cmp_func; |
903 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; |
904 cx_linked_list *list = c; |
| 803 |
905 const char *left = (const char*)l + list->loc_data; |
| 804 static int cx_ll_insert_sorted_cmp_helper(const void *l, const void *r) { |
906 const char *right = (const char*)r + list->loc_data; |
| 805 const char *left = (const char*)l + cx_ll_insert_sorted_loc_data; |
907 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 } |
908 } |
| 809 |
909 |
| 810 static size_t cx_ll_insert_sorted_impl( |
910 static size_t cx_ll_insert_sorted_impl( |
| 811 struct cx_list_s *list, |
911 struct cx_list_s *list, |
| 812 const void *array, |
912 const void *array, |
| 837 CX_LL_PTR(next, ll->loc_prev) = prev; |
937 CX_LL_PTR(next, ll->loc_prev) = prev; |
| 838 prev = next; |
938 prev = next; |
| 839 } |
939 } |
| 840 CX_LL_PTR(prev, ll->loc_next) = NULL; |
940 CX_LL_PTR(prev, ll->loc_next) = NULL; |
| 841 |
941 |
| 842 // invoke the low level function |
942 // invoke the low-level function |
| 843 cx_ll_insert_sorted_cmp_func = list->collection.cmpfunc; |
943 void *duplicates = cx_linked_list_insert_sorted_chain_impl( |
| 844 cx_ll_insert_sorted_loc_data = ll->loc_data; |
944 &ll->begin, |
| 845 if (allow_duplicates) { |
945 &ll->end, |
| 846 cx_linked_list_insert_sorted_chain( |
946 ll->loc_prev, |
| 847 &ll->begin, |
947 ll->loc_next, |
| 848 &ll->end, |
948 chain, |
| 849 ll->loc_prev, |
949 cx_ll_insert_sorted_cmp_helper, |
| 850 ll->loc_next, |
950 list, |
| 851 chain, |
951 allow_duplicates |
| 852 cx_ll_insert_sorted_cmp_helper |
952 ); |
| 853 ); |
953 list->collection.size += inserted; |
| 854 list->collection.size += inserted; |
954 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 |
955 // free the nodes that did not make it into the list |
| 866 while (duplicates != NULL) { |
956 while (duplicates != NULL) { |
| 867 void *next = CX_LL_PTR(duplicates, ll->loc_next); |
957 void *next = CX_LL_PTR(duplicates, ll->loc_next); |
| 868 cxFree(list->collection.allocator, duplicates); |
958 cxFree(list->collection.allocator, duplicates); |
| 869 duplicates = next; |
959 duplicates = next; |
| 1127 ) { |
1217 ) { |
| 1128 cx_linked_list *left = (cx_linked_list *) list; |
1218 cx_linked_list *left = (cx_linked_list *) list; |
| 1129 cx_linked_list *right = (cx_linked_list *) other; |
1219 cx_linked_list *right = (cx_linked_list *) other; |
| 1130 assert(left->loc_next == right->loc_next); |
1220 assert(left->loc_next == right->loc_next); |
| 1131 assert(left->loc_data == right->loc_data); |
1221 assert(left->loc_data == right->loc_data); |
| 1132 return cx_linked_list_compare(left->begin, right->begin, |
1222 return cx_linked_list_compare_c(left->begin, right->begin, |
| 1133 left->loc_next, left->loc_data, |
1223 left->loc_next, left->loc_data, |
| 1134 list->collection.cmpfunc); |
1224 cx_list_compare_wrapper, (void*)list); |
| 1135 } |
1225 } |
| 1136 |
1226 |
| 1137 static bool cx_ll_iter_valid(const void *it) { |
1227 static bool cx_ll_iter_valid(const void *it) { |
| 1138 const struct cx_iterator_s *iter = it; |
1228 const struct cx_iterator_s *iter = it; |
| 1139 return iter->elem_handle != NULL; |
1229 return iter->elem_handle != NULL; |