36 |
36 |
37 #define CX_LL_PTR(cur, off) (*(void**)(((char*)(cur))+(off))) |
37 #define CX_LL_PTR(cur, off) (*(void**)(((char*)(cur))+(off))) |
38 #define ll_prev(node) CX_LL_PTR(node, loc_prev) |
38 #define ll_prev(node) CX_LL_PTR(node, loc_prev) |
39 #define ll_next(node) CX_LL_PTR(node, loc_next) |
39 #define ll_next(node) CX_LL_PTR(node, loc_next) |
40 #define ll_advance(node) CX_LL_PTR(node, loc_advance) |
40 #define ll_advance(node) CX_LL_PTR(node, loc_advance) |
41 #define ll_data_f(node, follow_ptr) ((follow_ptr)?CX_LL_PTR(node, loc_data):(((char*)(node))+loc_data)) |
41 #define ll_data(node) (((char*)(node))+loc_data) |
42 #define ll_data(node) ll_data_f(node,follow_ptr) |
|
43 |
42 |
44 void *cx_linked_list_at( |
43 void *cx_linked_list_at( |
45 void const *start, |
44 void const *start, |
46 size_t start_index, |
45 size_t start_index, |
47 ptrdiff_t loc_advance, |
46 ptrdiff_t loc_advance, |
60 |
59 |
61 size_t cx_linked_list_find( |
60 size_t cx_linked_list_find( |
62 void const *start, |
61 void const *start, |
63 ptrdiff_t loc_advance, |
62 ptrdiff_t loc_advance, |
64 ptrdiff_t loc_data, |
63 ptrdiff_t loc_data, |
65 bool follow_ptr, |
|
66 CxListComparator cmp_func, |
64 CxListComparator cmp_func, |
67 void const *elem |
65 void const *elem |
68 ) { |
66 ) { |
69 assert(start != NULL); |
67 assert(start != NULL); |
70 assert(loc_advance >= 0); |
68 assert(loc_advance >= 0); |
376 rn++; |
372 rn++; |
377 } |
373 } |
378 re = ll_next(rc); |
374 re = ll_next(rc); |
379 |
375 |
380 // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them |
376 // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them |
381 void *sorted = cx_linked_list_sort_merge(loc_prev, loc_next, loc_data, follow_ptr, |
377 void *sorted = cx_linked_list_sort_merge(loc_prev, loc_next, loc_data, |
382 ln + rn, ls, le, re, cmp_func); |
378 ln + rn, ls, le, re, cmp_func); |
383 |
379 |
384 // Something left? Sort it! |
380 // Something left? Sort it! |
385 size_t remainder_length = cx_linked_list_size(re, loc_next); |
381 size_t remainder_length = cx_linked_list_size(re, loc_next); |
386 if (remainder_length > 0) { |
382 if (remainder_length > 0) { |
387 void *remainder = re; |
383 void *remainder = re; |
388 cx_linked_list_sort(&remainder, NULL, loc_prev, loc_next, loc_data, follow_ptr, cmp_func); |
384 cx_linked_list_sort(&remainder, NULL, loc_prev, loc_next, loc_data, cmp_func); |
389 |
385 |
390 // merge sorted list with (also sorted) remainder |
386 // merge sorted list with (also sorted) remainder |
391 *begin = cx_linked_list_sort_merge(loc_prev, loc_next, loc_data, follow_ptr, |
387 *begin = cx_linked_list_sort_merge(loc_prev, loc_next, loc_data, |
392 ln + rn + remainder_length, |
388 ln + rn + remainder_length, |
393 sorted, remainder, NULL, cmp_func); |
389 sorted, remainder, NULL, cmp_func); |
394 } else { |
390 } else { |
395 // no remainder - we've got our sorted list |
391 // no remainder - we've got our sorted list |
396 *begin = sorted; |
392 *begin = sorted; |
402 int cx_linked_list_compare( |
398 int cx_linked_list_compare( |
403 void const *begin_left, |
399 void const *begin_left, |
404 void const *begin_right, |
400 void const *begin_right, |
405 ptrdiff_t loc_advance, |
401 ptrdiff_t loc_advance, |
406 ptrdiff_t loc_data, |
402 ptrdiff_t loc_data, |
407 bool follow_ptr_left, |
|
408 bool follow_ptr_right, |
|
409 CxListComparator cmp_func |
403 CxListComparator cmp_func |
410 ) { |
404 ) { |
411 void const *left = begin_left, *right = begin_right; |
405 void const *left = begin_left, *right = begin_right; |
412 |
406 |
413 while (left != NULL && right != NULL) { |
407 while (left != NULL && right != NULL) { |
414 void const *left_data = ll_data_f(left, follow_ptr_left); |
408 void const *left_data = ll_data(left); |
415 void const *right_data = ll_data_f(right, follow_ptr_right); |
409 void const *right_data = ll_data(right); |
416 int result = cmp_func(left_data, right_data); |
410 int result = cmp_func(left_data, right_data); |
417 if (result != 0) return result; |
411 if (result != 0) return result; |
418 left = ll_advance(left); |
412 left = ll_advance(left); |
419 right = ll_advance(right); |
413 right = ll_advance(right); |
420 } |
414 } |
574 size_t n |
567 size_t n |
575 ) { |
568 ) { |
576 return cx_ll_insert_array(list, list->size, array, n); |
569 return cx_ll_insert_array(list, list->size, array, n); |
577 } |
570 } |
578 |
571 |
579 static int cx_pll_insert( |
|
580 struct cx_list_s *list, |
|
581 size_t index, |
|
582 void const *elem |
|
583 ) { |
|
584 return cx_ll_insert(list, index, &elem); |
|
585 } |
|
586 |
|
587 static int cx_pll_add( |
|
588 struct cx_list_s *list, |
|
589 void const *elem |
|
590 ) { |
|
591 return cx_ll_insert(list, list->size, &elem); |
|
592 } |
|
593 |
|
594 static int cx_ll_remove( |
572 static int cx_ll_remove( |
595 struct cx_list_s *list, |
573 struct cx_list_s *list, |
596 size_t index |
574 size_t index |
597 ) { |
575 ) { |
598 cx_linked_list *ll = (cx_linked_list *) list; |
576 cx_linked_list *ll = (cx_linked_list *) list; |
621 cx_linked_list *ll = (cx_linked_list *) list; |
599 cx_linked_list *ll = (cx_linked_list *) list; |
622 cx_linked_list_node *node = cx_ll_node_at(ll, index); |
600 cx_linked_list_node *node = cx_ll_node_at(ll, index); |
623 return node == NULL ? NULL : node->payload; |
601 return node == NULL ? NULL : node->payload; |
624 } |
602 } |
625 |
603 |
626 static void *cx_pll_at( |
|
627 struct cx_list_s const *list, |
|
628 size_t index |
|
629 ) { |
|
630 cx_linked_list *ll = (cx_linked_list *) list; |
|
631 cx_linked_list_node *node = cx_ll_node_at(ll, index); |
|
632 return node == NULL ? NULL : *(void **) node->payload; |
|
633 } |
|
634 |
|
635 static size_t cx_ll_find( |
604 static size_t cx_ll_find( |
636 struct cx_list_s const *list, |
605 struct cx_list_s const *list, |
637 void const *elem |
606 void const *elem |
638 ) { |
607 ) { |
639 cx_linked_list *ll = (cx_linked_list *) list; |
|
640 return cx_linked_list_find(((cx_linked_list *) list)->begin, |
608 return cx_linked_list_find(((cx_linked_list *) list)->begin, |
641 CX_LL_LOC_NEXT, CX_LL_LOC_DATA, |
609 CX_LL_LOC_NEXT, CX_LL_LOC_DATA, |
642 ll->follow_ptr, list->cmpfunc, elem); |
610 list->cmpfunc, elem); |
643 } |
611 } |
644 |
612 |
645 static void cx_ll_sort(struct cx_list_s *list) { |
613 static void cx_ll_sort(struct cx_list_s *list) { |
646 cx_linked_list *ll = (cx_linked_list *) list; |
614 cx_linked_list *ll = (cx_linked_list *) list; |
647 cx_linked_list_sort((void **) &ll->begin, (void **) &ll->end, |
615 cx_linked_list_sort((void **) &ll->begin, (void **) &ll->end, |
648 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, CX_LL_LOC_DATA, |
616 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, CX_LL_LOC_DATA, |
649 ll->follow_ptr, list->cmpfunc); |
617 list->cmpfunc); |
650 } |
618 } |
651 |
619 |
652 static void cx_ll_reverse(struct cx_list_s *list) { |
620 static void cx_ll_reverse(struct cx_list_s *list) { |
653 cx_linked_list *ll = (cx_linked_list *) list; |
621 cx_linked_list *ll = (cx_linked_list *) list; |
654 cx_linked_list_reverse((void **) &ll->begin, (void **) &ll->end, CX_LL_LOC_PREV, CX_LL_LOC_NEXT); |
622 cx_linked_list_reverse((void **) &ll->begin, (void **) &ll->end, CX_LL_LOC_PREV, CX_LL_LOC_NEXT); |
660 ) { |
628 ) { |
661 cx_linked_list *left = (cx_linked_list *) list; |
629 cx_linked_list *left = (cx_linked_list *) list; |
662 cx_linked_list *right = (cx_linked_list *) other; |
630 cx_linked_list *right = (cx_linked_list *) other; |
663 return cx_linked_list_compare(left->begin, right->begin, |
631 return cx_linked_list_compare(left->begin, right->begin, |
664 CX_LL_LOC_NEXT, CX_LL_LOC_DATA, |
632 CX_LL_LOC_NEXT, CX_LL_LOC_DATA, |
665 left->follow_ptr, right->follow_ptr, list->cmpfunc); |
633 list->cmpfunc); |
666 } |
634 } |
667 |
635 |
668 static bool cx_ll_iter_valid(void const *it) { |
636 static bool cx_ll_iter_valid(void const *it) { |
669 struct cx_iterator_s const *iter = it; |
637 struct cx_iterator_s const *iter = it; |
670 return iter->elem_handle != NULL; |
638 return iter->elem_handle != NULL; |
694 struct cx_iterator_s const *iter = it; |
662 struct cx_iterator_s const *iter = it; |
695 cx_linked_list_node *node = iter->elem_handle; |
663 cx_linked_list_node *node = iter->elem_handle; |
696 return node->payload; |
664 return node->payload; |
697 } |
665 } |
698 |
666 |
699 static void *cx_pll_iter_current(void const *it) { |
|
700 struct cx_iterator_s const *iter = it; |
|
701 cx_linked_list_node *node = iter->elem_handle; |
|
702 return *(void **) node->payload; |
|
703 } |
|
704 |
|
705 static bool cx_ll_iter_flag_rm(void *it) { |
667 static bool cx_ll_iter_flag_rm(void *it) { |
706 struct cx_iterator_base_s *iter = it; |
668 struct cx_iterator_base_s *iter = it; |
707 if (iter->mutating) { |
669 if (iter->mutating) { |
708 iter->remove = true; |
670 iter->remove = true; |
709 return true; |
671 return true; |
727 iter.base.mutating = false; |
689 iter.base.mutating = false; |
728 iter.base.remove = false; |
690 iter.base.remove = false; |
729 return iter; |
691 return iter; |
730 } |
692 } |
731 |
693 |
732 static CxIterator cx_pll_iterator( |
|
733 struct cx_list_s const *list, |
|
734 size_t index |
|
735 ) { |
|
736 CxIterator iter = cx_ll_iterator(list, index); |
|
737 iter.base.current = cx_pll_iter_current; |
|
738 return iter; |
|
739 } |
|
740 |
|
741 static CxMutIterator cx_ll_mut_iterator( |
694 static CxMutIterator cx_ll_mut_iterator( |
742 struct cx_list_s *list, |
695 struct cx_list_s *list, |
743 size_t index |
696 size_t index |
744 ) { |
697 ) { |
745 CxIterator it = cx_ll_iterator(list, index); |
698 CxIterator it = cx_ll_iterator(list, index); |
746 it.base.mutating = true; |
699 it.base.mutating = true; |
747 |
700 |
748 // we know the iterators share the same memory layout |
701 // we know the iterators share the same memory layout |
749 CxMutIterator iter; |
702 CxMutIterator iter; |
750 memcpy(&iter, &it, sizeof(CxMutIterator)); |
703 memcpy(&iter, &it, sizeof(CxMutIterator)); |
751 return iter; |
|
752 } |
|
753 |
|
754 static CxMutIterator cx_pll_mut_iterator( |
|
755 struct cx_list_s *list, |
|
756 size_t index |
|
757 ) { |
|
758 CxMutIterator iter = cx_ll_mut_iterator(list, index); |
|
759 iter.base.current = cx_pll_iter_current; |
|
760 return iter; |
704 return iter; |
761 } |
705 } |
762 |
706 |
763 static int cx_ll_insert_iter( |
707 static int cx_ll_insert_iter( |
764 CxMutIterator *iter, |
708 CxMutIterator *iter, |
776 } else { |
720 } else { |
777 int result = cx_ll_insert(list, list->size, elem); |
721 int result = cx_ll_insert(list, list->size, elem); |
778 iter->index = list->size; |
722 iter->index = list->size; |
779 return result; |
723 return result; |
780 } |
724 } |
781 } |
|
782 |
|
783 static int cx_pll_insert_iter( |
|
784 CxMutIterator *iter, |
|
785 void const *elem, |
|
786 int prepend |
|
787 ) { |
|
788 return cx_ll_insert_iter(iter, &elem, prepend); |
|
789 } |
725 } |
790 |
726 |
791 static void cx_ll_destructor(CxList *list) { |
727 static void cx_ll_destructor(CxList *list) { |
792 cx_linked_list *ll = (cx_linked_list *) list; |
728 cx_linked_list *ll = (cx_linked_list *) list; |
793 |
729 |
815 cx_ll_reverse, |
751 cx_ll_reverse, |
816 cx_ll_iterator, |
752 cx_ll_iterator, |
817 cx_ll_mut_iterator, |
753 cx_ll_mut_iterator, |
818 }; |
754 }; |
819 |
755 |
820 static cx_list_class cx_pointer_linked_list_class = { |
|
821 cx_ll_destructor, |
|
822 cx_pll_add, |
|
823 cx_ll_add_array, |
|
824 cx_pll_insert, |
|
825 cx_ll_insert_array, |
|
826 cx_pll_insert_iter, |
|
827 cx_ll_remove, |
|
828 cx_pll_at, |
|
829 cx_ll_find, |
|
830 cx_ll_sort, |
|
831 cx_ll_compare, |
|
832 cx_ll_reverse, |
|
833 cx_pll_iterator, |
|
834 cx_pll_mut_iterator, |
|
835 }; |
|
836 |
|
837 CxList *cxLinkedListCreate( |
756 CxList *cxLinkedListCreate( |
838 CxAllocator const *allocator, |
757 CxAllocator const *allocator, |
839 CxListComparator comparator, |
758 CxListComparator comparator, |
840 size_t item_size |
759 size_t item_size |
841 ) { |
760 ) { |
842 cx_linked_list *list = cxCalloc(allocator, 1, sizeof(cx_linked_list)); |
761 cx_linked_list *list = cxCalloc(allocator, 1, sizeof(cx_linked_list)); |
843 if (list == NULL) return NULL; |
762 if (list == NULL) return NULL; |
844 |
763 |
845 list->follow_ptr = false; |
|
846 list->base.cl = &cx_linked_list_class; |
764 list->base.cl = &cx_linked_list_class; |
847 list->base.allocator = allocator; |
765 list->base.allocator = allocator; |
848 list->base.cmpfunc = comparator; |
766 list->base.cmpfunc = comparator; |
849 list->base.itemsize = item_size; |
767 list->base.itemsize = item_size; |
850 list->base.capacity = SIZE_MAX; |
768 list->base.capacity = SIZE_MAX; |
851 |
769 |
852 return (CxList *) list; |
770 return (CxList *) list; |
853 } |
771 } |
854 |
|
855 CxList *cxPointerLinkedListCreate( |
|
856 CxAllocator const *allocator, |
|
857 CxListComparator comparator |
|
858 ) { |
|
859 cx_linked_list *list = cxCalloc(allocator, 1, sizeof(cx_linked_list)); |
|
860 if (list == NULL) return NULL; |
|
861 |
|
862 list->follow_ptr = true; |
|
863 list->base.cl = &cx_pointer_linked_list_class; |
|
864 list->base.allocator = allocator; |
|
865 list->base.cmpfunc = comparator; |
|
866 list->base.itemsize = sizeof(void *); |
|
867 list->base.capacity = SIZE_MAX; |
|
868 |
|
869 return (CxList *) list; |
|
870 } |
|