245 } else { |
245 } else { |
246 cx_linked_list_link(insert_end, successor, loc_prev, loc_next); |
246 cx_linked_list_link(insert_end, successor, loc_prev, loc_next); |
247 } |
247 } |
248 } |
248 } |
249 |
249 |
|
250 void cx_linked_list_insert_sorted( |
|
251 void **begin, |
|
252 void **end, |
|
253 ptrdiff_t loc_prev, |
|
254 ptrdiff_t loc_next, |
|
255 void *new_node, |
|
256 cx_compare_func cmp_func |
|
257 ) { |
|
258 assert(ll_next(new_node) == NULL); |
|
259 cx_linked_list_insert_sorted_chain( |
|
260 begin, end, loc_prev, loc_next, new_node, cmp_func); |
|
261 } |
|
262 |
|
263 void cx_linked_list_insert_sorted_chain( |
|
264 void **begin, |
|
265 void **end, |
|
266 ptrdiff_t loc_prev, |
|
267 ptrdiff_t loc_next, |
|
268 void *insert_begin, |
|
269 cx_compare_func cmp_func |
|
270 ) { |
|
271 assert(begin != NULL); |
|
272 assert(loc_next >= 0); |
|
273 assert(insert_begin != NULL); |
|
274 |
|
275 // track currently observed nodes |
|
276 void *dest_prev = NULL; |
|
277 void *dest = *begin; |
|
278 void *src = insert_begin; |
|
279 |
|
280 // special case: list is empty |
|
281 if (dest == NULL) { |
|
282 *begin = src; |
|
283 if (end != NULL) { |
|
284 *end = cx_linked_list_last(src, loc_next); |
|
285 } |
|
286 return; |
|
287 } |
|
288 |
|
289 // search the list for insertion points |
|
290 while (dest != NULL && src != NULL) { |
|
291 // compare current list node with source node |
|
292 // if less or equal, skip |
|
293 if (cmp_func(dest, src) <= 0) { |
|
294 dest_prev = dest; |
|
295 dest = ll_next(dest); |
|
296 continue; |
|
297 } |
|
298 |
|
299 // determine chain of elements that can be inserted |
|
300 void *end_of_chain = src; |
|
301 void *next_in_chain = ll_next(src); |
|
302 while (next_in_chain != NULL) { |
|
303 // once we become larger than the list elem, break |
|
304 if (cmp_func(dest, next_in_chain) <= 0) { |
|
305 break; |
|
306 } |
|
307 // otherwise, we can insert one more |
|
308 end_of_chain = next_in_chain; |
|
309 next_in_chain = ll_next(next_in_chain); |
|
310 } |
|
311 |
|
312 // insert the elements |
|
313 if (dest_prev == NULL) { |
|
314 // new begin |
|
315 *begin = src; |
|
316 } else { |
|
317 cx_linked_list_link(dest_prev, src, loc_prev, loc_next); |
|
318 } |
|
319 cx_linked_list_link(end_of_chain, dest, loc_prev, loc_next); |
|
320 |
|
321 // continue with next |
|
322 src = next_in_chain; |
|
323 dest_prev = dest; |
|
324 dest = ll_next(dest); |
|
325 } |
|
326 |
|
327 // insert remaining items |
|
328 if (src != NULL) { |
|
329 cx_linked_list_link(dest_prev, src, loc_prev, loc_next); |
|
330 } |
|
331 |
|
332 // determine new end of list, if requested |
|
333 if (end != NULL) { |
|
334 *end = cx_linked_list_last( |
|
335 dest != NULL ? dest : dest_prev, loc_next); |
|
336 } |
|
337 } |
|
338 |
250 void cx_linked_list_remove( |
339 void cx_linked_list_remove( |
251 void **begin, |
340 void **begin, |
252 void **end, |
341 void **end, |
253 ptrdiff_t loc_prev, |
342 ptrdiff_t loc_prev, |
254 ptrdiff_t loc_next, |
343 ptrdiff_t loc_next, |
496 cx_linked_list_node *begin; |
585 cx_linked_list_node *begin; |
497 cx_linked_list_node *end; |
586 cx_linked_list_node *end; |
498 } cx_linked_list; |
587 } cx_linked_list; |
499 |
588 |
500 static cx_linked_list_node *cx_ll_node_at( |
589 static cx_linked_list_node *cx_ll_node_at( |
501 cx_linked_list const *list, |
590 const cx_linked_list *list, |
502 size_t index |
591 size_t index |
503 ) { |
592 ) { |
504 if (index >= list->base.size) { |
593 if (index >= list->base.collection.size) { |
505 return NULL; |
594 return NULL; |
506 } else if (index > list->base.size / 2) { |
595 } else if (index > list->base.collection.size / 2) { |
507 return cx_linked_list_at(list->end, list->base.size - 1, CX_LL_LOC_PREV, index); |
596 return cx_linked_list_at(list->end, list->base.collection.size - 1, CX_LL_LOC_PREV, index); |
508 } else { |
597 } else { |
509 return cx_linked_list_at(list->begin, 0, CX_LL_LOC_NEXT, index); |
598 return cx_linked_list_at(list->begin, 0, CX_LL_LOC_NEXT, index); |
510 } |
599 } |
|
600 } |
|
601 |
|
602 static cx_linked_list_node *cx_ll_malloc_node(const struct cx_list_s *list) { |
|
603 return cxMalloc(list->collection.allocator, |
|
604 sizeof(cx_linked_list_node) + list->collection.elem_size); |
511 } |
605 } |
512 |
606 |
513 static int cx_ll_insert_at( |
607 static int cx_ll_insert_at( |
514 struct cx_list_s *list, |
608 struct cx_list_s *list, |
515 cx_linked_list_node *node, |
609 cx_linked_list_node *node, |
516 void const *elem |
610 const void *elem |
517 ) { |
611 ) { |
518 |
612 |
519 // create the new new_node |
613 // create the new new_node |
520 cx_linked_list_node *new_node = cxMalloc(list->allocator, |
614 cx_linked_list_node *new_node = cx_ll_malloc_node(list); |
521 sizeof(cx_linked_list_node) + list->item_size); |
|
522 |
615 |
523 // sortir if failed |
616 // sortir if failed |
524 if (new_node == NULL) return 1; |
617 if (new_node == NULL) return 1; |
525 |
618 |
526 // initialize new new_node |
619 // initialize new new_node |
527 new_node->prev = new_node->next = NULL; |
620 new_node->prev = new_node->next = NULL; |
528 memcpy(new_node->payload, elem, list->item_size); |
621 memcpy(new_node->payload, elem, list->collection.elem_size); |
529 |
622 |
530 // insert |
623 // insert |
531 cx_linked_list *ll = (cx_linked_list *) list; |
624 cx_linked_list *ll = (cx_linked_list *) list; |
532 cx_linked_list_insert_chain( |
625 cx_linked_list_insert_chain( |
533 (void **) &ll->begin, (void **) &ll->end, |
626 (void **) &ll->begin, (void **) &ll->end, |
534 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, |
627 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, |
535 node, new_node, new_node |
628 node, new_node, new_node |
536 ); |
629 ); |
537 |
630 |
538 // increase the size and return |
631 // increase the size and return |
539 list->size++; |
632 list->collection.size++; |
540 return 0; |
633 return 0; |
541 } |
634 } |
542 |
635 |
543 static size_t cx_ll_insert_array( |
636 static size_t cx_ll_insert_array( |
544 struct cx_list_s *list, |
637 struct cx_list_s *list, |
545 size_t index, |
638 size_t index, |
546 void const *array, |
639 const void *array, |
547 size_t n |
640 size_t n |
548 ) { |
641 ) { |
549 // out-of bounds and corner case check |
642 // out-of bounds and corner case check |
550 if (index > list->size || n == 0) return 0; |
643 if (index > list->collection.size || n == 0) return 0; |
551 |
644 |
552 // find position efficiently |
645 // find position efficiently |
553 cx_linked_list_node *node = index == 0 ? NULL : cx_ll_node_at((cx_linked_list *) list, index - 1); |
646 cx_linked_list_node *node = index == 0 ? NULL : cx_ll_node_at((cx_linked_list *) list, index - 1); |
554 |
647 |
555 // perform first insert |
648 // perform first insert |
737 next->prev = nleft; |
887 next->prev = nleft; |
738 } |
888 } |
739 } else { |
889 } else { |
740 // swap payloads to avoid relinking |
890 // swap payloads to avoid relinking |
741 char buf[CX_LINKED_LIST_SWAP_SBO_SIZE]; |
891 char buf[CX_LINKED_LIST_SWAP_SBO_SIZE]; |
742 memcpy(buf, nleft->payload, list->item_size); |
892 memcpy(buf, nleft->payload, list->collection.elem_size); |
743 memcpy(nleft->payload, nright->payload, list->item_size); |
893 memcpy(nleft->payload, nright->payload, list->collection.elem_size); |
744 memcpy(nright->payload, buf, list->item_size); |
894 memcpy(nright->payload, buf, list->collection.elem_size); |
745 } |
895 } |
746 |
896 |
747 return 0; |
897 return 0; |
748 } |
898 } |
749 |
899 |
750 static void *cx_ll_at( |
900 static void *cx_ll_at( |
751 struct cx_list_s const *list, |
901 const struct cx_list_s *list, |
752 size_t index |
902 size_t index |
753 ) { |
903 ) { |
754 cx_linked_list *ll = (cx_linked_list *) list; |
904 cx_linked_list *ll = (cx_linked_list *) list; |
755 cx_linked_list_node *node = cx_ll_node_at(ll, index); |
905 cx_linked_list_node *node = cx_ll_node_at(ll, index); |
756 return node == NULL ? NULL : node->payload; |
906 return node == NULL ? NULL : node->payload; |
757 } |
907 } |
758 |
908 |
759 static ssize_t cx_ll_find_remove( |
909 static ssize_t cx_ll_find_remove( |
760 struct cx_list_s *list, |
910 struct cx_list_s *list, |
761 void const *elem, |
911 const void *elem, |
762 bool remove |
912 bool remove |
763 ) { |
913 ) { |
764 if (remove) { |
914 if (remove) { |
765 cx_linked_list *ll = ((cx_linked_list *) list); |
915 cx_linked_list *ll = ((cx_linked_list *) list); |
766 cx_linked_list_node *node; |
916 cx_linked_list_node *node; |
767 ssize_t index = cx_linked_list_find_node( |
917 ssize_t index = cx_linked_list_find_node( |
768 (void **) &node, |
918 (void **) &node, |
769 ll->begin, |
919 ll->begin, |
770 CX_LL_LOC_NEXT, CX_LL_LOC_DATA, |
920 CX_LL_LOC_NEXT, CX_LL_LOC_DATA, |
771 list->cmpfunc, elem |
921 list->collection.cmpfunc, elem |
772 ); |
922 ); |
773 if (node != NULL) { |
923 if (node != NULL) { |
774 cx_invoke_destructor(list, node->payload); |
924 cx_invoke_destructor(list, node->payload); |
775 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, |
925 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, |
776 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); |
926 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); |
777 list->size--; |
927 list->collection.size--; |
778 cxFree(list->allocator, node); |
928 cxFree(list->collection.allocator, node); |
779 } |
929 } |
780 return index; |
930 return index; |
781 } else { |
931 } else { |
782 return cx_linked_list_find( |
932 return cx_linked_list_find( |
783 ((cx_linked_list *) list)->begin, |
933 ((cx_linked_list *) list)->begin, |
784 CX_LL_LOC_NEXT, CX_LL_LOC_DATA, |
934 CX_LL_LOC_NEXT, CX_LL_LOC_DATA, |
785 list->cmpfunc, elem |
935 list->collection.cmpfunc, elem |
786 ); |
936 ); |
787 } |
937 } |
788 } |
938 } |
789 |
939 |
790 static void cx_ll_sort(struct cx_list_s *list) { |
940 static void cx_ll_sort(struct cx_list_s *list) { |
791 cx_linked_list *ll = (cx_linked_list *) list; |
941 cx_linked_list *ll = (cx_linked_list *) list; |
792 cx_linked_list_sort((void **) &ll->begin, (void **) &ll->end, |
942 cx_linked_list_sort((void **) &ll->begin, (void **) &ll->end, |
793 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, CX_LL_LOC_DATA, |
943 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, CX_LL_LOC_DATA, |
794 list->cmpfunc); |
944 list->collection.cmpfunc); |
795 } |
945 } |
796 |
946 |
797 static void cx_ll_reverse(struct cx_list_s *list) { |
947 static void cx_ll_reverse(struct cx_list_s *list) { |
798 cx_linked_list *ll = (cx_linked_list *) list; |
948 cx_linked_list *ll = (cx_linked_list *) list; |
799 cx_linked_list_reverse((void **) &ll->begin, (void **) &ll->end, CX_LL_LOC_PREV, CX_LL_LOC_NEXT); |
949 cx_linked_list_reverse((void **) &ll->begin, (void **) &ll->end, CX_LL_LOC_PREV, CX_LL_LOC_NEXT); |
800 } |
950 } |
801 |
951 |
802 static int cx_ll_compare( |
952 static int cx_ll_compare( |
803 struct cx_list_s const *list, |
953 const struct cx_list_s *list, |
804 struct cx_list_s const *other |
954 const struct cx_list_s *other |
805 ) { |
955 ) { |
806 cx_linked_list *left = (cx_linked_list *) list; |
956 cx_linked_list *left = (cx_linked_list *) list; |
807 cx_linked_list *right = (cx_linked_list *) other; |
957 cx_linked_list *right = (cx_linked_list *) other; |
808 return cx_linked_list_compare(left->begin, right->begin, |
958 return cx_linked_list_compare(left->begin, right->begin, |
809 CX_LL_LOC_NEXT, CX_LL_LOC_DATA, |
959 CX_LL_LOC_NEXT, CX_LL_LOC_DATA, |
810 list->cmpfunc); |
960 list->collection.cmpfunc); |
811 } |
961 } |
812 |
962 |
813 static bool cx_ll_iter_valid(void const *it) { |
963 static bool cx_ll_iter_valid(const void *it) { |
814 struct cx_iterator_s const *iter = it; |
964 const struct cx_iterator_s *iter = it; |
815 return iter->elem_handle != NULL; |
965 return iter->elem_handle != NULL; |
816 } |
966 } |
817 |
967 |
818 static void cx_ll_iter_next(void *it) { |
968 static void cx_ll_iter_next(void *it) { |
819 struct cx_iterator_base_s *itbase = it; |
969 struct cx_iterator_s *iter = it; |
820 if (itbase->remove) { |
970 if (iter->base.remove) { |
821 itbase->remove = false; |
971 iter->base.remove = false; |
822 struct cx_mut_iterator_s *iter = it; |
972 struct cx_list_s *list = iter->src_handle.m; |
823 struct cx_list_s *list = iter->src_handle; |
973 cx_linked_list *ll = iter->src_handle.m; |
824 cx_linked_list *ll = iter->src_handle; |
|
825 cx_linked_list_node *node = iter->elem_handle; |
974 cx_linked_list_node *node = iter->elem_handle; |
826 iter->elem_handle = node->next; |
975 iter->elem_handle = node->next; |
827 cx_invoke_destructor(list, node->payload); |
976 cx_invoke_destructor(list, node->payload); |
828 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, |
977 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, |
829 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); |
978 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); |
830 list->size--; |
979 list->collection.size--; |
831 cxFree(list->allocator, node); |
980 cxFree(list->collection.allocator, node); |
832 } else { |
981 } else { |
833 struct cx_iterator_s *iter = it; |
|
834 iter->index++; |
982 iter->index++; |
835 cx_linked_list_node *node = iter->elem_handle; |
983 cx_linked_list_node *node = iter->elem_handle; |
836 iter->elem_handle = node->next; |
984 iter->elem_handle = node->next; |
837 } |
985 } |
838 } |
986 } |
839 |
987 |
840 static void cx_ll_iter_prev(void *it) { |
988 static void cx_ll_iter_prev(void *it) { |
841 struct cx_iterator_base_s *itbase = it; |
989 struct cx_iterator_s *iter = it; |
842 if (itbase->remove) { |
990 if (iter->base.remove) { |
843 itbase->remove = false; |
991 iter->base.remove = false; |
844 struct cx_mut_iterator_s *iter = it; |
992 struct cx_list_s *list = iter->src_handle.m; |
845 struct cx_list_s *list = iter->src_handle; |
993 cx_linked_list *ll = iter->src_handle.m; |
846 cx_linked_list *ll = iter->src_handle; |
|
847 cx_linked_list_node *node = iter->elem_handle; |
994 cx_linked_list_node *node = iter->elem_handle; |
848 iter->elem_handle = node->prev; |
995 iter->elem_handle = node->prev; |
849 iter->index--; |
996 iter->index--; |
850 cx_invoke_destructor(list, node->payload); |
997 cx_invoke_destructor(list, node->payload); |
851 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, |
998 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, |
852 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); |
999 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); |
853 list->size--; |
1000 list->collection.size--; |
854 cxFree(list->allocator, node); |
1001 cxFree(list->collection.allocator, node); |
855 } else { |
1002 } else { |
856 struct cx_iterator_s *iter = it; |
|
857 iter->index--; |
1003 iter->index--; |
858 cx_linked_list_node *node = iter->elem_handle; |
1004 cx_linked_list_node *node = iter->elem_handle; |
859 iter->elem_handle = node->prev; |
1005 iter->elem_handle = node->prev; |
860 } |
1006 } |
861 } |
1007 } |
862 |
1008 |
863 static void *cx_ll_iter_current(void const *it) { |
1009 static void *cx_ll_iter_current(const void *it) { |
864 struct cx_iterator_s const *iter = it; |
1010 const struct cx_iterator_s *iter = it; |
865 cx_linked_list_node *node = iter->elem_handle; |
1011 cx_linked_list_node *node = iter->elem_handle; |
866 return node->payload; |
1012 return node->payload; |
867 } |
1013 } |
868 |
1014 |
869 static bool cx_ll_iter_flag_rm(void *it) { |
|
870 struct cx_iterator_base_s *iter = it; |
|
871 if (iter->mutating) { |
|
872 iter->remove = true; |
|
873 return true; |
|
874 } else { |
|
875 return false; |
|
876 } |
|
877 } |
|
878 |
|
879 static CxIterator cx_ll_iterator( |
1015 static CxIterator cx_ll_iterator( |
880 struct cx_list_s const *list, |
1016 const struct cx_list_s *list, |
881 size_t index, |
1017 size_t index, |
882 bool backwards |
1018 bool backwards |
883 ) { |
1019 ) { |
884 CxIterator iter; |
1020 CxIterator iter; |
885 iter.index = index; |
1021 iter.index = index; |
886 iter.src_handle = list; |
1022 iter.src_handle.c = list; |
887 iter.elem_handle = cx_ll_node_at((cx_linked_list const *) list, index); |
1023 iter.elem_handle = cx_ll_node_at((const cx_linked_list *) list, index); |
|
1024 iter.elem_size = list->collection.elem_size; |
|
1025 iter.elem_count = list->collection.size; |
888 iter.base.valid = cx_ll_iter_valid; |
1026 iter.base.valid = cx_ll_iter_valid; |
889 iter.base.current = cx_ll_iter_current; |
1027 iter.base.current = cx_ll_iter_current; |
890 iter.base.next = backwards ? cx_ll_iter_prev : cx_ll_iter_next; |
1028 iter.base.next = backwards ? cx_ll_iter_prev : cx_ll_iter_next; |
891 iter.base.flag_removal = cx_ll_iter_flag_rm; |
|
892 iter.base.mutating = false; |
1029 iter.base.mutating = false; |
893 iter.base.remove = false; |
1030 iter.base.remove = false; |
894 return iter; |
1031 return iter; |
895 } |
1032 } |
896 |
1033 |
897 static int cx_ll_insert_iter( |
1034 static int cx_ll_insert_iter( |
898 CxMutIterator *iter, |
1035 CxIterator *iter, |
899 void const *elem, |
1036 const void *elem, |
900 int prepend |
1037 int prepend |
901 ) { |
1038 ) { |
902 struct cx_list_s *list = iter->src_handle; |
1039 struct cx_list_s *list = iter->src_handle.m; |
903 cx_linked_list_node *node = iter->elem_handle; |
1040 cx_linked_list_node *node = iter->elem_handle; |
904 if (node != NULL) { |
1041 if (node != NULL) { |
905 assert(prepend >= 0 && prepend <= 1); |
1042 assert(prepend >= 0 && prepend <= 1); |
906 cx_linked_list_node *choice[2] = {node, node->prev}; |
1043 cx_linked_list_node *choice[2] = {node, node->prev}; |
907 int result = cx_ll_insert_at(list, choice[prepend], elem); |
1044 int result = cx_ll_insert_at(list, choice[prepend], elem); |
908 iter->index += prepend * (0 == result); |
1045 if (result == 0) { |
|
1046 iter->elem_count++; |
|
1047 if (prepend) { |
|
1048 iter->index++; |
|
1049 } |
|
1050 } |
909 return result; |
1051 return result; |
910 } else { |
1052 } else { |
911 int result = cx_ll_insert_element(list, list->size, elem); |
1053 int result = cx_ll_insert_element(list, list->collection.size, elem); |
912 iter->index = list->size; |
1054 if (result == 0) { |
|
1055 iter->elem_count++; |
|
1056 iter->index = list->collection.size; |
|
1057 } |
913 return result; |
1058 return result; |
914 } |
1059 } |
915 } |
1060 } |
916 |
1061 |
917 static void cx_ll_destructor(CxList *list) { |
1062 static void cx_ll_destructor(CxList *list) { |