ucx/linked_list.c

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

mercurial