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/linked_list.h" |
29 #include "cx/linked_list.h" |
30 #include "cx/utils.h" |
|
31 #include "cx/compare.h" |
30 #include "cx/compare.h" |
32 #include <string.h> |
31 #include <string.h> |
33 #include <assert.h> |
32 #include <assert.h> |
34 |
33 |
35 // LOW LEVEL LINKED LIST FUNCTIONS |
34 // LOW LEVEL LINKED LIST FUNCTIONS |
89 const void *node = start; |
88 const void *node = start; |
90 ssize_t index = 0; |
89 ssize_t index = 0; |
91 do { |
90 do { |
92 void *current = ll_data(node); |
91 void *current = ll_data(node); |
93 if (cmp_func(current, elem) == 0) { |
92 if (cmp_func(current, elem) == 0) { |
94 *result = (void*) node; |
93 *result = (void *) node; |
95 return index; |
94 return index; |
96 } |
95 } |
97 node = ll_advance(node); |
96 node = ll_advance(node); |
98 index++; |
97 index++; |
99 } while (node != NULL); |
98 } while (node != NULL); |
334 *end = cx_linked_list_last( |
333 *end = cx_linked_list_last( |
335 dest != NULL ? dest : dest_prev, loc_next); |
334 dest != NULL ? dest : dest_prev, loc_next); |
336 } |
335 } |
337 } |
336 } |
338 |
337 |
339 void cx_linked_list_remove( |
338 size_t cx_linked_list_remove_chain( |
340 void **begin, |
339 void **begin, |
341 void **end, |
340 void **end, |
342 ptrdiff_t loc_prev, |
341 ptrdiff_t loc_prev, |
343 ptrdiff_t loc_next, |
342 ptrdiff_t loc_next, |
344 void *node |
343 void *node, |
|
344 size_t num |
345 ) { |
345 ) { |
346 assert(node != NULL); |
346 assert(node != NULL); |
347 assert(loc_next >= 0); |
347 assert(loc_next >= 0); |
348 assert(loc_prev >= 0 || begin != NULL); |
348 assert(loc_prev >= 0 || begin != NULL); |
349 |
349 |
|
350 // easy exit |
|
351 if (num == 0) return 0; |
|
352 |
350 // find adjacent nodes |
353 // find adjacent nodes |
351 void *next = ll_next(node); |
|
352 void *prev; |
354 void *prev; |
353 if (loc_prev >= 0) { |
355 if (loc_prev >= 0) { |
354 prev = ll_prev(node); |
356 prev = ll_prev(node); |
355 } else { |
357 } else { |
356 prev = cx_linked_list_prev(*begin, loc_next, node); |
358 prev = cx_linked_list_prev(*begin, loc_next, node); |
|
359 } |
|
360 |
|
361 void *next = ll_next(node); |
|
362 size_t removed = 1; |
|
363 for (; removed < num && next != NULL ; removed++) { |
|
364 next = ll_next(next); |
357 } |
365 } |
358 |
366 |
359 // update next pointer of prev node, or set begin |
367 // update next pointer of prev node, or set begin |
360 if (prev == NULL) { |
368 if (prev == NULL) { |
361 if (begin != NULL) { |
369 if (begin != NULL) { |
434 n++; |
444 n++; |
435 } |
445 } |
436 |
446 |
437 // Update pointer |
447 // Update pointer |
438 if (loc_prev >= 0) ll_prev(sorted[0]) = NULL; |
448 if (loc_prev >= 0) ll_prev(sorted[0]) = NULL; |
439 cx_for_n (i, length - 1) { |
449 for (size_t i = 0 ; i < length - 1; i++) { |
440 cx_linked_list_link(sorted[i], sorted[i + 1], loc_prev, loc_next); |
450 cx_linked_list_link(sorted[i], sorted[i + 1], loc_prev, loc_next); |
441 } |
451 } |
442 ll_next(sorted[length - 1]) = NULL; |
452 ll_next(sorted[length - 1]) = NULL; |
443 |
453 |
444 *begin = sorted[0]; |
454 *begin = sorted[0]; |
445 *end = sorted[length-1]; |
455 *end = sorted[length - 1]; |
446 if (sorted != sbo) { |
456 if (sorted != sbo) { |
447 free(sorted); |
457 free(sorted); |
448 } |
458 } |
449 } |
459 } |
450 |
460 |
644 |
654 |
645 // find position efficiently |
655 // find position efficiently |
646 cx_linked_list_node *node = index == 0 ? NULL : cx_ll_node_at((cx_linked_list *) list, index - 1); |
656 cx_linked_list_node *node = index == 0 ? NULL : cx_ll_node_at((cx_linked_list *) list, index - 1); |
647 |
657 |
648 // perform first insert |
658 // perform first insert |
649 if (0 != cx_ll_insert_at(list, node, array)) { |
659 if (0 != cx_ll_insert_at(list, node, array)) return 1; |
650 return 1; |
|
651 } |
|
652 |
660 |
653 // is there more? |
661 // is there more? |
654 if (n == 1) return 1; |
662 if (n == 1) return 1; |
655 |
663 |
656 // we now know exactly where we are |
664 // we now know exactly where we are |
658 |
666 |
659 // we can add the remaining nodes and immediately advance to the inserted node |
667 // we can add the remaining nodes and immediately advance to the inserted node |
660 const char *source = array; |
668 const char *source = array; |
661 for (size_t i = 1; i < n; i++) { |
669 for (size_t i = 1; i < n; i++) { |
662 source += list->collection.elem_size; |
670 source += list->collection.elem_size; |
663 if (0 != cx_ll_insert_at(list, node, source)) { |
671 if (0 != cx_ll_insert_at(list, node, source)) return i; |
664 return i; |
|
665 } |
|
666 node = node->next; |
672 node = node->next; |
667 } |
673 } |
668 return n; |
674 return n; |
669 } |
675 } |
670 |
676 |
731 list->collection.size += inserted; |
737 list->collection.size += inserted; |
732 |
738 |
733 return inserted; |
739 return inserted; |
734 } |
740 } |
735 |
741 |
736 static int cx_ll_remove( |
742 static size_t cx_ll_remove( |
737 struct cx_list_s *list, |
743 struct cx_list_s *list, |
738 size_t index |
744 size_t index, |
|
745 size_t num, |
|
746 void *targetbuf |
739 ) { |
747 ) { |
740 cx_linked_list *ll = (cx_linked_list *) list; |
748 cx_linked_list *ll = (cx_linked_list *) list; |
741 cx_linked_list_node *node = cx_ll_node_at(ll, index); |
749 cx_linked_list_node *node = cx_ll_node_at(ll, index); |
742 |
750 |
743 // out-of-bounds check |
751 // out-of-bounds check |
744 if (node == NULL) return 1; |
752 if (node == NULL) return 0; |
745 |
|
746 // element destruction |
|
747 cx_invoke_destructor(list, node->payload); |
|
748 |
753 |
749 // remove |
754 // remove |
750 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, |
755 size_t removed = cx_linked_list_remove_chain( |
751 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); |
756 (void **) &ll->begin, |
|
757 (void **) &ll->end, |
|
758 CX_LL_LOC_PREV, |
|
759 CX_LL_LOC_NEXT, |
|
760 node, |
|
761 num |
|
762 ); |
752 |
763 |
753 // adjust size |
764 // adjust size |
754 list->collection.size--; |
765 list->collection.size -= removed; |
755 |
766 |
756 // free and return |
767 // copy or destroy the removed chain |
757 cxFree(list->collection.allocator, node); |
768 if (targetbuf == NULL) { |
758 |
769 cx_linked_list_node *n = node; |
759 return 0; |
770 for (size_t i = 0; i < removed; i++) { |
|
771 // element destruction |
|
772 cx_invoke_destructor(list, n->payload); |
|
773 |
|
774 // free the node and advance |
|
775 void *next = n->next; |
|
776 cxFree(list->collection.allocator, n); |
|
777 n = next; |
|
778 } |
|
779 } else { |
|
780 char *dest = targetbuf; |
|
781 cx_linked_list_node *n = node; |
|
782 for (size_t i = 0; i < removed; i++) { |
|
783 // copy payload |
|
784 memcpy(dest, n->payload, list->collection.elem_size); |
|
785 |
|
786 // advance target buffer |
|
787 dest += list->collection.elem_size; |
|
788 |
|
789 // free the node and advance |
|
790 void *next = n->next; |
|
791 cxFree(list->collection.allocator, n); |
|
792 n = next; |
|
793 } |
|
794 } |
|
795 |
|
796 return removed; |
760 } |
797 } |
761 |
798 |
762 static void cx_ll_clear(struct cx_list_s *list) { |
799 static void cx_ll_clear(struct cx_list_s *list) { |
763 if (list->collection.size == 0) return; |
800 if (list->collection.size == 0) return; |
764 |
801 |
775 } |
812 } |
776 |
813 |
777 #ifndef CX_LINKED_LIST_SWAP_SBO_SIZE |
814 #ifndef CX_LINKED_LIST_SWAP_SBO_SIZE |
778 #define CX_LINKED_LIST_SWAP_SBO_SIZE 128 |
815 #define CX_LINKED_LIST_SWAP_SBO_SIZE 128 |
779 #endif |
816 #endif |
780 unsigned cx_linked_list_swap_sbo_size = CX_LINKED_LIST_SWAP_SBO_SIZE; |
817 const unsigned cx_linked_list_swap_sbo_size = CX_LINKED_LIST_SWAP_SBO_SIZE; |
781 |
818 |
782 static int cx_ll_swap( |
819 static int cx_ll_swap( |
783 struct cx_list_s *list, |
820 struct cx_list_s *list, |
784 size_t i, |
821 size_t i, |
785 size_t j |
822 size_t j |
796 right = j; |
833 right = j; |
797 } else { |
834 } else { |
798 left = j; |
835 left = j; |
799 right = i; |
836 right = i; |
800 } |
837 } |
801 cx_linked_list_node *nleft, *nright; |
838 cx_linked_list_node *nleft = NULL, *nright = NULL; |
802 if (left < mid && right < mid) { |
839 if (left < mid && right < mid) { |
803 // case 1: both items left from mid |
840 // case 1: both items left from mid |
804 nleft = cx_ll_node_at(ll, left); |
841 nleft = cx_ll_node_at(ll, left); |
805 assert(nleft != NULL); |
842 assert(nleft != NULL); |
806 nright = nleft; |
843 nright = nleft; |