ucx/linked_list.c

changeset 112
c3f2f16fa4b8
parent 108
77254bd6dccb
child 113
dde28a806552
equal deleted inserted replaced
111:81c4f73236a4 112:c3f2f16fa4b8
28 28
29 #include "cx/linked_list.h" 29 #include "cx/linked_list.h"
30 #include "cx/compare.h" 30 #include "cx/compare.h"
31 #include <string.h> 31 #include <string.h>
32 #include <assert.h> 32 #include <assert.h>
33 #include <unistd.h>
33 34
34 // LOW LEVEL LINKED LIST FUNCTIONS 35 // LOW LEVEL LINKED LIST FUNCTIONS
35 36
36 #define CX_LL_PTR(cur, off) (*(void**)(((char*)(cur))+(off))) 37 #define CX_LL_PTR(cur, off) (*(void**)(((char*)(cur))+(off)))
37 #define ll_prev(node) CX_LL_PTR(node, loc_prev) 38 #define ll_prev(node) CX_LL_PTR(node, loc_prev)
242 assert(ll_next(new_node) == NULL); 243 assert(ll_next(new_node) == NULL);
243 cx_linked_list_insert_sorted_chain( 244 cx_linked_list_insert_sorted_chain(
244 begin, end, loc_prev, loc_next, new_node, cmp_func); 245 begin, end, loc_prev, loc_next, new_node, cmp_func);
245 } 246 }
246 247
248 static void *cx_linked_list_insert_sorted_chain_impl(
249 void **begin,
250 void **end,
251 ptrdiff_t loc_prev,
252 ptrdiff_t loc_next,
253 void *insert_begin,
254 cx_compare_func cmp_func,
255 bool allow_duplicates
256 ) {
257 assert(begin != NULL);
258 assert(loc_next >= 0);
259 assert(insert_begin != NULL);
260
261 // strategy: build completely new chains from scratch
262 void *source_original = *begin;
263 void *source_argument = insert_begin;
264 void *new_begin = NULL;
265 void *new_end = NULL;
266 void *dup_begin = NULL;
267 void *dup_end = NULL;
268
269 // determine the new start
270 {
271 int d = source_original == NULL ? 1 : cmp_func(source_original, source_argument);
272 if (d <= 0) {
273 // the new chain starts with the original chain
274 new_begin = new_end = source_original;
275 source_original = ll_next(source_original);
276 if (d == 0) {
277 if (allow_duplicates) {
278 // duplicate allowed, append it to the chain
279 cx_linked_list_link(new_end, source_argument, loc_prev, loc_next);
280 new_end = source_argument;
281 } else {
282 // duplicate is not allowed, start a duplicate chain with the argument
283 dup_begin = dup_end = source_argument;
284 }
285 source_argument = ll_next(source_argument);
286 }
287 } else {
288 // input is smaller, or there is no original chain;
289 // start the new chain with the source argument
290 new_begin = new_end = source_argument;
291 source_argument = ll_next(source_argument);
292 }
293 }
294
295 // now successively compare the elements and add them to the correct chains
296 while (source_original != NULL && source_argument != NULL) {
297 int d = cmp_func(source_original, source_argument);
298 if (d <= 0) {
299 // the original is not larger, add it to the chain
300 cx_linked_list_link(new_end, source_original, loc_prev, loc_next);
301 new_end = source_original;
302 source_original = ll_next(source_original);
303 if (d == 0) {
304 if (allow_duplicates) {
305 // duplicate allowed, append it to the chain
306 cx_linked_list_link(new_end, source_argument, loc_prev, loc_next);
307 new_end = source_argument;
308 } else {
309 // duplicate is not allowed, append it to the duplicate chain
310 if (dup_end == NULL) {
311 dup_begin = dup_end = source_argument;
312 } else {
313 cx_linked_list_link(dup_end, source_argument, loc_prev, loc_next);
314 dup_end = source_argument;
315 }
316 }
317 source_argument = ll_next(source_argument);
318 }
319 } else {
320 // the original is larger, append the source argument to the chain
321 // check if we must discard the source argument as duplicate
322 if (!allow_duplicates && cmp_func(new_end, source_argument) == 0) {
323 if (dup_end == NULL) {
324 dup_begin = dup_end = source_argument;
325 } else {
326 cx_linked_list_link(dup_end, source_argument, loc_prev, loc_next);
327 dup_end = source_argument;
328 }
329 } else {
330 // no duplicate or duplicates allowed
331 cx_linked_list_link(new_end, source_argument, loc_prev, loc_next);
332 new_end = source_argument;
333 }
334 source_argument = ll_next(source_argument);
335 }
336 }
337
338 if (source_original != NULL) {
339 // something is left from the original chain, append it
340 cx_linked_list_link(new_end, source_original, loc_prev, loc_next);
341 new_end = cx_linked_list_last(source_original, loc_next);
342 } else if (source_argument != NULL) {
343 // something is left from the input chain;
344 // when we allow duplicates, append it
345 if (allow_duplicates) {
346 cx_linked_list_link(new_end, source_argument, loc_prev, loc_next);
347 new_end = cx_linked_list_last(source_argument, loc_next);
348 } else {
349 // otherwise we must check one-by-one
350 while (source_argument != NULL) {
351 if (cmp_func(new_end, source_argument) == 0) {
352 if (dup_end == NULL) {
353 dup_begin = dup_end = source_argument;
354 } else {
355 cx_linked_list_link(dup_end, source_argument, loc_prev, loc_next);
356 dup_end = source_argument;
357 }
358 } else {
359 cx_linked_list_link(new_end, source_argument, loc_prev, loc_next);
360 new_end = source_argument;
361 }
362 source_argument = ll_next(source_argument);
363 }
364 }
365 }
366
367 // null the next pointers at the end of the chain
368 ll_next(new_end) = NULL;
369 if (dup_end != NULL) {
370 ll_next(dup_end) = NULL;
371 }
372
373 // null the optional prev pointers
374 if (loc_prev >= 0) {
375 ll_prev(new_begin) = NULL;
376 if (dup_begin != NULL) {
377 ll_prev(dup_begin) = NULL;
378 }
379 }
380
381 // output
382 *begin = new_begin;
383 if (end != NULL) {
384 *end = new_end;
385 }
386 return dup_begin;
387 }
388
247 void cx_linked_list_insert_sorted_chain( 389 void cx_linked_list_insert_sorted_chain(
248 void **begin, 390 void **begin,
249 void **end, 391 void **end,
250 ptrdiff_t loc_prev, 392 ptrdiff_t loc_prev,
251 ptrdiff_t loc_next, 393 ptrdiff_t loc_next,
252 void *insert_begin, 394 void *insert_begin,
253 cx_compare_func cmp_func 395 cx_compare_func cmp_func
254 ) { 396 ) {
255 assert(begin != NULL); 397 cx_linked_list_insert_sorted_chain_impl(
256 assert(loc_next >= 0); 398 begin, end, loc_prev, loc_next,
257 assert(insert_begin != NULL); 399 insert_begin, cmp_func, true);
258 400 }
259 // track currently observed nodes 401
260 void *dest_prev = NULL; 402 int cx_linked_list_insert_unique(
261 void *dest = *begin; 403 void **begin,
262 void *src = insert_begin; 404 void **end,
263 405 ptrdiff_t loc_prev,
264 // special case: list is empty 406 ptrdiff_t loc_next,
265 if (dest == NULL) { 407 void *new_node,
266 *begin = src; 408 cx_compare_func cmp_func
267 if (end != NULL) { 409 ) {
268 *end = cx_linked_list_last(src, loc_next); 410 assert(ll_next(new_node) == NULL);
269 } 411 return NULL != cx_linked_list_insert_unique_chain(
270 return; 412 begin, end, loc_prev, loc_next, new_node, cmp_func);
271 } 413 }
272 414
273 // search the list for insertion points 415 void *cx_linked_list_insert_unique_chain(
274 while (dest != NULL && src != NULL) { 416 void **begin,
275 // compare current list node with source node 417 void **end,
276 // if less or equal, skip 418 ptrdiff_t loc_prev,
277 if (cmp_func(dest, src) <= 0) { 419 ptrdiff_t loc_next,
278 dest_prev = dest; 420 void *insert_begin,
279 dest = ll_next(dest); 421 cx_compare_func cmp_func
280 continue; 422 ) {
281 } 423 return cx_linked_list_insert_sorted_chain_impl(
282 424 begin, end, loc_prev, loc_next,
283 // determine chain of elements that can be inserted 425 insert_begin, cmp_func, false);
284 void *end_of_chain = src;
285 void *next_in_chain = ll_next(src);
286 while (next_in_chain != NULL) {
287 // once we become larger than the list elem, break
288 if (cmp_func(dest, next_in_chain) <= 0) {
289 break;
290 }
291 // otherwise, we can insert one more
292 end_of_chain = next_in_chain;
293 next_in_chain = ll_next(next_in_chain);
294 }
295
296 // insert the elements
297 if (dest_prev == NULL) {
298 // new begin
299 *begin = src;
300 } else {
301 cx_linked_list_link(dest_prev, src, loc_prev, loc_next);
302 }
303 cx_linked_list_link(end_of_chain, dest, loc_prev, loc_next);
304
305 // continue with next
306 src = next_in_chain;
307 dest_prev = dest;
308 dest = ll_next(dest);
309 }
310
311 // insert remaining items
312 if (src != NULL) {
313 cx_linked_list_link(dest_prev, src, loc_prev, loc_next);
314 }
315
316 // determine new end of list, if requested
317 if (end != NULL) {
318 *end = cx_linked_list_last(
319 dest != NULL ? dest : dest_prev, loc_next);
320 }
321 } 426 }
322 427
323 size_t cx_linked_list_remove_chain( 428 size_t cx_linked_list_remove_chain(
324 void **begin, 429 void **begin,
325 void **end, 430 void **end,
562 *begin = prev; 667 *begin = prev;
563 } 668 }
564 669
565 // HIGH LEVEL LINKED LIST IMPLEMENTATION 670 // HIGH LEVEL LINKED LIST IMPLEMENTATION
566 671
567 typedef struct cx_linked_list_node cx_linked_list_node; 672 static void *cx_ll_node_at(
568 struct cx_linked_list_node {
569 cx_linked_list_node *prev;
570 cx_linked_list_node *next;
571 char payload[];
572 };
573
574 #define CX_LL_LOC_PREV offsetof(cx_linked_list_node, prev)
575 #define CX_LL_LOC_NEXT offsetof(cx_linked_list_node, next)
576 #define CX_LL_LOC_DATA offsetof(cx_linked_list_node, payload)
577
578 typedef struct {
579 struct cx_list_s base;
580 cx_linked_list_node *begin;
581 cx_linked_list_node *end;
582 } cx_linked_list;
583
584 static cx_linked_list_node *cx_ll_node_at(
585 const cx_linked_list *list, 673 const cx_linked_list *list,
586 size_t index 674 size_t index
587 ) { 675 ) {
588 if (index >= list->base.collection.size) { 676 if (index >= list->base.collection.size) {
589 return NULL; 677 return NULL;
590 } else if (index > list->base.collection.size / 2) { 678 } else if (index > list->base.collection.size / 2) {
591 return cx_linked_list_at(list->end, list->base.collection.size - 1, CX_LL_LOC_PREV, index); 679 return cx_linked_list_at(list->end, list->base.collection.size - 1, list->loc_prev, index);
592 } else { 680 } else {
593 return cx_linked_list_at(list->begin, 0, CX_LL_LOC_NEXT, index); 681 return cx_linked_list_at(list->begin, 0, list->loc_next, index);
594 } 682 }
595 } 683 }
596 684
597 static cx_linked_list_node *cx_ll_malloc_node(const struct cx_list_s *list) { 685 static void *cx_ll_malloc_node(const cx_linked_list *list) {
598 return cxMalloc(list->collection.allocator, 686 return cxZalloc(list->base.collection.allocator,
599 sizeof(cx_linked_list_node) + list->collection.elem_size); 687 list->loc_data + list->base.collection.elem_size + list->extra_data_len);
600 } 688 }
601 689
602 static int cx_ll_insert_at( 690 static int cx_ll_insert_at(
603 struct cx_list_s *list, 691 struct cx_list_s *list,
604 cx_linked_list_node *node, 692 void *node,
605 const void *elem 693 const void *elem
606 ) { 694 ) {
695 cx_linked_list *ll = (cx_linked_list *) list;
607 696
608 // create the new new_node 697 // create the new new_node
609 cx_linked_list_node *new_node = cx_ll_malloc_node(list); 698 void *new_node = cx_ll_malloc_node(ll);
610 699
611 // sortir if failed 700 // sortir if failed
612 if (new_node == NULL) return 1; 701 if (new_node == NULL) return 1;
613 702
614 // initialize new new_node 703 // copy the data
615 new_node->prev = new_node->next = NULL;
616 if (elem != NULL) { 704 if (elem != NULL) {
617 memcpy(new_node->payload, elem, list->collection.elem_size); 705 memcpy((char*)new_node + ll->loc_data, elem, list->collection.elem_size);
618 } 706 }
619 707
620 // insert 708 // insert
621 cx_linked_list *ll = (cx_linked_list *) list;
622 cx_linked_list_insert_chain( 709 cx_linked_list_insert_chain(
623 (void **) &ll->begin, (void **) &ll->end, 710 &ll->begin, &ll->end,
624 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, 711 ll->loc_prev, ll->loc_next,
625 node, new_node, new_node 712 node, new_node, new_node
626 ); 713 );
627 714
628 // increase the size and return 715 // increase the size and return
629 list->collection.size++; 716 list->collection.size++;
638 ) { 725 ) {
639 // out-of bounds and corner case check 726 // out-of bounds and corner case check
640 if (index > list->collection.size || n == 0) return 0; 727 if (index > list->collection.size || n == 0) return 0;
641 728
642 // find position efficiently 729 // find position efficiently
643 cx_linked_list_node *node = index == 0 ? NULL : cx_ll_node_at((cx_linked_list *) list, index - 1); 730 void *node = index == 0 ? NULL : cx_ll_node_at((cx_linked_list *) list, index - 1);
644 731
645 // perform first insert 732 // perform first insert
646 if (0 != cx_ll_insert_at(list, node, array)) return 1; 733 if (0 != cx_ll_insert_at(list, node, array)) return 1;
647 734
648 // is there more? 735 // is there more?
649 if (n == 1) return 1; 736 if (n == 1) return 1;
650 737
651 // we now know exactly where we are 738 // we now know exactly where we are
652 node = node == NULL ? ((cx_linked_list *) list)->begin : node->next; 739 cx_linked_list *ll = (cx_linked_list *) list;
740 node = node == NULL ? ((cx_linked_list *) list)->begin : CX_LL_PTR(node, ll->loc_next);
653 741
654 // we can add the remaining nodes and immediately advance to the inserted node 742 // we can add the remaining nodes and immediately advance to the inserted node
655 const char *source = array; 743 const char *source = array;
656 for (size_t i = 1; i < n; i++) { 744 for (size_t i = 1; i < n; i++) {
657 source += list->collection.elem_size; 745 source += list->collection.elem_size;
658 if (0 != cx_ll_insert_at(list, node, source)) return i; 746 if (0 != cx_ll_insert_at(list, node, source)) return i;
659 node = node->next; 747 node = CX_LL_PTR(node, ll->loc_next);
660 } 748 }
661 return n; 749 return n;
662 } 750 }
663 751
664 static void *cx_ll_insert_element( 752 static void *cx_ll_insert_element(
668 ) { 756 ) {
669 // out-of-bounds check 757 // out-of-bounds check
670 if (index > list->collection.size) return NULL; 758 if (index > list->collection.size) return NULL;
671 759
672 // find position efficiently 760 // find position efficiently
673 cx_linked_list_node *node = index == 0 ? NULL : cx_ll_node_at((cx_linked_list *) list, index - 1); 761 void *node = index == 0 ? NULL : cx_ll_node_at((cx_linked_list *) list, index - 1);
674 762
675 // perform first insert 763 // perform first insert
676 if (cx_ll_insert_at(list, node, element)) return NULL; 764 if (cx_ll_insert_at(list, node, element)) return NULL;
677 765
678 // return a pointer to the data of the inserted node 766 // return a pointer to the data of the inserted node
767 cx_linked_list *ll = (cx_linked_list *) list;
679 if (node == NULL) { 768 if (node == NULL) {
680 return ((cx_linked_list *) list)->begin->payload; 769 return (char*)(ll->begin) + ll->loc_data;
681 } else { 770 } else {
682 return node->next->payload; 771 char *next = CX_LL_PTR(node, ll->loc_next);
772 return next + ll->loc_data;
683 } 773 }
684 } 774 }
685 775
686 static _Thread_local cx_compare_func cx_ll_insert_sorted_cmp_func; 776 static _Thread_local cx_compare_func cx_ll_insert_sorted_cmp_func;
777 static _Thread_local off_t cx_ll_insert_sorted_loc_data;
687 778
688 static int cx_ll_insert_sorted_cmp_helper(const void *l, const void *r) { 779 static int cx_ll_insert_sorted_cmp_helper(const void *l, const void *r) {
689 const cx_linked_list_node *left = l; 780 const char *left = (const char*)l + cx_ll_insert_sorted_loc_data;
690 const cx_linked_list_node *right = r; 781 const char *right = (const char*)r + cx_ll_insert_sorted_loc_data;
691 return cx_ll_insert_sorted_cmp_func(left->payload, right->payload); 782 return cx_ll_insert_sorted_cmp_func(left, right);
783 }
784
785 static size_t cx_ll_insert_sorted_impl(
786 struct cx_list_s *list,
787 const void *array,
788 size_t n,
789 bool allow_duplicates
790 ) {
791 cx_linked_list *ll = (cx_linked_list *) list;
792
793 // special case
794 if (n == 0) return 0;
795
796 // create a new chain of nodes
797 void *chain = cx_ll_malloc_node(ll);
798 if (chain == NULL) return 0;
799
800 memcpy((char*)chain + ll->loc_data, array, list->collection.elem_size);
801
802 // add all elements from the array to that chain
803 void *prev = chain;
804 const char *src = array;
805 size_t inserted = 1;
806 for (; inserted < n; inserted++) {
807 void *next = cx_ll_malloc_node(ll);
808 if (next == NULL) break;
809 src += list->collection.elem_size;
810 memcpy((char*)next + ll->loc_data, src, list->collection.elem_size);
811 CX_LL_PTR(prev, ll->loc_next) = next;
812 CX_LL_PTR(next, ll->loc_prev) = prev;
813 prev = next;
814 }
815 CX_LL_PTR(prev, ll->loc_next) = NULL;
816
817 // invoke the low level function
818 cx_ll_insert_sorted_cmp_func = list->collection.cmpfunc;
819 cx_ll_insert_sorted_loc_data = ll->loc_data;
820 if (allow_duplicates) {
821 cx_linked_list_insert_sorted_chain(
822 &ll->begin,
823 &ll->end,
824 ll->loc_prev,
825 ll->loc_next,
826 chain,
827 cx_ll_insert_sorted_cmp_helper
828 );
829 list->collection.size += inserted;
830 } else {
831 void *duplicates = cx_linked_list_insert_unique_chain(
832 &ll->begin,
833 &ll->end,
834 ll->loc_prev,
835 ll->loc_next,
836 chain,
837 cx_ll_insert_sorted_cmp_helper
838 );
839 list->collection.size += inserted;
840 // free the nodes that did not make it into the list
841 while (duplicates != NULL) {
842 void *next = CX_LL_PTR(duplicates, ll->loc_next);
843 cxFree(list->collection.allocator, duplicates);
844 duplicates = next;
845 list->collection.size--;
846 }
847 }
848
849 return inserted;
692 } 850 }
693 851
694 static size_t cx_ll_insert_sorted( 852 static size_t cx_ll_insert_sorted(
695 struct cx_list_s *list, 853 struct cx_list_s *list,
696 const void *array, 854 const void *array,
697 size_t n 855 size_t n
698 ) { 856 ) {
699 // special case 857 return cx_ll_insert_sorted_impl(list, array, n, true);
700 if (n == 0) return 0; 858 }
701 859
702 // create a new chain of nodes 860 static size_t cx_ll_insert_unique(
703 cx_linked_list_node *chain = cx_ll_malloc_node(list); 861 struct cx_list_s *list,
704 if (chain == NULL) return 0; 862 const void *array,
705 863 size_t n
706 memcpy(chain->payload, array, list->collection.elem_size); 864 ) {
707 chain->prev = NULL; 865 return cx_ll_insert_sorted_impl(list, array, n, false);
708 chain->next = NULL;
709
710 // add all elements from the array to that chain
711 cx_linked_list_node *prev = chain;
712 const char *src = array;
713 size_t inserted = 1;
714 for (; inserted < n; inserted++) {
715 cx_linked_list_node *next = cx_ll_malloc_node(list);
716 if (next == NULL) break;
717 src += list->collection.elem_size;
718 memcpy(next->payload, src, list->collection.elem_size);
719 prev->next = next;
720 next->prev = prev;
721 prev = next;
722 }
723 prev->next = NULL;
724
725 // invoke the low level function
726 cx_linked_list *ll = (cx_linked_list *) list;
727 cx_ll_insert_sorted_cmp_func = list->collection.cmpfunc;
728 cx_linked_list_insert_sorted_chain(
729 (void **) &ll->begin,
730 (void **) &ll->end,
731 CX_LL_LOC_PREV,
732 CX_LL_LOC_NEXT,
733 chain,
734 cx_ll_insert_sorted_cmp_helper
735 );
736
737 // adjust the list metadata
738 list->collection.size += inserted;
739
740 return inserted;
741 } 866 }
742 867
743 static size_t cx_ll_remove( 868 static size_t cx_ll_remove(
744 struct cx_list_s *list, 869 struct cx_list_s *list,
745 size_t index, 870 size_t index,
746 size_t num, 871 size_t num,
747 void *targetbuf 872 void *targetbuf
748 ) { 873 ) {
749 cx_linked_list *ll = (cx_linked_list *) list; 874 cx_linked_list *ll = (cx_linked_list *) list;
750 cx_linked_list_node *node = cx_ll_node_at(ll, index); 875 void *node = cx_ll_node_at(ll, index);
751 876
752 // out-of-bounds check 877 // out-of-bounds check
753 if (node == NULL) return 0; 878 if (node == NULL) return 0;
754 879
755 // remove 880 // remove
756 size_t removed = cx_linked_list_remove_chain( 881 size_t removed = cx_linked_list_remove_chain(
757 (void **) &ll->begin, 882 (void **) &ll->begin,
758 (void **) &ll->end, 883 (void **) &ll->end,
759 CX_LL_LOC_PREV, 884 ll->loc_prev,
760 CX_LL_LOC_NEXT, 885 ll->loc_next,
761 node, 886 node,
762 num 887 num
763 ); 888 );
764 889
765 // adjust size 890 // adjust size
766 list->collection.size -= removed; 891 list->collection.size -= removed;
767 892
768 // copy or destroy the removed chain 893 // copy or destroy the removed chain
769 if (targetbuf == NULL) { 894 if (targetbuf == NULL) {
770 cx_linked_list_node *n = node; 895 char *n = node;
771 for (size_t i = 0; i < removed; i++) { 896 for (size_t i = 0; i < removed; i++) {
772 // element destruction 897 // element destruction
773 cx_invoke_destructor(list, n->payload); 898 cx_invoke_destructor(list, n + ll->loc_data);
774 899
775 // free the node and advance 900 // free the node and advance
776 void *next = n->next; 901 void *next = CX_LL_PTR(n, ll->loc_next);
777 cxFree(list->collection.allocator, n); 902 cxFree(list->collection.allocator, n);
778 n = next; 903 n = next;
779 } 904 }
780 } else { 905 } else {
781 char *dest = targetbuf; 906 char *dest = targetbuf;
782 cx_linked_list_node *n = node; 907 char *n = node;
783 for (size_t i = 0; i < removed; i++) { 908 for (size_t i = 0; i < removed; i++) {
784 // copy payload 909 // copy payload
785 memcpy(dest, n->payload, list->collection.elem_size); 910 memcpy(dest, n + ll->loc_data, list->collection.elem_size);
786 911
787 // advance target buffer 912 // advance target buffer
788 dest += list->collection.elem_size; 913 dest += list->collection.elem_size;
789 914
790 // free the node and advance 915 // free the node and advance
791 void *next = n->next; 916 void *next = CX_LL_PTR(n, ll->loc_next);
792 cxFree(list->collection.allocator, n); 917 cxFree(list->collection.allocator, n);
793 n = next; 918 n = next;
794 } 919 }
795 } 920 }
796 921
799 924
800 static void cx_ll_clear(struct cx_list_s *list) { 925 static void cx_ll_clear(struct cx_list_s *list) {
801 if (list->collection.size == 0) return; 926 if (list->collection.size == 0) return;
802 927
803 cx_linked_list *ll = (cx_linked_list *) list; 928 cx_linked_list *ll = (cx_linked_list *) list;
804 cx_linked_list_node *node = ll->begin; 929 char *node = ll->begin;
805 while (node != NULL) { 930 while (node != NULL) {
806 cx_invoke_destructor(list, node->payload); 931 cx_invoke_destructor(list, node + ll->loc_data);
807 cx_linked_list_node *next = node->next; 932 void *next = CX_LL_PTR(node, ll->loc_next);
808 cxFree(list->collection.allocator, node); 933 cxFree(list->collection.allocator, node);
809 node = next; 934 node = next;
810 } 935 }
811 ll->begin = ll->end = NULL; 936 ll->begin = ll->end = NULL;
812 list->collection.size = 0; 937 list->collection.size = 0;
829 right = j; 954 right = j;
830 } else { 955 } else {
831 left = j; 956 left = j;
832 right = i; 957 right = i;
833 } 958 }
834 cx_linked_list_node *nleft = NULL, *nright = NULL; 959 void *nleft = NULL, *nright = NULL;
835 if (left < mid && right < mid) { 960 if (left < mid && right < mid) {
836 // case 1: both items left from mid 961 // case 1: both items left from mid
837 nleft = cx_ll_node_at(ll, left); 962 nleft = cx_ll_node_at(ll, left);
838 assert(nleft != NULL); 963 assert(nleft != NULL);
839 nright = nleft; 964 nright = nleft;
840 for (size_t c = left; c < right; c++) { 965 for (size_t c = left; c < right; c++) {
841 nright = nright->next; 966 nright = CX_LL_PTR(nright, ll->loc_next);
842 } 967 }
843 } else if (left >= mid && right >= mid) { 968 } else if (left >= mid && right >= mid) {
844 // case 2: both items right from mid 969 // case 2: both items right from mid
845 nright = cx_ll_node_at(ll, right); 970 nright = cx_ll_node_at(ll, right);
846 assert(nright != NULL); 971 assert(nright != NULL);
847 nleft = nright; 972 nleft = nright;
848 for (size_t c = right; c > left; c--) { 973 for (size_t c = right; c > left; c--) {
849 nleft = nleft->prev; 974 nleft = CX_LL_PTR(nleft, ll->loc_prev);
850 } 975 }
851 } else { 976 } else {
852 // case 3: one item left, one item right 977 // case 3: one item left, one item right
853 978
854 // chose the closest to begin / end 979 // chose the closest to begin / end
870 if (right - left <= diff2boundary) { 995 if (right - left <= diff2boundary) {
871 // search other element starting from already found element 996 // search other element starting from already found element
872 if (closest == left) { 997 if (closest == left) {
873 nright = nleft; 998 nright = nleft;
874 for (size_t c = left; c < right; c++) { 999 for (size_t c = left; c < right; c++) {
875 nright = nright->next; 1000 nright = CX_LL_PTR(nright, ll->loc_next);
876 } 1001 }
877 } else { 1002 } else {
878 nleft = nright; 1003 nleft = nright;
879 for (size_t c = right; c > left; c--) { 1004 for (size_t c = right; c > left; c--) {
880 nleft = nleft->prev; 1005 nleft = CX_LL_PTR(nleft, ll->loc_prev);
881 } 1006 }
882 } 1007 }
883 } else { 1008 } else {
884 // search other element starting at the boundary 1009 // search other element starting at the boundary
885 if (closest == left) { 1010 if (closest == left) {
888 nleft = cx_ll_node_at(ll, other); 1013 nleft = cx_ll_node_at(ll, other);
889 } 1014 }
890 } 1015 }
891 } 1016 }
892 1017
893 cx_linked_list_node *prev = nleft->prev; 1018 void *prev = CX_LL_PTR(nleft, ll->loc_prev);
894 cx_linked_list_node *next = nright->next; 1019 void *next = CX_LL_PTR(nright, ll->loc_next);
895 cx_linked_list_node *midstart = nleft->next; 1020 void *midstart = CX_LL_PTR(nleft, ll->loc_next);
896 cx_linked_list_node *midend = nright->prev; 1021 void *midend = CX_LL_PTR(nright, ll->loc_prev);
897 1022
898 if (prev == NULL) { 1023 if (prev == NULL) {
899 ll->begin = nright; 1024 ll->begin = nright;
900 } else { 1025 } else {
901 prev->next = nright; 1026 CX_LL_PTR(prev, ll->loc_next) = nright;
902 } 1027 }
903 nright->prev = prev; 1028 CX_LL_PTR(nright, ll->loc_prev) = prev;
904 if (midstart == nright) { 1029 if (midstart == nright) {
905 // special case: both nodes are adjacent 1030 // special case: both nodes are adjacent
906 nright->next = nleft; 1031 CX_LL_PTR(nright, ll->loc_next) = nleft;
907 nleft->prev = nright; 1032 CX_LL_PTR(nleft, ll->loc_prev) = nright;
908 } else { 1033 } else {
909 // likely case: a chain is between the two nodes 1034 // likely case: a chain is between the two nodes
910 nright->next = midstart; 1035 CX_LL_PTR(nright, ll->loc_next) = midstart;
911 midstart->prev = nright; 1036 CX_LL_PTR(midstart, ll->loc_prev) = nright;
912 midend->next = nleft; 1037 CX_LL_PTR(midend, ll->loc_next) = nleft;
913 nleft->prev = midend; 1038 CX_LL_PTR(nleft, ll->loc_prev) = midend;
914 } 1039 }
915 nleft->next = next; 1040 CX_LL_PTR(nleft, ll->loc_next) = next;
916 if (next == NULL) { 1041 if (next == NULL) {
917 ll->end = nleft; 1042 ll->end = nleft;
918 } else { 1043 } else {
919 next->prev = nleft; 1044 CX_LL_PTR(next, ll->loc_prev) = nleft;
920 } 1045 }
921 1046
922 return 0; 1047 return 0;
923 } 1048 }
924 1049
925 static void *cx_ll_at( 1050 static void *cx_ll_at(
926 const struct cx_list_s *list, 1051 const struct cx_list_s *list,
927 size_t index 1052 size_t index
928 ) { 1053 ) {
929 cx_linked_list *ll = (cx_linked_list *) list; 1054 cx_linked_list *ll = (cx_linked_list *) list;
930 cx_linked_list_node *node = cx_ll_node_at(ll, index); 1055 char *node = cx_ll_node_at(ll, index);
931 return node == NULL ? NULL : node->payload; 1056 return node == NULL ? NULL : node + ll->loc_data;
932 } 1057 }
933 1058
934 static size_t cx_ll_find_remove( 1059 static size_t cx_ll_find_remove(
935 struct cx_list_s *list, 1060 struct cx_list_s *list,
936 const void *elem, 1061 const void *elem,
937 bool remove 1062 bool remove
938 ) { 1063 ) {
939 if (list->collection.size == 0) return 0; 1064 if (list->collection.size == 0) return 0;
940 1065
941 size_t index; 1066 size_t index;
942 cx_linked_list *ll = ((cx_linked_list *) list); 1067 cx_linked_list *ll = (cx_linked_list *) list;
943 cx_linked_list_node *node = cx_linked_list_find( 1068 char *node = cx_linked_list_find(
944 ll->begin, 1069 ll->begin,
945 CX_LL_LOC_NEXT, CX_LL_LOC_DATA, 1070 ll->loc_next, ll->loc_data,
946 list->collection.cmpfunc, elem, 1071 list->collection.cmpfunc, elem,
947 &index 1072 &index
948 ); 1073 );
949 if (node == NULL) { 1074 if (node == NULL) {
950 return list->collection.size; 1075 return list->collection.size;
951 } 1076 }
952 if (remove) { 1077 if (remove) {
953 cx_invoke_destructor(list, node->payload); 1078 cx_invoke_destructor(list, node + ll->loc_data);
954 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, 1079 cx_linked_list_remove(&ll->begin, &ll->end,
955 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); 1080 ll->loc_prev, ll->loc_next, node);
956 list->collection.size--; 1081 list->collection.size--;
957 cxFree(list->collection.allocator, node); 1082 cxFree(list->collection.allocator, node);
958 } 1083 }
959 return index; 1084 return index;
960 } 1085 }
961 1086
962 static void cx_ll_sort(struct cx_list_s *list) { 1087 static void cx_ll_sort(struct cx_list_s *list) {
963 cx_linked_list *ll = (cx_linked_list *) list; 1088 cx_linked_list *ll = (cx_linked_list *) list;
964 cx_linked_list_sort((void **) &ll->begin, (void **) &ll->end, 1089 cx_linked_list_sort(&ll->begin, &ll->end,
965 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, CX_LL_LOC_DATA, 1090 ll->loc_prev, ll->loc_next, ll->loc_data,
966 list->collection.cmpfunc); 1091 list->collection.cmpfunc);
967 } 1092 }
968 1093
969 static void cx_ll_reverse(struct cx_list_s *list) { 1094 static void cx_ll_reverse(struct cx_list_s *list) {
970 cx_linked_list *ll = (cx_linked_list *) list; 1095 cx_linked_list *ll = (cx_linked_list *) list;
971 cx_linked_list_reverse((void **) &ll->begin, (void **) &ll->end, CX_LL_LOC_PREV, CX_LL_LOC_NEXT); 1096 cx_linked_list_reverse(&ll->begin, &ll->end, ll->loc_prev, ll->loc_next);
972 } 1097 }
973 1098
974 static int cx_ll_compare( 1099 static int cx_ll_compare(
975 const struct cx_list_s *list, 1100 const struct cx_list_s *list,
976 const struct cx_list_s *other 1101 const struct cx_list_s *other
977 ) { 1102 ) {
978 cx_linked_list *left = (cx_linked_list *) list; 1103 cx_linked_list *left = (cx_linked_list *) list;
979 cx_linked_list *right = (cx_linked_list *) other; 1104 cx_linked_list *right = (cx_linked_list *) other;
1105 assert(left->loc_next == right->loc_next);
1106 assert(left->loc_data == right->loc_data);
980 return cx_linked_list_compare(left->begin, right->begin, 1107 return cx_linked_list_compare(left->begin, right->begin,
981 CX_LL_LOC_NEXT, CX_LL_LOC_DATA, 1108 left->loc_next, left->loc_data,
982 list->collection.cmpfunc); 1109 list->collection.cmpfunc);
983 } 1110 }
984 1111
985 static bool cx_ll_iter_valid(const void *it) { 1112 static bool cx_ll_iter_valid(const void *it) {
986 const struct cx_iterator_s *iter = it; 1113 const struct cx_iterator_s *iter = it;
991 struct cx_iterator_s *iter = it; 1118 struct cx_iterator_s *iter = it;
992 if (iter->base.remove) { 1119 if (iter->base.remove) {
993 iter->base.remove = false; 1120 iter->base.remove = false;
994 struct cx_list_s *list = iter->src_handle.m; 1121 struct cx_list_s *list = iter->src_handle.m;
995 cx_linked_list *ll = iter->src_handle.m; 1122 cx_linked_list *ll = iter->src_handle.m;
996 cx_linked_list_node *node = iter->elem_handle; 1123 char *node = iter->elem_handle;
997 iter->elem_handle = node->next; 1124 iter->elem_handle = CX_LL_PTR(node, ll->loc_next);
998 cx_invoke_destructor(list, node->payload); 1125 cx_invoke_destructor(list, node + ll->loc_data);
999 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, 1126 cx_linked_list_remove(&ll->begin, &ll->end,
1000 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); 1127 ll->loc_prev, ll->loc_next, node);
1001 list->collection.size--; 1128 list->collection.size--;
1129 iter->elem_count--;
1002 cxFree(list->collection.allocator, node); 1130 cxFree(list->collection.allocator, node);
1003 } else { 1131 } else {
1132 const cx_linked_list *ll = iter->src_handle.c;
1004 iter->index++; 1133 iter->index++;
1005 cx_linked_list_node *node = iter->elem_handle; 1134 void *node = iter->elem_handle;
1006 iter->elem_handle = node->next; 1135 iter->elem_handle = CX_LL_PTR(node, ll->loc_next);
1007 } 1136 }
1008 } 1137 }
1009 1138
1010 static void cx_ll_iter_prev(void *it) { 1139 static void cx_ll_iter_prev(void *it) {
1011 struct cx_iterator_s *iter = it; 1140 struct cx_iterator_s *iter = it;
1012 if (iter->base.remove) { 1141 if (iter->base.remove) {
1013 iter->base.remove = false; 1142 iter->base.remove = false;
1014 struct cx_list_s *list = iter->src_handle.m; 1143 struct cx_list_s *list = iter->src_handle.m;
1015 cx_linked_list *ll = iter->src_handle.m; 1144 cx_linked_list *ll = iter->src_handle.m;
1016 cx_linked_list_node *node = iter->elem_handle; 1145 char *node = iter->elem_handle;
1017 iter->elem_handle = node->prev; 1146 iter->elem_handle = CX_LL_PTR(node, ll->loc_prev);
1018 iter->index--; 1147 iter->index--;
1019 cx_invoke_destructor(list, node->payload); 1148 cx_invoke_destructor(list, node + ll->loc_data);
1020 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, 1149 cx_linked_list_remove(&ll->begin, &ll->end,
1021 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); 1150 ll->loc_prev, ll->loc_next, node);
1022 list->collection.size--; 1151 list->collection.size--;
1152 iter->elem_count--;
1023 cxFree(list->collection.allocator, node); 1153 cxFree(list->collection.allocator, node);
1024 } else { 1154 } else {
1155 const cx_linked_list *ll = iter->src_handle.c;
1025 iter->index--; 1156 iter->index--;
1026 cx_linked_list_node *node = iter->elem_handle; 1157 char *node = iter->elem_handle;
1027 iter->elem_handle = node->prev; 1158 iter->elem_handle = CX_LL_PTR(node, ll->loc_prev);
1028 } 1159 }
1029 } 1160 }
1030 1161
1031 static void *cx_ll_iter_current(const void *it) { 1162 static void *cx_ll_iter_current(const void *it) {
1032 const struct cx_iterator_s *iter = it; 1163 const struct cx_iterator_s *iter = it;
1033 cx_linked_list_node *node = iter->elem_handle; 1164 const cx_linked_list *ll = iter->src_handle.c;
1034 return node->payload; 1165 char *node = iter->elem_handle;
1166 return node + ll->loc_data;
1035 } 1167 }
1036 1168
1037 static CxIterator cx_ll_iterator( 1169 static CxIterator cx_ll_iterator(
1038 const struct cx_list_s *list, 1170 const struct cx_list_s *list,
1039 size_t index, 1171 size_t index,
1057 CxIterator *iter, 1189 CxIterator *iter,
1058 const void *elem, 1190 const void *elem,
1059 int prepend 1191 int prepend
1060 ) { 1192 ) {
1061 struct cx_list_s *list = iter->src_handle.m; 1193 struct cx_list_s *list = iter->src_handle.m;
1062 cx_linked_list_node *node = iter->elem_handle; 1194 cx_linked_list *ll = iter->src_handle.m;
1195 void *node = iter->elem_handle;
1063 if (node != NULL) { 1196 if (node != NULL) {
1064 assert(prepend >= 0 && prepend <= 1); 1197 assert(prepend >= 0 && prepend <= 1);
1065 cx_linked_list_node *choice[2] = {node, node->prev}; 1198 void *choice[2] = {node, CX_LL_PTR(node, ll->loc_prev)};
1066 int result = cx_ll_insert_at(list, choice[prepend], elem); 1199 int result = cx_ll_insert_at(list, choice[prepend], elem);
1067 if (result == 0) { 1200 if (result == 0) {
1068 iter->elem_count++; 1201 iter->elem_count++;
1069 if (prepend) { 1202 if (prepend) {
1070 iter->index++; 1203 iter->index++;
1082 } 1215 }
1083 1216
1084 static void cx_ll_destructor(CxList *list) { 1217 static void cx_ll_destructor(CxList *list) {
1085 cx_linked_list *ll = (cx_linked_list *) list; 1218 cx_linked_list *ll = (cx_linked_list *) list;
1086 1219
1087 cx_linked_list_node *node = ll->begin; 1220 char *node = ll->begin;
1088 while (node) { 1221 while (node) {
1089 cx_invoke_destructor(list, node->payload); 1222 cx_invoke_destructor(list, node + ll->loc_data);
1090 void *next = node->next; 1223 void *next = CX_LL_PTR(node, ll->loc_next);
1091 cxFree(list->collection.allocator, node); 1224 cxFree(list->collection.allocator, node);
1092 node = next; 1225 node = next;
1093 } 1226 }
1094 1227
1095 cxFree(list->collection.allocator, list); 1228 cxFree(list->collection.allocator, list);
1098 static cx_list_class cx_linked_list_class = { 1231 static cx_list_class cx_linked_list_class = {
1099 cx_ll_destructor, 1232 cx_ll_destructor,
1100 cx_ll_insert_element, 1233 cx_ll_insert_element,
1101 cx_ll_insert_array, 1234 cx_ll_insert_array,
1102 cx_ll_insert_sorted, 1235 cx_ll_insert_sorted,
1236 cx_ll_insert_unique,
1103 cx_ll_insert_iter, 1237 cx_ll_insert_iter,
1104 cx_ll_remove, 1238 cx_ll_remove,
1105 cx_ll_clear, 1239 cx_ll_clear,
1106 cx_ll_swap, 1240 cx_ll_swap,
1107 cx_ll_at, 1241 cx_ll_at,
1121 allocator = cxDefaultAllocator; 1255 allocator = cxDefaultAllocator;
1122 } 1256 }
1123 1257
1124 cx_linked_list *list = cxCalloc(allocator, 1, sizeof(cx_linked_list)); 1258 cx_linked_list *list = cxCalloc(allocator, 1, sizeof(cx_linked_list));
1125 if (list == NULL) return NULL; 1259 if (list == NULL) return NULL;
1260 list->extra_data_len = 0;
1261 list->loc_prev = 0;
1262 list->loc_next = sizeof(void*);
1263 list->loc_data = sizeof(void*)*2;
1126 cx_list_init((CxList*)list, &cx_linked_list_class, 1264 cx_list_init((CxList*)list, &cx_linked_list_class,
1127 allocator, comparator, elem_size); 1265 allocator, comparator, elem_size);
1128 1266
1129 return (CxList *) list; 1267 return (CxList *) list;
1130 } 1268 }

mercurial