ucx/linked_list.c

changeset 852
83fdf679df99
parent 816
839fefbdedc7
equal deleted inserted replaced
850:bbe2925eb590 852:83fdf679df99
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29 #include "cx/linked_list.h" 29 #include "cx/linked_list.h"
30 #include "cx/utils.h"
31 #include "cx/compare.h" 30 #include "cx/compare.h"
32 #include <string.h> 31 #include <string.h>
33 #include <assert.h> 32 #include <assert.h>
34 33
35 // LOW LEVEL LINKED LIST FUNCTIONS 34 // LOW LEVEL LINKED LIST FUNCTIONS
39 #define ll_next(node) CX_LL_PTR(node, loc_next) 38 #define ll_next(node) CX_LL_PTR(node, loc_next)
40 #define ll_advance(node) CX_LL_PTR(node, loc_advance) 39 #define ll_advance(node) CX_LL_PTR(node, loc_advance)
41 #define ll_data(node) (((char*)(node))+loc_data) 40 #define ll_data(node) (((char*)(node))+loc_data)
42 41
43 void *cx_linked_list_at( 42 void *cx_linked_list_at(
44 void const *start, 43 const void *start,
45 size_t start_index, 44 size_t start_index,
46 ptrdiff_t loc_advance, 45 ptrdiff_t loc_advance,
47 size_t index 46 size_t index
48 ) { 47 ) {
49 assert(start != NULL); 48 assert(start != NULL);
50 assert(loc_advance >= 0); 49 assert(loc_advance >= 0);
51 size_t i = start_index; 50 size_t i = start_index;
52 void const *cur = start; 51 const void *cur = start;
53 while (i != index && cur != NULL) { 52 while (i != index && cur != NULL) {
54 cur = ll_advance(cur); 53 cur = ll_advance(cur);
55 i < index ? i++ : i--; 54 i < index ? i++ : i--;
56 } 55 }
57 return (void *) cur; 56 return (void *) cur;
58 } 57 }
59 58
60 ssize_t cx_linked_list_find( 59 ssize_t cx_linked_list_find(
61 void const *start, 60 const void *start,
62 ptrdiff_t loc_advance, 61 ptrdiff_t loc_advance,
63 ptrdiff_t loc_data, 62 ptrdiff_t loc_data,
64 cx_compare_func cmp_func, 63 cx_compare_func cmp_func,
65 void const *elem 64 const void *elem
66 ) { 65 ) {
67 void *dummy; 66 void *dummy;
68 return cx_linked_list_find_node( 67 return cx_linked_list_find_node(
69 &dummy, start, 68 &dummy, start,
70 loc_advance, loc_data, 69 loc_advance, loc_data,
72 ); 71 );
73 } 72 }
74 73
75 ssize_t cx_linked_list_find_node( 74 ssize_t cx_linked_list_find_node(
76 void **result, 75 void **result,
77 void const *start, 76 const void *start,
78 ptrdiff_t loc_advance, 77 ptrdiff_t loc_advance,
79 ptrdiff_t loc_data, 78 ptrdiff_t loc_data,
80 cx_compare_func cmp_func, 79 cx_compare_func cmp_func,
81 void const *elem 80 const void *elem
82 ) { 81 ) {
83 assert(result != NULL); 82 assert(result != NULL);
84 assert(start != NULL); 83 assert(start != NULL);
85 assert(loc_advance >= 0); 84 assert(loc_advance >= 0);
86 assert(loc_data >= 0); 85 assert(loc_data >= 0);
87 assert(cmp_func); 86 assert(cmp_func);
88 87
89 void const *node = start; 88 const void *node = start;
90 ssize_t index = 0; 89 ssize_t index = 0;
91 do { 90 do {
92 void *current = ll_data(node); 91 void *current = ll_data(node);
93 if (cmp_func(current, elem) == 0) { 92 if (cmp_func(current, elem) == 0) {
94 *result = (void*) node; 93 *result = (void *) node;
95 return index; 94 return index;
96 } 95 }
97 node = ll_advance(node); 96 node = ll_advance(node);
98 index++; 97 index++;
99 } while (node != NULL); 98 } while (node != NULL);
100 *result = NULL; 99 *result = NULL;
101 return -1; 100 return -1;
102 } 101 }
103 102
104 void *cx_linked_list_first( 103 void *cx_linked_list_first(
105 void const *node, 104 const void *node,
106 ptrdiff_t loc_prev 105 ptrdiff_t loc_prev
107 ) { 106 ) {
108 return cx_linked_list_last(node, loc_prev); 107 return cx_linked_list_last(node, loc_prev);
109 } 108 }
110 109
111 void *cx_linked_list_last( 110 void *cx_linked_list_last(
112 void const *node, 111 const void *node,
113 ptrdiff_t loc_next 112 ptrdiff_t loc_next
114 ) { 113 ) {
115 assert(node != NULL); 114 assert(node != NULL);
116 assert(loc_next >= 0); 115 assert(loc_next >= 0);
117 116
118 void const *cur = node; 117 const void *cur = node;
119 void const *last; 118 const void *last;
120 do { 119 do {
121 last = cur; 120 last = cur;
122 } while ((cur = ll_next(cur)) != NULL); 121 } while ((cur = ll_next(cur)) != NULL);
123 122
124 return (void *) last; 123 return (void *) last;
125 } 124 }
126 125
127 void *cx_linked_list_prev( 126 void *cx_linked_list_prev(
128 void const *begin, 127 const void *begin,
129 ptrdiff_t loc_next, 128 ptrdiff_t loc_next,
130 void const *node 129 const void *node
131 ) { 130 ) {
132 assert(begin != NULL); 131 assert(begin != NULL);
133 assert(node != NULL); 132 assert(node != NULL);
134 assert(loc_next >= 0); 133 assert(loc_next >= 0);
135 if (begin == node) return NULL; 134 if (begin == node) return NULL;
136 void const *cur = begin; 135 const void *cur = begin;
137 void const *next; 136 const void *next;
138 while (1) { 137 while (1) {
139 next = ll_next(cur); 138 next = ll_next(cur);
140 if (next == node) return (void *) cur; 139 if (next == node) return (void *) cur;
141 cur = next; 140 cur = next;
142 } 141 }
245 } else { 244 } else {
246 cx_linked_list_link(insert_end, successor, loc_prev, loc_next); 245 cx_linked_list_link(insert_end, successor, loc_prev, loc_next);
247 } 246 }
248 } 247 }
249 248
250 void cx_linked_list_remove( 249 void cx_linked_list_insert_sorted(
251 void **begin, 250 void **begin,
252 void **end, 251 void **end,
253 ptrdiff_t loc_prev, 252 ptrdiff_t loc_prev,
254 ptrdiff_t loc_next, 253 ptrdiff_t loc_next,
255 void *node 254 void *new_node,
255 cx_compare_func cmp_func
256 ) {
257 assert(ll_next(new_node) == NULL);
258 cx_linked_list_insert_sorted_chain(
259 begin, end, loc_prev, loc_next, new_node, cmp_func);
260 }
261
262 void cx_linked_list_insert_sorted_chain(
263 void **begin,
264 void **end,
265 ptrdiff_t loc_prev,
266 ptrdiff_t loc_next,
267 void *insert_begin,
268 cx_compare_func cmp_func
269 ) {
270 assert(begin != NULL);
271 assert(loc_next >= 0);
272 assert(insert_begin != NULL);
273
274 // track currently observed nodes
275 void *dest_prev = NULL;
276 void *dest = *begin;
277 void *src = insert_begin;
278
279 // special case: list is empty
280 if (dest == NULL) {
281 *begin = src;
282 if (end != NULL) {
283 *end = cx_linked_list_last(src, loc_next);
284 }
285 return;
286 }
287
288 // search the list for insertion points
289 while (dest != NULL && src != NULL) {
290 // compare current list node with source node
291 // if less or equal, skip
292 if (cmp_func(dest, src) <= 0) {
293 dest_prev = dest;
294 dest = ll_next(dest);
295 continue;
296 }
297
298 // determine chain of elements that can be inserted
299 void *end_of_chain = src;
300 void *next_in_chain = ll_next(src);
301 while (next_in_chain != NULL) {
302 // once we become larger than the list elem, break
303 if (cmp_func(dest, next_in_chain) <= 0) {
304 break;
305 }
306 // otherwise, we can insert one more
307 end_of_chain = next_in_chain;
308 next_in_chain = ll_next(next_in_chain);
309 }
310
311 // insert the elements
312 if (dest_prev == NULL) {
313 // new begin
314 *begin = src;
315 } else {
316 cx_linked_list_link(dest_prev, src, loc_prev, loc_next);
317 }
318 cx_linked_list_link(end_of_chain, dest, loc_prev, loc_next);
319
320 // continue with next
321 src = next_in_chain;
322 dest_prev = dest;
323 dest = ll_next(dest);
324 }
325
326 // insert remaining items
327 if (src != NULL) {
328 cx_linked_list_link(dest_prev, src, loc_prev, loc_next);
329 }
330
331 // determine new end of list, if requested
332 if (end != NULL) {
333 *end = cx_linked_list_last(
334 dest != NULL ? dest : dest_prev, loc_next);
335 }
336 }
337
338 size_t cx_linked_list_remove_chain(
339 void **begin,
340 void **end,
341 ptrdiff_t loc_prev,
342 ptrdiff_t loc_next,
343 void *node,
344 size_t num
256 ) { 345 ) {
257 assert(node != NULL); 346 assert(node != NULL);
258 assert(loc_next >= 0); 347 assert(loc_next >= 0);
259 assert(loc_prev >= 0 || begin != NULL); 348 assert(loc_prev >= 0 || begin != NULL);
260 349
350 // easy exit
351 if (num == 0) return 0;
352
261 // find adjacent nodes 353 // find adjacent nodes
262 void *next = ll_next(node);
263 void *prev; 354 void *prev;
264 if (loc_prev >= 0) { 355 if (loc_prev >= 0) {
265 prev = ll_prev(node); 356 prev = ll_prev(node);
266 } else { 357 } else {
267 prev = cx_linked_list_prev(*begin, loc_next, node); 358 prev = cx_linked_list_prev(*begin, loc_next, node);
359 }
360
361 void *next = ll_next(node);
362 size_t removed = 1;
363 for (; removed < num && next != NULL ; removed++) {
364 next = ll_next(next);
268 } 365 }
269 366
270 // update next pointer of prev node, or set begin 367 // update next pointer of prev node, or set begin
271 if (prev == NULL) { 368 if (prev == NULL) {
272 if (begin != NULL) { 369 if (begin != NULL) {
282 *end = prev; 379 *end = prev;
283 } 380 }
284 } else if (loc_prev >= 0) { 381 } else if (loc_prev >= 0) {
285 ll_prev(next) = prev; 382 ll_prev(next) = prev;
286 } 383 }
384
385 return removed;
287 } 386 }
288 387
289 size_t cx_linked_list_size( 388 size_t cx_linked_list_size(
290 void const *node, 389 const void *node,
291 ptrdiff_t loc_next 390 ptrdiff_t loc_next
292 ) { 391 ) {
293 assert(loc_next >= 0); 392 assert(loc_next >= 0);
294 size_t size = 0; 393 size_t size = 0;
295 while (node != NULL) { 394 while (node != NULL) {
345 n++; 444 n++;
346 } 445 }
347 446
348 // Update pointer 447 // Update pointer
349 if (loc_prev >= 0) ll_prev(sorted[0]) = NULL; 448 if (loc_prev >= 0) ll_prev(sorted[0]) = NULL;
350 cx_for_n (i, length - 1) { 449 for (size_t i = 0 ; i < length - 1; i++) {
351 cx_linked_list_link(sorted[i], sorted[i + 1], loc_prev, loc_next); 450 cx_linked_list_link(sorted[i], sorted[i + 1], loc_prev, loc_next);
352 } 451 }
353 ll_next(sorted[length - 1]) = NULL; 452 ll_next(sorted[length - 1]) = NULL;
354 453
355 *begin = sorted[0]; 454 *begin = sorted[0];
356 *end = sorted[length-1]; 455 *end = sorted[length - 1];
357 if (sorted != sbo) { 456 if (sorted != sbo) {
358 free(sorted); 457 free(sorted);
359 } 458 }
360 } 459 }
361 460
423 if (end) *end = sorted_end; 522 if (end) *end = sorted_end;
424 } 523 }
425 } 524 }
426 525
427 int cx_linked_list_compare( 526 int cx_linked_list_compare(
428 void const *begin_left, 527 const void *begin_left,
429 void const *begin_right, 528 const void *begin_right,
430 ptrdiff_t loc_advance, 529 ptrdiff_t loc_advance,
431 ptrdiff_t loc_data, 530 ptrdiff_t loc_data,
432 cx_compare_func cmp_func 531 cx_compare_func cmp_func
433 ) { 532 ) {
434 void const *left = begin_left, *right = begin_right; 533 const void *left = begin_left, *right = begin_right;
435 534
436 while (left != NULL && right != NULL) { 535 while (left != NULL && right != NULL) {
437 void const *left_data = ll_data(left); 536 const void *left_data = ll_data(left);
438 void const *right_data = ll_data(right); 537 const void *right_data = ll_data(right);
439 int result = cmp_func(left_data, right_data); 538 int result = cmp_func(left_data, right_data);
440 if (result != 0) return result; 539 if (result != 0) return result;
441 left = ll_advance(left); 540 left = ll_advance(left);
442 right = ll_advance(right); 541 right = ll_advance(right);
443 } 542 }
496 cx_linked_list_node *begin; 595 cx_linked_list_node *begin;
497 cx_linked_list_node *end; 596 cx_linked_list_node *end;
498 } cx_linked_list; 597 } cx_linked_list;
499 598
500 static cx_linked_list_node *cx_ll_node_at( 599 static cx_linked_list_node *cx_ll_node_at(
501 cx_linked_list const *list, 600 const cx_linked_list *list,
502 size_t index 601 size_t index
503 ) { 602 ) {
504 if (index >= list->base.collection.size) { 603 if (index >= list->base.collection.size) {
505 return NULL; 604 return NULL;
506 } else if (index > list->base.collection.size / 2) { 605 } else if (index > list->base.collection.size / 2) {
508 } else { 607 } else {
509 return cx_linked_list_at(list->begin, 0, CX_LL_LOC_NEXT, index); 608 return cx_linked_list_at(list->begin, 0, CX_LL_LOC_NEXT, index);
510 } 609 }
511 } 610 }
512 611
612 static cx_linked_list_node *cx_ll_malloc_node(const struct cx_list_s *list) {
613 return cxMalloc(list->collection.allocator,
614 sizeof(cx_linked_list_node) + list->collection.elem_size);
615 }
616
513 static int cx_ll_insert_at( 617 static int cx_ll_insert_at(
514 struct cx_list_s *list, 618 struct cx_list_s *list,
515 cx_linked_list_node *node, 619 cx_linked_list_node *node,
516 void const *elem 620 const void *elem
517 ) { 621 ) {
518 622
519 // create the new new_node 623 // create the new new_node
520 cx_linked_list_node *new_node = cxMalloc(list->collection.allocator, 624 cx_linked_list_node *new_node = cx_ll_malloc_node(list);
521 sizeof(cx_linked_list_node) + list->collection.elem_size);
522 625
523 // sortir if failed 626 // sortir if failed
524 if (new_node == NULL) return 1; 627 if (new_node == NULL) return 1;
525 628
526 // initialize new new_node 629 // initialize new new_node
541 } 644 }
542 645
543 static size_t cx_ll_insert_array( 646 static size_t cx_ll_insert_array(
544 struct cx_list_s *list, 647 struct cx_list_s *list,
545 size_t index, 648 size_t index,
546 void const *array, 649 const void *array,
547 size_t n 650 size_t n
548 ) { 651 ) {
549 // out-of bounds and corner case check 652 // out-of bounds and corner case check
550 if (index > list->collection.size || n == 0) return 0; 653 if (index > list->collection.size || n == 0) return 0;
551 654
552 // find position efficiently 655 // find position efficiently
553 cx_linked_list_node *node = index == 0 ? NULL : cx_ll_node_at((cx_linked_list *) list, index - 1); 656 cx_linked_list_node *node = index == 0 ? NULL : cx_ll_node_at((cx_linked_list *) list, index - 1);
554 657
555 // perform first insert 658 // perform first insert
556 if (0 != cx_ll_insert_at(list, node, array)) { 659 if (0 != cx_ll_insert_at(list, node, array)) return 1;
557 return 1;
558 }
559 660
560 // is there more? 661 // is there more?
561 if (n == 1) return 1; 662 if (n == 1) return 1;
562 663
563 // we now know exactly where we are 664 // we now know exactly where we are
564 node = node == NULL ? ((cx_linked_list *) list)->begin : node->next; 665 node = node == NULL ? ((cx_linked_list *) list)->begin : node->next;
565 666
566 // we can add the remaining nodes and immedately advance to the inserted node 667 // we can add the remaining nodes and immediately advance to the inserted node
567 char const *source = array; 668 const char *source = array;
568 for (size_t i = 1; i < n; i++) { 669 for (size_t i = 1; i < n; i++) {
569 source += list->collection.elem_size; 670 source += list->collection.elem_size;
570 if (0 != cx_ll_insert_at(list, node, source)) { 671 if (0 != cx_ll_insert_at(list, node, source)) return i;
571 return i;
572 }
573 node = node->next; 672 node = node->next;
574 } 673 }
575 return n; 674 return n;
576 } 675 }
577 676
578 static int cx_ll_insert_element( 677 static int cx_ll_insert_element(
579 struct cx_list_s *list, 678 struct cx_list_s *list,
580 size_t index, 679 size_t index,
581 void const *element 680 const void *element
582 ) { 681 ) {
583 return 1 != cx_ll_insert_array(list, index, element, 1); 682 return 1 != cx_ll_insert_array(list, index, element, 1);
584 } 683 }
585 684
586 static int cx_ll_remove( 685 static _Thread_local cx_compare_func cx_ll_insert_sorted_cmp_func;
686
687 static int cx_ll_insert_sorted_cmp_helper(const void *l, const void *r) {
688 const cx_linked_list_node *left = l;
689 const cx_linked_list_node *right = r;
690 return cx_ll_insert_sorted_cmp_func(left->payload, right->payload);
691 }
692
693 static size_t cx_ll_insert_sorted(
587 struct cx_list_s *list, 694 struct cx_list_s *list,
588 size_t index 695 const void *array,
696 size_t n
697 ) {
698 // special case
699 if (n == 0) return 0;
700
701 // create a new chain of nodes
702 cx_linked_list_node *chain = cx_ll_malloc_node(list);
703 if (chain == NULL) return 0;
704
705 memcpy(chain->payload, array, list->collection.elem_size);
706 chain->prev = NULL;
707 chain->next = NULL;
708
709 // add all elements from the array to that chain
710 cx_linked_list_node *prev = chain;
711 const char *src = array;
712 size_t inserted = 1;
713 for (; inserted < n; inserted++) {
714 cx_linked_list_node *next = cx_ll_malloc_node(list);
715 if (next == NULL) break;
716 src += list->collection.elem_size;
717 memcpy(next->payload, src, list->collection.elem_size);
718 prev->next = next;
719 next->prev = prev;
720 prev = next;
721 }
722 prev->next = NULL;
723
724 // invoke the low level function
725 cx_linked_list *ll = (cx_linked_list *) list;
726 cx_ll_insert_sorted_cmp_func = list->collection.cmpfunc;
727 cx_linked_list_insert_sorted_chain(
728 (void **) &ll->begin,
729 (void **) &ll->end,
730 CX_LL_LOC_PREV,
731 CX_LL_LOC_NEXT,
732 chain,
733 cx_ll_insert_sorted_cmp_helper
734 );
735
736 // adjust the list metadata
737 list->collection.size += inserted;
738
739 return inserted;
740 }
741
742 static size_t cx_ll_remove(
743 struct cx_list_s *list,
744 size_t index,
745 size_t num,
746 void *targetbuf
589 ) { 747 ) {
590 cx_linked_list *ll = (cx_linked_list *) list; 748 cx_linked_list *ll = (cx_linked_list *) list;
591 cx_linked_list_node *node = cx_ll_node_at(ll, index); 749 cx_linked_list_node *node = cx_ll_node_at(ll, index);
592 750
593 // out-of-bounds check 751 // out-of-bounds check
594 if (node == NULL) return 1; 752 if (node == NULL) return 0;
595
596 // element destruction
597 cx_invoke_destructor(list, node->payload);
598 753
599 // remove 754 // remove
600 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, 755 size_t removed = cx_linked_list_remove_chain(
601 CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); 756 (void **) &ll->begin,
757 (void **) &ll->end,
758 CX_LL_LOC_PREV,
759 CX_LL_LOC_NEXT,
760 node,
761 num
762 );
602 763
603 // adjust size 764 // adjust size
604 list->collection.size--; 765 list->collection.size -= removed;
605 766
606 // free and return 767 // copy or destroy the removed chain
607 cxFree(list->collection.allocator, node); 768 if (targetbuf == NULL) {
608 769 cx_linked_list_node *n = node;
609 return 0; 770 for (size_t i = 0; i < removed; i++) {
771 // element destruction
772 cx_invoke_destructor(list, n->payload);
773
774 // free the node and advance
775 void *next = n->next;
776 cxFree(list->collection.allocator, n);
777 n = next;
778 }
779 } else {
780 char *dest = targetbuf;
781 cx_linked_list_node *n = node;
782 for (size_t i = 0; i < removed; i++) {
783 // copy payload
784 memcpy(dest, n->payload, list->collection.elem_size);
785
786 // advance target buffer
787 dest += list->collection.elem_size;
788
789 // free the node and advance
790 void *next = n->next;
791 cxFree(list->collection.allocator, n);
792 n = next;
793 }
794 }
795
796 return removed;
610 } 797 }
611 798
612 static void cx_ll_clear(struct cx_list_s *list) { 799 static void cx_ll_clear(struct cx_list_s *list) {
613 if (list->collection.size == 0) return; 800 if (list->collection.size == 0) return;
614 801
625 } 812 }
626 813
627 #ifndef CX_LINKED_LIST_SWAP_SBO_SIZE 814 #ifndef CX_LINKED_LIST_SWAP_SBO_SIZE
628 #define CX_LINKED_LIST_SWAP_SBO_SIZE 128 815 #define CX_LINKED_LIST_SWAP_SBO_SIZE 128
629 #endif 816 #endif
630 unsigned cx_linked_list_swap_sbo_size = CX_LINKED_LIST_SWAP_SBO_SIZE; 817 const unsigned cx_linked_list_swap_sbo_size = CX_LINKED_LIST_SWAP_SBO_SIZE;
631 818
632 static int cx_ll_swap( 819 static int cx_ll_swap(
633 struct cx_list_s *list, 820 struct cx_list_s *list,
634 size_t i, 821 size_t i,
635 size_t j 822 size_t j
646 right = j; 833 right = j;
647 } else { 834 } else {
648 left = j; 835 left = j;
649 right = i; 836 right = i;
650 } 837 }
651 cx_linked_list_node *nleft, *nright; 838 cx_linked_list_node *nleft = NULL, *nright = NULL;
652 if (left < mid && right < mid) { 839 if (left < mid && right < mid) {
653 // case 1: both items left from mid 840 // case 1: both items left from mid
654 nleft = cx_ll_node_at(ll, left); 841 nleft = cx_ll_node_at(ll, left);
655 assert(nleft != NULL); 842 assert(nleft != NULL);
656 nright = nleft; 843 nright = nleft;
746 933
747 return 0; 934 return 0;
748 } 935 }
749 936
750 static void *cx_ll_at( 937 static void *cx_ll_at(
751 struct cx_list_s const *list, 938 const struct cx_list_s *list,
752 size_t index 939 size_t index
753 ) { 940 ) {
754 cx_linked_list *ll = (cx_linked_list *) list; 941 cx_linked_list *ll = (cx_linked_list *) list;
755 cx_linked_list_node *node = cx_ll_node_at(ll, index); 942 cx_linked_list_node *node = cx_ll_node_at(ll, index);
756 return node == NULL ? NULL : node->payload; 943 return node == NULL ? NULL : node->payload;
757 } 944 }
758 945
759 static ssize_t cx_ll_find_remove( 946 static ssize_t cx_ll_find_remove(
760 struct cx_list_s *list, 947 struct cx_list_s *list,
761 void const *elem, 948 const void *elem,
762 bool remove 949 bool remove
763 ) { 950 ) {
764 if (remove) { 951 if (remove) {
765 cx_linked_list *ll = ((cx_linked_list *) list); 952 cx_linked_list *ll = ((cx_linked_list *) list);
766 cx_linked_list_node *node; 953 cx_linked_list_node *node;
798 cx_linked_list *ll = (cx_linked_list *) list; 985 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); 986 cx_linked_list_reverse((void **) &ll->begin, (void **) &ll->end, CX_LL_LOC_PREV, CX_LL_LOC_NEXT);
800 } 987 }
801 988
802 static int cx_ll_compare( 989 static int cx_ll_compare(
803 struct cx_list_s const *list, 990 const struct cx_list_s *list,
804 struct cx_list_s const *other 991 const struct cx_list_s *other
805 ) { 992 ) {
806 cx_linked_list *left = (cx_linked_list *) list; 993 cx_linked_list *left = (cx_linked_list *) list;
807 cx_linked_list *right = (cx_linked_list *) other; 994 cx_linked_list *right = (cx_linked_list *) other;
808 return cx_linked_list_compare(left->begin, right->begin, 995 return cx_linked_list_compare(left->begin, right->begin,
809 CX_LL_LOC_NEXT, CX_LL_LOC_DATA, 996 CX_LL_LOC_NEXT, CX_LL_LOC_DATA,
810 list->collection.cmpfunc); 997 list->collection.cmpfunc);
811 } 998 }
812 999
813 static bool cx_ll_iter_valid(void const *it) { 1000 static bool cx_ll_iter_valid(const void *it) {
814 struct cx_iterator_s const *iter = it; 1001 const struct cx_iterator_s *iter = it;
815 return iter->elem_handle != NULL; 1002 return iter->elem_handle != NULL;
816 } 1003 }
817 1004
818 static void cx_ll_iter_next(void *it) { 1005 static void cx_ll_iter_next(void *it) {
819 struct cx_iterator_s *iter = it; 1006 struct cx_iterator_s *iter = it;
854 cx_linked_list_node *node = iter->elem_handle; 1041 cx_linked_list_node *node = iter->elem_handle;
855 iter->elem_handle = node->prev; 1042 iter->elem_handle = node->prev;
856 } 1043 }
857 } 1044 }
858 1045
859 static void *cx_ll_iter_current(void const *it) { 1046 static void *cx_ll_iter_current(const void *it) {
860 struct cx_iterator_s const *iter = it; 1047 const struct cx_iterator_s *iter = it;
861 cx_linked_list_node *node = iter->elem_handle; 1048 cx_linked_list_node *node = iter->elem_handle;
862 return node->payload; 1049 return node->payload;
863 } 1050 }
864 1051
865 static CxIterator cx_ll_iterator( 1052 static CxIterator cx_ll_iterator(
866 struct cx_list_s const *list, 1053 const struct cx_list_s *list,
867 size_t index, 1054 size_t index,
868 bool backwards 1055 bool backwards
869 ) { 1056 ) {
870 CxIterator iter; 1057 CxIterator iter;
871 iter.index = index; 1058 iter.index = index;
872 iter.src_handle.c = list; 1059 iter.src_handle.c = list;
873 iter.elem_handle = cx_ll_node_at((cx_linked_list const *) list, index); 1060 iter.elem_handle = cx_ll_node_at((const cx_linked_list *) list, index);
874 iter.elem_size = list->collection.elem_size; 1061 iter.elem_size = list->collection.elem_size;
875 iter.elem_count = list->collection.size; 1062 iter.elem_count = list->collection.size;
876 iter.base.valid = cx_ll_iter_valid; 1063 iter.base.valid = cx_ll_iter_valid;
877 iter.base.current = cx_ll_iter_current; 1064 iter.base.current = cx_ll_iter_current;
878 iter.base.next = backwards ? cx_ll_iter_prev : cx_ll_iter_next; 1065 iter.base.next = backwards ? cx_ll_iter_prev : cx_ll_iter_next;
881 return iter; 1068 return iter;
882 } 1069 }
883 1070
884 static int cx_ll_insert_iter( 1071 static int cx_ll_insert_iter(
885 CxIterator *iter, 1072 CxIterator *iter,
886 void const *elem, 1073 const void *elem,
887 int prepend 1074 int prepend
888 ) { 1075 ) {
889 struct cx_list_s *list = iter->src_handle.m; 1076 struct cx_list_s *list = iter->src_handle.m;
890 cx_linked_list_node *node = iter->elem_handle; 1077 cx_linked_list_node *node = iter->elem_handle;
891 if (node != NULL) { 1078 if (node != NULL) {
892 assert(prepend >= 0 && prepend <= 1); 1079 assert(prepend >= 0 && prepend <= 1);
893 cx_linked_list_node *choice[2] = {node, node->prev}; 1080 cx_linked_list_node *choice[2] = {node, node->prev};
894 int result = cx_ll_insert_at(list, choice[prepend], elem); 1081 int result = cx_ll_insert_at(list, choice[prepend], elem);
895 iter->index += prepend * (0 == result); 1082 if (result == 0) {
1083 iter->elem_count++;
1084 if (prepend) {
1085 iter->index++;
1086 }
1087 }
896 return result; 1088 return result;
897 } else { 1089 } else {
898 int result = cx_ll_insert_element(list, list->collection.size, elem); 1090 int result = cx_ll_insert_element(list, list->collection.size, elem);
899 iter->index = list->collection.size; 1091 if (result == 0) {
1092 iter->elem_count++;
1093 iter->index = list->collection.size;
1094 }
900 return result; 1095 return result;
901 } 1096 }
902 } 1097 }
903 1098
904 static void cx_ll_destructor(CxList *list) { 1099 static void cx_ll_destructor(CxList *list) {
917 1112
918 static cx_list_class cx_linked_list_class = { 1113 static cx_list_class cx_linked_list_class = {
919 cx_ll_destructor, 1114 cx_ll_destructor,
920 cx_ll_insert_element, 1115 cx_ll_insert_element,
921 cx_ll_insert_array, 1116 cx_ll_insert_array,
1117 cx_ll_insert_sorted,
922 cx_ll_insert_iter, 1118 cx_ll_insert_iter,
923 cx_ll_remove, 1119 cx_ll_remove,
924 cx_ll_clear, 1120 cx_ll_clear,
925 cx_ll_swap, 1121 cx_ll_swap,
926 cx_ll_at, 1122 cx_ll_at,
930 cx_ll_reverse, 1126 cx_ll_reverse,
931 cx_ll_iterator, 1127 cx_ll_iterator,
932 }; 1128 };
933 1129
934 CxList *cxLinkedListCreate( 1130 CxList *cxLinkedListCreate(
935 CxAllocator const *allocator, 1131 const CxAllocator *allocator,
936 cx_compare_func comparator, 1132 cx_compare_func comparator,
937 size_t elem_size 1133 size_t elem_size
938 ) { 1134 ) {
939 if (allocator == NULL) { 1135 if (allocator == NULL) {
940 allocator = cxDefaultAllocator; 1136 allocator = cxDefaultAllocator;

mercurial