ucx/linked_list.c

changeset 101
7b3a3130be44
parent 49
2f71f4ee247a
equal deleted inserted replaced
100:d2bd73d28ff1 101:7b3a3130be44
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
89 const void *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);
334 *end = cx_linked_list_last( 333 *end = cx_linked_list_last(
335 dest != NULL ? dest : dest_prev, loc_next); 334 dest != NULL ? dest : dest_prev, loc_next);
336 } 335 }
337 } 336 }
338 337
339 void cx_linked_list_remove( 338 size_t cx_linked_list_remove_chain(
340 void **begin, 339 void **begin,
341 void **end, 340 void **end,
342 ptrdiff_t loc_prev, 341 ptrdiff_t loc_prev,
343 ptrdiff_t loc_next, 342 ptrdiff_t loc_next,
344 void *node 343 void *node,
344 size_t num
345 ) { 345 ) {
346 assert(node != NULL); 346 assert(node != NULL);
347 assert(loc_next >= 0); 347 assert(loc_next >= 0);
348 assert(loc_prev >= 0 || begin != NULL); 348 assert(loc_prev >= 0 || begin != NULL);
349 349
350 // easy exit
351 if (num == 0) return 0;
352
350 // find adjacent nodes 353 // find adjacent nodes
351 void *next = ll_next(node);
352 void *prev; 354 void *prev;
353 if (loc_prev >= 0) { 355 if (loc_prev >= 0) {
354 prev = ll_prev(node); 356 prev = ll_prev(node);
355 } else { 357 } else {
356 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);
357 } 365 }
358 366
359 // update next pointer of prev node, or set begin 367 // update next pointer of prev node, or set begin
360 if (prev == NULL) { 368 if (prev == NULL) {
361 if (begin != NULL) { 369 if (begin != NULL) {
371 *end = prev; 379 *end = prev;
372 } 380 }
373 } else if (loc_prev >= 0) { 381 } else if (loc_prev >= 0) {
374 ll_prev(next) = prev; 382 ll_prev(next) = prev;
375 } 383 }
384
385 return removed;
376 } 386 }
377 387
378 size_t cx_linked_list_size( 388 size_t cx_linked_list_size(
379 const void *node, 389 const void *node,
380 ptrdiff_t loc_next 390 ptrdiff_t loc_next
434 n++; 444 n++;
435 } 445 }
436 446
437 // Update pointer 447 // Update pointer
438 if (loc_prev >= 0) ll_prev(sorted[0]) = NULL; 448 if (loc_prev >= 0) ll_prev(sorted[0]) = NULL;
439 cx_for_n (i, length - 1) { 449 for (size_t i = 0 ; i < length - 1; i++) {
440 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);
441 } 451 }
442 ll_next(sorted[length - 1]) = NULL; 452 ll_next(sorted[length - 1]) = NULL;
443 453
444 *begin = sorted[0]; 454 *begin = sorted[0];
445 *end = sorted[length-1]; 455 *end = sorted[length - 1];
446 if (sorted != sbo) { 456 if (sorted != sbo) {
447 free(sorted); 457 free(sorted);
448 } 458 }
449 } 459 }
450 460
644 654
645 // find position efficiently 655 // find position efficiently
646 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);
647 657
648 // perform first insert 658 // perform first insert
649 if (0 != cx_ll_insert_at(list, node, array)) { 659 if (0 != cx_ll_insert_at(list, node, array)) return 1;
650 return 1;
651 }
652 660
653 // is there more? 661 // is there more?
654 if (n == 1) return 1; 662 if (n == 1) return 1;
655 663
656 // we now know exactly where we are 664 // we now know exactly where we are
658 666
659 // we can add the remaining nodes and immediately advance to the inserted node 667 // we can add the remaining nodes and immediately advance to the inserted node
660 const char *source = array; 668 const char *source = array;
661 for (size_t i = 1; i < n; i++) { 669 for (size_t i = 1; i < n; i++) {
662 source += list->collection.elem_size; 670 source += list->collection.elem_size;
663 if (0 != cx_ll_insert_at(list, node, source)) { 671 if (0 != cx_ll_insert_at(list, node, source)) return i;
664 return i;
665 }
666 node = node->next; 672 node = node->next;
667 } 673 }
668 return n; 674 return n;
669 } 675 }
670 676
731 list->collection.size += inserted; 737 list->collection.size += inserted;
732 738
733 return inserted; 739 return inserted;
734 } 740 }
735 741
736 static int cx_ll_remove( 742 static size_t cx_ll_remove(
737 struct cx_list_s *list, 743 struct cx_list_s *list,
738 size_t index 744 size_t index,
745 size_t num,
746 void *targetbuf
739 ) { 747 ) {
740 cx_linked_list *ll = (cx_linked_list *) list; 748 cx_linked_list *ll = (cx_linked_list *) list;
741 cx_linked_list_node *node = cx_ll_node_at(ll, index); 749 cx_linked_list_node *node = cx_ll_node_at(ll, index);
742 750
743 // out-of-bounds check 751 // out-of-bounds check
744 if (node == NULL) return 1; 752 if (node == NULL) return 0;
745
746 // element destruction
747 cx_invoke_destructor(list, node->payload);
748 753
749 // remove 754 // remove
750 cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, 755 size_t removed = cx_linked_list_remove_chain(
751 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 );
752 763
753 // adjust size 764 // adjust size
754 list->collection.size--; 765 list->collection.size -= removed;
755 766
756 // free and return 767 // copy or destroy the removed chain
757 cxFree(list->collection.allocator, node); 768 if (targetbuf == NULL) {
758 769 cx_linked_list_node *n = node;
759 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;
760 } 797 }
761 798
762 static void cx_ll_clear(struct cx_list_s *list) { 799 static void cx_ll_clear(struct cx_list_s *list) {
763 if (list->collection.size == 0) return; 800 if (list->collection.size == 0) return;
764 801
775 } 812 }
776 813
777 #ifndef CX_LINKED_LIST_SWAP_SBO_SIZE 814 #ifndef CX_LINKED_LIST_SWAP_SBO_SIZE
778 #define CX_LINKED_LIST_SWAP_SBO_SIZE 128 815 #define CX_LINKED_LIST_SWAP_SBO_SIZE 128
779 #endif 816 #endif
780 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;
781 818
782 static int cx_ll_swap( 819 static int cx_ll_swap(
783 struct cx_list_s *list, 820 struct cx_list_s *list,
784 size_t i, 821 size_t i,
785 size_t j 822 size_t j
796 right = j; 833 right = j;
797 } else { 834 } else {
798 left = j; 835 left = j;
799 right = i; 836 right = i;
800 } 837 }
801 cx_linked_list_node *nleft, *nright; 838 cx_linked_list_node *nleft = NULL, *nright = NULL;
802 if (left < mid && right < mid) { 839 if (left < mid && right < mid) {
803 // case 1: both items left from mid 840 // case 1: both items left from mid
804 nleft = cx_ll_node_at(ll, left); 841 nleft = cx_ll_node_at(ll, left);
805 assert(nleft != NULL); 842 assert(nleft != NULL);
806 nright = nleft; 843 nright = nleft;

mercurial