571 // adjust size |
573 // adjust size |
572 list->size--; |
574 list->size--; |
573 |
575 |
574 // free and return |
576 // free and return |
575 cxFree(list->allocator, node); |
577 cxFree(list->allocator, node); |
|
578 |
|
579 return 0; |
|
580 } |
|
581 |
|
582 #ifndef CX_LINKED_LIST_SWAP_SBO_SIZE |
|
583 #define CX_LINKED_LIST_SWAP_SBO_SIZE 16 |
|
584 #endif |
|
585 |
|
586 static int cx_ll_swap( |
|
587 struct cx_list_s *list, |
|
588 size_t i, |
|
589 size_t j |
|
590 ) { |
|
591 if (i >= list->size || j >= list->size) return 1; |
|
592 if (i == j) return 0; |
|
593 |
|
594 // perform an optimized search that finds both elements in one run |
|
595 cx_linked_list *ll = (cx_linked_list *) list; |
|
596 size_t mid = list->size / 2; |
|
597 size_t left, right; |
|
598 if (i < j) { |
|
599 left = i; |
|
600 right = j; |
|
601 } else { |
|
602 left = j; |
|
603 right = i; |
|
604 } |
|
605 cx_linked_list_node *nleft, *nright; |
|
606 if (left < mid && right < mid) { |
|
607 // case 1: both items left from mid |
|
608 nleft = cx_ll_node_at(ll, left); |
|
609 nright = nleft; |
|
610 for (size_t c = left; c < right; c++) { |
|
611 nright = nright->next; |
|
612 } |
|
613 } else if (left >= mid && right >= mid) { |
|
614 // case 2: both items right from mid |
|
615 nright = cx_ll_node_at(ll, right); |
|
616 nleft = nright; |
|
617 for (size_t c = right; c > left; c--) { |
|
618 nleft = nleft->prev; |
|
619 } |
|
620 } else { |
|
621 // case 3: one item left, one item right |
|
622 |
|
623 // chose the closest to begin / end |
|
624 size_t closest; |
|
625 size_t other; |
|
626 size_t diff2boundary = list->size - right - 1; |
|
627 if (left <= diff2boundary) { |
|
628 closest = left; |
|
629 other = right; |
|
630 nleft = cx_ll_node_at(ll, left); |
|
631 } else { |
|
632 closest = right; |
|
633 other = left; |
|
634 diff2boundary = left; |
|
635 nright = cx_ll_node_at(ll, right); |
|
636 } |
|
637 |
|
638 // is other element closer to us or closer to boundary? |
|
639 if (right - left <= diff2boundary) { |
|
640 // search other element starting from already found element |
|
641 if (closest == left) { |
|
642 nright = nleft; |
|
643 for (size_t c = left; c < right; c++) { |
|
644 nright = nright->next; |
|
645 } |
|
646 } else { |
|
647 nleft = nright; |
|
648 for (size_t c = right; c > left; c--) { |
|
649 nleft = nleft->prev; |
|
650 } |
|
651 } |
|
652 } else { |
|
653 // search other element starting at the boundary |
|
654 if (closest == left) { |
|
655 nright = cx_ll_node_at(ll, other); |
|
656 } else { |
|
657 nleft = cx_ll_node_at(ll, other); |
|
658 } |
|
659 } |
|
660 } |
|
661 |
|
662 if (list->itemsize > CX_LINKED_LIST_SWAP_SBO_SIZE || CX_DISABLE_LINKED_LIST_SWAP_SBO) { |
|
663 cx_linked_list_node *prev = nleft->prev; |
|
664 cx_linked_list_node *next = nright->next; |
|
665 cx_linked_list_node *midstart = nleft->next; |
|
666 cx_linked_list_node *midend = nright->prev; |
|
667 |
|
668 if (prev == NULL) { |
|
669 ll->begin = nright; |
|
670 } else { |
|
671 prev->next = nright; |
|
672 } |
|
673 nright->prev = prev; |
|
674 if (midstart == nright) { |
|
675 // special case: both nodes are adjacent |
|
676 nright->next = nleft; |
|
677 nleft->prev = nright; |
|
678 } else { |
|
679 // likely case: a chain is between the two nodes |
|
680 nright->next = midstart; |
|
681 midstart->prev = nright; |
|
682 midend->next = nleft; |
|
683 nleft->prev = midend; |
|
684 } |
|
685 nleft->next = next; |
|
686 if (next == NULL) { |
|
687 ll->end = nleft; |
|
688 } else { |
|
689 next->prev = nleft; |
|
690 } |
|
691 } else { |
|
692 // swap payloads to avoid relinking |
|
693 char buf[CX_LINKED_LIST_SWAP_SBO_SIZE]; |
|
694 memcpy(buf, nleft->payload, list->itemsize); |
|
695 memcpy(nleft->payload, nright->payload, list->itemsize); |
|
696 memcpy(nright->payload, buf, list->itemsize); |
|
697 } |
576 |
698 |
577 return 0; |
699 return 0; |
578 } |
700 } |
579 |
701 |
580 static void *cx_ll_at( |
702 static void *cx_ll_at( |