58 |
58 |
59 size_t cx_linked_list_find( |
59 size_t cx_linked_list_find( |
60 void const *start, |
60 void const *start, |
61 ptrdiff_t loc_advance, |
61 ptrdiff_t loc_advance, |
62 ptrdiff_t loc_data, |
62 ptrdiff_t loc_data, |
63 CxListComparator cmp_func, |
63 cx_compare_func cmp_func, |
64 void const *elem |
64 void const *elem |
65 ) { |
65 ) { |
66 assert(start != NULL); |
66 assert(start != NULL); |
67 assert(loc_advance >= 0); |
67 assert(loc_advance >= 0); |
68 assert(loc_data >= 0); |
68 assert(loc_data >= 0); |
289 ptrdiff_t loc_data, |
289 ptrdiff_t loc_data, |
290 size_t length, |
290 size_t length, |
291 void *ls, |
291 void *ls, |
292 void *le, |
292 void *le, |
293 void *re, |
293 void *re, |
294 CxListComparator cmp_func |
294 cx_compare_func cmp_func |
295 ) { |
295 ) { |
296 void *sbo[CX_LINKED_LIST_SORT_SBO_SIZE]; |
296 void *sbo[CX_LINKED_LIST_SORT_SBO_SIZE]; |
297 void **sorted = length >= CX_LINKED_LIST_SORT_SBO_SIZE ? |
297 void **sorted = length >= CX_LINKED_LIST_SORT_SBO_SIZE ? |
298 malloc(sizeof(void *) * length) : sbo; |
298 malloc(sizeof(void *) * length) : sbo; |
299 if (sorted == NULL) abort(); |
299 if (sorted == NULL) abort(); |
401 int cx_linked_list_compare( |
401 int cx_linked_list_compare( |
402 void const *begin_left, |
402 void const *begin_left, |
403 void const *begin_right, |
403 void const *begin_right, |
404 ptrdiff_t loc_advance, |
404 ptrdiff_t loc_advance, |
405 ptrdiff_t loc_data, |
405 ptrdiff_t loc_data, |
406 CxListComparator cmp_func |
406 cx_compare_func cmp_func |
407 ) { |
407 ) { |
408 void const *left = begin_left, *right = begin_right; |
408 void const *left = begin_left, *right = begin_right; |
409 |
409 |
410 while (left != NULL && right != NULL) { |
410 while (left != NULL && right != NULL) { |
411 void const *left_data = ll_data(left); |
411 void const *left_data = ll_data(left); |
492 void const *elem |
492 void const *elem |
493 ) { |
493 ) { |
494 |
494 |
495 // create the new new_node |
495 // create the new new_node |
496 cx_linked_list_node *new_node = cxMalloc(list->allocator, |
496 cx_linked_list_node *new_node = cxMalloc(list->allocator, |
497 sizeof(cx_linked_list_node) + list->itemsize); |
497 sizeof(cx_linked_list_node) + list->item_size); |
498 |
498 |
499 // sortir if failed |
499 // sortir if failed |
500 if (new_node == NULL) return 1; |
500 if (new_node == NULL) return 1; |
501 |
501 |
502 // initialize new new_node |
502 // initialize new new_node |
503 new_node->prev = new_node->next = NULL; |
503 new_node->prev = new_node->next = NULL; |
504 memcpy(new_node->payload, elem, list->itemsize); |
504 memcpy(new_node->payload, elem, list->item_size); |
505 |
505 |
506 // insert |
506 // insert |
507 cx_linked_list *ll = (cx_linked_list *) list; |
507 cx_linked_list *ll = (cx_linked_list *) list; |
508 cx_linked_list_insert_chain( |
508 cx_linked_list_insert_chain( |
509 (void **) &ll->begin, (void **) &ll->end, |
509 (void **) &ll->begin, (void **) &ll->end, |
540 node = node == NULL ? ((cx_linked_list *) list)->begin : node->next; |
540 node = node == NULL ? ((cx_linked_list *) list)->begin : node->next; |
541 |
541 |
542 // we can add the remaining nodes and immedately advance to the inserted node |
542 // we can add the remaining nodes and immedately advance to the inserted node |
543 char const *source = array; |
543 char const *source = array; |
544 for (size_t i = 1; i < n; i++) { |
544 for (size_t i = 1; i < n; i++) { |
545 source += list->itemsize; |
545 source += list->item_size; |
546 if (0 != cx_ll_insert_at(list, node, source)) { |
546 if (0 != cx_ll_insert_at(list, node, source)) { |
547 return i; |
547 return i; |
548 } |
548 } |
549 node = node->next; |
549 node = node->next; |
550 } |
550 } |
568 |
568 |
569 // out-of-bounds check |
569 // out-of-bounds check |
570 if (node == NULL) return 1; |
570 if (node == NULL) return 1; |
571 |
571 |
572 // element destruction |
572 // element destruction |
573 if (list->content_destructor_type != CX_DESTRUCTOR_NONE) { |
573 cx_invoke_destructor(list, node->payload); |
574 cx_list_invoke_destructor(list, node->payload); |
|
575 } |
|
576 |
574 |
577 // remove |
575 // remove |
578 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, |
576 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, |
579 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); |
577 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); |
580 |
578 |
590 static void cx_ll_clear(struct cx_list_s *list) { |
588 static void cx_ll_clear(struct cx_list_s *list) { |
591 if (list->size == 0) return; |
589 if (list->size == 0) return; |
592 |
590 |
593 cx_linked_list *ll = (cx_linked_list *) list; |
591 cx_linked_list *ll = (cx_linked_list *) list; |
594 cx_linked_list_node *node = ll->begin; |
592 cx_linked_list_node *node = ll->begin; |
595 |
593 while (node != NULL) { |
596 // looks super redundant, but avoids repeatedly checking |
594 cx_invoke_destructor(list, node->payload); |
597 // the destructor type for each element |
595 cx_linked_list_node *next = node->next; |
598 switch (list->content_destructor_type) { |
596 cxFree(list->allocator, node); |
599 case CX_DESTRUCTOR_SIMPLE: { |
597 node = next; |
600 while (node != NULL) { |
598 } |
601 cx_list_invoke_simple_destructor(list, node->payload); |
|
602 cx_linked_list_node *next = node->next; |
|
603 cxFree(list->allocator, node); |
|
604 node = next; |
|
605 } |
|
606 break; |
|
607 } |
|
608 case CX_DESTRUCTOR_ADVANCED: { |
|
609 while (node != NULL) { |
|
610 cx_list_invoke_advanced_destructor(list, node->payload); |
|
611 cx_linked_list_node *next = node->next; |
|
612 cxFree(list->allocator, node); |
|
613 node = next; |
|
614 } |
|
615 break; |
|
616 } |
|
617 case CX_DESTRUCTOR_NONE: { |
|
618 while (node != NULL) { |
|
619 cx_linked_list_node *next = node->next; |
|
620 cxFree(list->allocator, node); |
|
621 node = next; |
|
622 } |
|
623 break; |
|
624 } |
|
625 } |
|
626 |
|
627 ll->begin = ll->end = NULL; |
599 ll->begin = ll->end = NULL; |
628 list->size = 0; |
600 list->size = 0; |
629 } |
601 } |
630 |
602 |
631 #ifndef CX_LINKED_LIST_SWAP_SBO_SIZE |
603 #ifndef CX_LINKED_LIST_SWAP_SBO_SIZE |
706 nleft = cx_ll_node_at(ll, other); |
678 nleft = cx_ll_node_at(ll, other); |
707 } |
679 } |
708 } |
680 } |
709 } |
681 } |
710 |
682 |
711 if (list->itemsize > CX_LINKED_LIST_SWAP_SBO_SIZE || CX_DISABLE_LINKED_LIST_SWAP_SBO) { |
683 if (list->item_size > CX_LINKED_LIST_SWAP_SBO_SIZE || CX_DISABLE_LINKED_LIST_SWAP_SBO) { |
712 cx_linked_list_node *prev = nleft->prev; |
684 cx_linked_list_node *prev = nleft->prev; |
713 cx_linked_list_node *next = nright->next; |
685 cx_linked_list_node *next = nright->next; |
714 cx_linked_list_node *midstart = nleft->next; |
686 cx_linked_list_node *midstart = nleft->next; |
715 cx_linked_list_node *midend = nright->prev; |
687 cx_linked_list_node *midend = nright->prev; |
716 |
688 |
738 next->prev = nleft; |
710 next->prev = nleft; |
739 } |
711 } |
740 } else { |
712 } else { |
741 // swap payloads to avoid relinking |
713 // swap payloads to avoid relinking |
742 char buf[CX_LINKED_LIST_SWAP_SBO_SIZE]; |
714 char buf[CX_LINKED_LIST_SWAP_SBO_SIZE]; |
743 memcpy(buf, nleft->payload, list->itemsize); |
715 memcpy(buf, nleft->payload, list->item_size); |
744 memcpy(nleft->payload, nright->payload, list->itemsize); |
716 memcpy(nleft->payload, nright->payload, list->item_size); |
745 memcpy(nright->payload, buf, list->itemsize); |
717 memcpy(nright->payload, buf, list->item_size); |
746 } |
718 } |
747 |
719 |
748 return 0; |
720 return 0; |
749 } |
721 } |
750 |
722 |
801 struct cx_mut_iterator_s *iter = it; |
773 struct cx_mut_iterator_s *iter = it; |
802 struct cx_list_s *list = iter->src_handle; |
774 struct cx_list_s *list = iter->src_handle; |
803 cx_linked_list *ll = iter->src_handle; |
775 cx_linked_list *ll = iter->src_handle; |
804 cx_linked_list_node *node = iter->elem_handle; |
776 cx_linked_list_node *node = iter->elem_handle; |
805 iter->elem_handle = node->next; |
777 iter->elem_handle = node->next; |
806 if (list->content_destructor_type != CX_DESTRUCTOR_NONE) { |
778 cx_invoke_destructor(list, node->payload); |
807 cx_list_invoke_destructor(list, node->payload); |
|
808 } |
|
809 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, |
779 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, |
810 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); |
780 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); |
811 list->size--; |
781 list->size--; |
812 cxFree(list->allocator, node); |
782 cxFree(list->allocator, node); |
813 } else { |
783 } else { |
826 struct cx_list_s *list = iter->src_handle; |
796 struct cx_list_s *list = iter->src_handle; |
827 cx_linked_list *ll = iter->src_handle; |
797 cx_linked_list *ll = iter->src_handle; |
828 cx_linked_list_node *node = iter->elem_handle; |
798 cx_linked_list_node *node = iter->elem_handle; |
829 iter->elem_handle = node->prev; |
799 iter->elem_handle = node->prev; |
830 iter->index--; |
800 iter->index--; |
831 if (list->content_destructor_type != CX_DESTRUCTOR_NONE) { |
801 cx_invoke_destructor(list, node->payload); |
832 cx_list_invoke_destructor(list, node->payload); |
|
833 } |
|
834 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, |
802 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, |
835 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); |
803 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); |
836 list->size--; |
804 list->size--; |
837 cxFree(list->allocator, node); |
805 cxFree(list->allocator, node); |
838 } else { |
806 } else { |
925 cx_ll_iterator, |
893 cx_ll_iterator, |
926 }; |
894 }; |
927 |
895 |
928 CxList *cxLinkedListCreate( |
896 CxList *cxLinkedListCreate( |
929 CxAllocator const *allocator, |
897 CxAllocator const *allocator, |
930 CxListComparator comparator, |
898 cx_compare_func comparator, |
931 size_t item_size |
899 size_t item_size |
932 ) { |
900 ) { |
933 if (allocator == NULL) { |
901 if (allocator == NULL) { |
934 allocator = cxDefaultAllocator; |
902 allocator = cxDefaultAllocator; |
935 } |
903 } |
938 if (list == NULL) return NULL; |
906 if (list == NULL) return NULL; |
939 |
907 |
940 list->base.cl = &cx_linked_list_class; |
908 list->base.cl = &cx_linked_list_class; |
941 list->base.allocator = allocator; |
909 list->base.allocator = allocator; |
942 list->base.cmpfunc = comparator; |
910 list->base.cmpfunc = comparator; |
943 list->base.capacity = SIZE_MAX; |
|
944 |
911 |
945 if (item_size > 0) { |
912 if (item_size > 0) { |
946 list->base.itemsize = item_size; |
913 list->base.item_size = item_size; |
947 } else { |
914 } else { |
948 cxListStorePointers((CxList *) list); |
915 cxListStorePointers((CxList *) list); |
949 } |
916 } |
950 |
917 |
951 return (CxList *) list; |
918 return (CxList *) list; |