| 54 i < index ? i++ : i--; |
54 i < index ? i++ : i--; |
| 55 } |
55 } |
| 56 return (void *) cur; |
56 return (void *) cur; |
| 57 } |
57 } |
| 58 |
58 |
| 59 ssize_t cx_linked_list_find( |
59 void *cx_linked_list_find( |
| 60 const void *start, |
60 const void *start, |
| 61 ptrdiff_t loc_advance, |
61 ptrdiff_t loc_advance, |
| 62 ptrdiff_t loc_data, |
62 ptrdiff_t loc_data, |
| 63 cx_compare_func cmp_func, |
63 cx_compare_func cmp_func, |
| 64 const void *elem |
64 const void *elem, |
| 65 ) { |
65 size_t *found_index |
| 66 void *dummy; |
66 ) { |
| 67 return cx_linked_list_find_node( |
|
| 68 &dummy, start, |
|
| 69 loc_advance, loc_data, |
|
| 70 cmp_func, elem |
|
| 71 ); |
|
| 72 } |
|
| 73 |
|
| 74 ssize_t cx_linked_list_find_node( |
|
| 75 void **result, |
|
| 76 const void *start, |
|
| 77 ptrdiff_t loc_advance, |
|
| 78 ptrdiff_t loc_data, |
|
| 79 cx_compare_func cmp_func, |
|
| 80 const void *elem |
|
| 81 ) { |
|
| 82 assert(result != NULL); |
|
| 83 assert(start != NULL); |
67 assert(start != NULL); |
| 84 assert(loc_advance >= 0); |
68 assert(loc_advance >= 0); |
| 85 assert(loc_data >= 0); |
69 assert(loc_data >= 0); |
| 86 assert(cmp_func); |
70 assert(cmp_func); |
| 87 |
71 |
| 88 const void *node = start; |
72 void *node = (void*) start; |
| 89 ssize_t index = 0; |
73 size_t index = 0; |
| 90 do { |
74 do { |
| 91 void *current = ll_data(node); |
75 void *current = ll_data(node); |
| 92 if (cmp_func(current, elem) == 0) { |
76 if (cmp_func(current, elem) == 0) { |
| 93 *result = (void *) node; |
77 if (found_index != NULL) { |
| 94 return index; |
78 *found_index = index; |
| |
79 } |
| |
80 return node; |
| 95 } |
81 } |
| 96 node = ll_advance(node); |
82 node = ll_advance(node); |
| 97 index++; |
83 index++; |
| 98 } while (node != NULL); |
84 } while (node != NULL); |
| 99 *result = NULL; |
85 return NULL; |
| 100 return -1; |
|
| 101 } |
86 } |
| 102 |
87 |
| 103 void *cx_linked_list_first( |
88 void *cx_linked_list_first( |
| 104 const void *node, |
89 const void *node, |
| 105 ptrdiff_t loc_prev |
90 ptrdiff_t loc_prev |
| 808 node = next; |
793 node = next; |
| 809 } |
794 } |
| 810 ll->begin = ll->end = NULL; |
795 ll->begin = ll->end = NULL; |
| 811 list->collection.size = 0; |
796 list->collection.size = 0; |
| 812 } |
797 } |
| 813 |
|
| 814 #ifndef CX_LINKED_LIST_SWAP_SBO_SIZE |
|
| 815 #define CX_LINKED_LIST_SWAP_SBO_SIZE 128 |
|
| 816 #endif |
|
| 817 const unsigned cx_linked_list_swap_sbo_size = CX_LINKED_LIST_SWAP_SBO_SIZE; |
|
| 818 |
798 |
| 819 static int cx_ll_swap( |
799 static int cx_ll_swap( |
| 820 struct cx_list_s *list, |
800 struct cx_list_s *list, |
| 821 size_t i, |
801 size_t i, |
| 822 size_t j |
802 size_t j |
| 892 nleft = cx_ll_node_at(ll, other); |
872 nleft = cx_ll_node_at(ll, other); |
| 893 } |
873 } |
| 894 } |
874 } |
| 895 } |
875 } |
| 896 |
876 |
| 897 if (list->collection.elem_size > CX_LINKED_LIST_SWAP_SBO_SIZE) { |
877 cx_linked_list_node *prev = nleft->prev; |
| 898 cx_linked_list_node *prev = nleft->prev; |
878 cx_linked_list_node *next = nright->next; |
| 899 cx_linked_list_node *next = nright->next; |
879 cx_linked_list_node *midstart = nleft->next; |
| 900 cx_linked_list_node *midstart = nleft->next; |
880 cx_linked_list_node *midend = nright->prev; |
| 901 cx_linked_list_node *midend = nright->prev; |
881 |
| 902 |
882 if (prev == NULL) { |
| 903 if (prev == NULL) { |
883 ll->begin = nright; |
| 904 ll->begin = nright; |
884 } else { |
| 905 } else { |
885 prev->next = nright; |
| 906 prev->next = nright; |
886 } |
| 907 } |
887 nright->prev = prev; |
| 908 nright->prev = prev; |
888 if (midstart == nright) { |
| 909 if (midstart == nright) { |
889 // special case: both nodes are adjacent |
| 910 // special case: both nodes are adjacent |
890 nright->next = nleft; |
| 911 nright->next = nleft; |
891 nleft->prev = nright; |
| 912 nleft->prev = nright; |
892 } else { |
| 913 } else { |
893 // likely case: a chain is between the two nodes |
| 914 // likely case: a chain is between the two nodes |
894 nright->next = midstart; |
| 915 nright->next = midstart; |
895 midstart->prev = nright; |
| 916 midstart->prev = nright; |
896 midend->next = nleft; |
| 917 midend->next = nleft; |
897 nleft->prev = midend; |
| 918 nleft->prev = midend; |
898 } |
| 919 } |
899 nleft->next = next; |
| 920 nleft->next = next; |
900 if (next == NULL) { |
| 921 if (next == NULL) { |
901 ll->end = nleft; |
| 922 ll->end = nleft; |
902 } else { |
| 923 } else { |
903 next->prev = nleft; |
| 924 next->prev = nleft; |
|
| 925 } |
|
| 926 } else { |
|
| 927 // swap payloads to avoid relinking |
|
| 928 char buf[CX_LINKED_LIST_SWAP_SBO_SIZE]; |
|
| 929 memcpy(buf, nleft->payload, list->collection.elem_size); |
|
| 930 memcpy(nleft->payload, nright->payload, list->collection.elem_size); |
|
| 931 memcpy(nright->payload, buf, list->collection.elem_size); |
|
| 932 } |
904 } |
| 933 |
905 |
| 934 return 0; |
906 return 0; |
| 935 } |
907 } |
| 936 |
908 |
| 941 cx_linked_list *ll = (cx_linked_list *) list; |
913 cx_linked_list *ll = (cx_linked_list *) list; |
| 942 cx_linked_list_node *node = cx_ll_node_at(ll, index); |
914 cx_linked_list_node *node = cx_ll_node_at(ll, index); |
| 943 return node == NULL ? NULL : node->payload; |
915 return node == NULL ? NULL : node->payload; |
| 944 } |
916 } |
| 945 |
917 |
| 946 static ssize_t cx_ll_find_remove( |
918 static size_t cx_ll_find_remove( |
| 947 struct cx_list_s *list, |
919 struct cx_list_s *list, |
| 948 const void *elem, |
920 const void *elem, |
| 949 bool remove |
921 bool remove |
| 950 ) { |
922 ) { |
| |
923 size_t index; |
| |
924 cx_linked_list *ll = ((cx_linked_list *) list); |
| |
925 cx_linked_list_node *node = cx_linked_list_find( |
| |
926 ll->begin, |
| |
927 CX_LL_LOC_NEXT, CX_LL_LOC_DATA, |
| |
928 list->collection.cmpfunc, elem, |
| |
929 &index |
| |
930 ); |
| |
931 if (node == NULL) { |
| |
932 return list->collection.size; |
| |
933 } |
| 951 if (remove) { |
934 if (remove) { |
| 952 cx_linked_list *ll = ((cx_linked_list *) list); |
935 cx_invoke_destructor(list, node->payload); |
| 953 cx_linked_list_node *node; |
936 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, |
| 954 ssize_t index = cx_linked_list_find_node( |
937 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); |
| 955 (void **) &node, |
938 list->collection.size--; |
| 956 ll->begin, |
939 cxFree(list->collection.allocator, node); |
| 957 CX_LL_LOC_NEXT, CX_LL_LOC_DATA, |
940 } |
| 958 list->collection.cmpfunc, elem |
941 return index; |
| 959 ); |
|
| 960 if (node != NULL) { |
|
| 961 cx_invoke_destructor(list, node->payload); |
|
| 962 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, |
|
| 963 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); |
|
| 964 list->collection.size--; |
|
| 965 cxFree(list->collection.allocator, node); |
|
| 966 } |
|
| 967 return index; |
|
| 968 } else { |
|
| 969 return cx_linked_list_find( |
|
| 970 ((cx_linked_list *) list)->begin, |
|
| 971 CX_LL_LOC_NEXT, CX_LL_LOC_DATA, |
|
| 972 list->collection.cmpfunc, elem |
|
| 973 ); |
|
| 974 } |
|
| 975 } |
942 } |
| 976 |
943 |
| 977 static void cx_ll_sort(struct cx_list_s *list) { |
944 static void cx_ll_sort(struct cx_list_s *list) { |
| 978 cx_linked_list *ll = (cx_linked_list *) list; |
945 cx_linked_list *ll = (cx_linked_list *) list; |
| 979 cx_linked_list_sort((void **) &ll->begin, (void **) &ll->end, |
946 cx_linked_list_sort((void **) &ll->begin, (void **) &ll->end, |
| 1136 allocator = cxDefaultAllocator; |
1103 allocator = cxDefaultAllocator; |
| 1137 } |
1104 } |
| 1138 |
1105 |
| 1139 cx_linked_list *list = cxCalloc(allocator, 1, sizeof(cx_linked_list)); |
1106 cx_linked_list *list = cxCalloc(allocator, 1, sizeof(cx_linked_list)); |
| 1140 if (list == NULL) return NULL; |
1107 if (list == NULL) return NULL; |
| 1141 |
1108 cx_list_init((CxList*)list, &cx_linked_list_class, |
| 1142 list->base.cl = &cx_linked_list_class; |
1109 allocator, comparator, elem_size); |
| 1143 list->base.collection.allocator = allocator; |
|
| 1144 |
|
| 1145 if (elem_size > 0) { |
|
| 1146 list->base.collection.elem_size = elem_size; |
|
| 1147 list->base.collection.cmpfunc = comparator; |
|
| 1148 } else { |
|
| 1149 list->base.collection.cmpfunc = comparator == NULL ? cx_cmp_ptr : comparator; |
|
| 1150 cxListStorePointers((CxList *) list); |
|
| 1151 } |
|
| 1152 |
1110 |
| 1153 return (CxList *) list; |
1111 return (CxList *) list; |
| 1154 } |
1112 } |