| 564 // lists are compatible |
566 // lists are compatible |
| 565 return list->cl->compare(list, other); |
567 return list->cl->compare(list, other); |
| 566 } |
568 } |
| 567 } |
569 } |
| 568 |
570 |
| 569 CxIterator cxListMutIteratorAt( |
571 size_t cxListSize(const CxList *list) { |
| 570 CxList *list, |
572 return list->collection.size; |
| 571 size_t index |
573 } |
| 572 ) { |
574 |
| 573 if (list == NULL) list = cxEmptyList; |
575 int cxListAdd(CxList *list, const void *elem) { |
| 574 CxIterator it = list->cl->iterator(list, index, false); |
576 list->collection.sorted = false; |
| 575 it.base.mutating = true; |
577 return list->cl->insert_element(list, list->collection.size, elem) == NULL; |
| 576 return it; |
578 } |
| 577 } |
579 |
| 578 |
580 size_t cxListAddArray(CxList *list, const void *array, size_t n) { |
| 579 CxIterator cxListMutBackwardsIteratorAt( |
581 list->collection.sorted = false; |
| 580 CxList *list, |
582 return list->cl->insert_array(list, list->collection.size, array, n); |
| 581 size_t index |
583 } |
| 582 ) { |
584 |
| 583 if (list == NULL) list = cxEmptyList; |
585 int cxListInsert(CxList *list, size_t index, const void *elem) { |
| 584 CxIterator it = list->cl->iterator(list, index, true); |
586 list->collection.sorted = false; |
| 585 it.base.mutating = true; |
587 return list->cl->insert_element(list, index, elem) == NULL; |
| 586 return it; |
588 } |
| 587 } |
589 |
| 588 |
590 void *cxListEmplaceAt(CxList *list, size_t index) { |
| 589 void cxListFree(CxList *list) { |
591 list->collection.sorted = false; |
| 590 if (list == NULL) return; |
592 return list->cl->insert_element(list, index, NULL); |
| 591 list->cl->deallocate(list); |
593 } |
| 592 } |
594 |
| 593 |
595 void *cxListEmplace(CxList *list) { |
| 594 int cxListSet( |
596 list->collection.sorted = false; |
| 595 CxList *list, |
597 return list->cl->insert_element(list, list->collection.size, NULL); |
| 596 size_t index, |
598 } |
| 597 const void *elem |
599 |
| 598 ) { |
600 static bool cx_list_emplace_iterator_valid(const void *it) { |
| |
601 const CxIterator *iter = it; |
| |
602 return iter->index < iter->elem_count; |
| |
603 } |
| |
604 |
| |
605 CxIterator cxListEmplaceArrayAt(CxList *list, size_t index, size_t n) { |
| |
606 list->collection.sorted = false; |
| |
607 size_t c = list->cl->insert_array(list, index, NULL, n); |
| |
608 CxIterator iter = list->cl->iterator(list, index, false); |
| |
609 // tweak the fields of this iterator |
| |
610 iter.elem_count = c; |
| |
611 iter.index = 0; |
| |
612 // replace the valid function to abort iteration when c is reached |
| |
613 iter.base.valid = cx_list_emplace_iterator_valid; |
| |
614 // if we are storing pointers, we want to return the pure pointers. |
| |
615 // therefore, we must unwrap the "current" method |
| |
616 if (list->collection.store_pointer) { |
| |
617 iter.base.current = iter.base.current_impl; |
| |
618 } |
| |
619 return iter; |
| |
620 } |
| |
621 |
| |
622 CxIterator cxListEmplaceArray(CxList *list, size_t n) { |
| |
623 return cxListEmplaceArrayAt(list, list->collection.size, n); |
| |
624 } |
| |
625 |
| |
626 int cxListInsertSorted(CxList *list, const void *elem) { |
| |
627 assert(cxCollectionSorted(list)); |
| |
628 list->collection.sorted = true; |
| |
629 const void *data = list->collection.store_pointer ? &elem : elem; |
| |
630 return list->cl->insert_sorted(list, data, 1) == 0; |
| |
631 } |
| |
632 |
| |
633 int cxListInsertUnique(CxList *list, const void *elem) { |
| |
634 if (cxCollectionSorted(list)) { |
| |
635 list->collection.sorted = true; |
| |
636 const void *data = list->collection.store_pointer ? &elem : elem; |
| |
637 return list->cl->insert_unique(list, data, 1) == 0; |
| |
638 } else { |
| |
639 if (cxListContains(list, elem)) { |
| |
640 return 0; |
| |
641 } else { |
| |
642 return cxListAdd(list, elem); |
| |
643 } |
| |
644 } |
| |
645 } |
| |
646 |
| |
647 size_t cxListInsertArray(CxList *list, size_t index, const void *array, size_t n) { |
| |
648 list->collection.sorted = false; |
| |
649 return list->cl->insert_array(list, index, array, n); |
| |
650 } |
| |
651 |
| |
652 size_t cxListInsertSortedArray(CxList *list, const void *array, size_t n) { |
| |
653 assert(cxCollectionSorted(list)); |
| |
654 list->collection.sorted = true; |
| |
655 return list->cl->insert_sorted(list, array, n); |
| |
656 } |
| |
657 |
| |
658 size_t cxListInsertUniqueArray(CxList *list, const void *array, size_t n) { |
| |
659 if (cxCollectionSorted(list)) { |
| |
660 list->collection.sorted = true; |
| |
661 return list->cl->insert_unique(list, array, n); |
| |
662 } else { |
| |
663 const char *source = array; |
| |
664 for (size_t i = 0 ; i < n; i++) { |
| |
665 // note: this also checks elements added in a previous iteration |
| |
666 const void *data = list->collection.store_pointer ? |
| |
667 *((const void**)source) : source; |
| |
668 if (!cxListContains(list, data)) { |
| |
669 if (cxListAdd(list, data)) { |
| |
670 return i; // LCOV_EXCL_LINE |
| |
671 } |
| |
672 } |
| |
673 source += list->collection.elem_size; |
| |
674 } |
| |
675 return n; |
| |
676 } |
| |
677 } |
| |
678 |
| |
679 int cxListInsertAfter(CxIterator *iter, const void *elem) { |
| |
680 CxList* list = (CxList*)iter->src_handle; |
| |
681 list->collection.sorted = false; |
| |
682 return list->cl->insert_iter(iter, elem, 0); |
| |
683 } |
| |
684 |
| |
685 int cxListInsertBefore(CxIterator *iter, const void *elem) { |
| |
686 CxList* list = (CxList*)iter->src_handle; |
| |
687 list->collection.sorted = false; |
| |
688 return list->cl->insert_iter(iter, elem, 1); |
| |
689 } |
| |
690 |
| |
691 int cxListRemove(CxList *list, size_t index) { |
| |
692 return list->cl->remove(list, index, 1, NULL) == 0; |
| |
693 } |
| |
694 |
| |
695 int cxListRemoveAndGet(CxList *list, size_t index, void *targetbuf) { |
| |
696 return list->cl->remove(list, index, 1, targetbuf) == 0; |
| |
697 } |
| |
698 |
| |
699 int cxListRemoveAndGetFirst(CxList *list, void *targetbuf) { |
| |
700 return list->cl->remove(list, 0, 1, targetbuf) == 0; |
| |
701 } |
| |
702 |
| |
703 int cxListRemoveAndGetLast(CxList *list, void *targetbuf) { |
| |
704 // note: index may wrap - member function will catch that |
| |
705 return list->cl->remove(list, list->collection.size - 1, 1, targetbuf) == 0; |
| |
706 } |
| |
707 |
| |
708 size_t cxListRemoveArray(CxList *list, size_t index, size_t num) { |
| |
709 return list->cl->remove(list, index, num, NULL); |
| |
710 } |
| |
711 |
| |
712 size_t cxListRemoveArrayAndGet(CxList *list, size_t index, size_t num, void *targetbuf) { |
| |
713 return list->cl->remove(list, index, num, targetbuf); |
| |
714 } |
| |
715 |
| |
716 void cxListClear(CxList *list) { |
| |
717 list->cl->clear(list); |
| |
718 list->collection.sorted = true; // empty lists are always sorted |
| |
719 } |
| |
720 |
| |
721 int cxListSwap(CxList *list, size_t i, size_t j) { |
| |
722 list->collection.sorted = false; |
| |
723 return list->cl->swap(list, i, j); |
| |
724 } |
| |
725 |
| |
726 void *cxListAt(const CxList *list, size_t index) { |
| |
727 return list->cl->at(list, index); |
| |
728 } |
| |
729 |
| |
730 void *cxListFirst(const CxList *list) { |
| |
731 return list->cl->at(list, 0); |
| |
732 } |
| |
733 |
| |
734 void *cxListLast(const CxList *list) { |
| |
735 return list->cl->at(list, list->collection.size - 1); |
| |
736 } |
| |
737 |
| |
738 int cxListSet(CxList *list, size_t index, const void *elem) { |
| 599 if (index >= list->collection.size) { |
739 if (index >= list->collection.size) { |
| 600 return 1; |
740 return 1; |
| 601 } |
741 } |
| 602 |
742 |
| 603 if (list->collection.store_pointer) { |
743 if (list->collection.store_pointer) { |
| 609 memcpy(target, elem, list->collection.elem_size); |
749 memcpy(target, elem, list->collection.elem_size); |
| 610 } |
750 } |
| 611 |
751 |
| 612 return 0; |
752 return 0; |
| 613 } |
753 } |
| |
754 |
| |
755 CxIterator cxListIteratorAt(const CxList *list, size_t index) { |
| |
756 if (list == NULL) list = cxEmptyList; |
| |
757 return list->cl->iterator(list, index, false); |
| |
758 } |
| |
759 |
| |
760 CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index) { |
| |
761 if (list == NULL) list = cxEmptyList; |
| |
762 return list->cl->iterator(list, index, true); |
| |
763 } |
| |
764 |
| |
765 CxIterator cxListIterator(const CxList *list) { |
| |
766 if (list == NULL) list = cxEmptyList; |
| |
767 return list->cl->iterator(list, 0, false); |
| |
768 } |
| |
769 |
| |
770 CxIterator cxListBackwardsIterator(const CxList *list) { |
| |
771 if (list == NULL) list = cxEmptyList; |
| |
772 return list->cl->iterator(list, list->collection.size - 1, true); |
| |
773 } |
| |
774 |
| |
775 size_t cxListFind(const CxList *list, const void *elem) { |
| |
776 return list->cl->find_remove((CxList*)list, elem, false); |
| |
777 } |
| |
778 |
| |
779 bool cxListContains(const CxList* list, const void* elem) { |
| |
780 return list->cl->find_remove((CxList*)list, elem, false) < list->collection.size; |
| |
781 } |
| |
782 |
| |
783 bool cxListIndexValid(const CxList *list, size_t index) { |
| |
784 return index < list->collection.size; |
| |
785 } |
| |
786 |
| |
787 size_t cxListFindRemove(CxList *list, const void *elem) { |
| |
788 return list->cl->find_remove(list, elem, true); |
| |
789 } |
| |
790 |
| |
791 void cxListSort(CxList *list) { |
| |
792 if (list->collection.sorted) return; |
| |
793 list->cl->sort(list); |
| |
794 list->collection.sorted = true; |
| |
795 } |
| |
796 |
| |
797 void cxListReverse(CxList *list) { |
| |
798 // still sorted, but not according to the cmp_func |
| |
799 list->collection.sorted = false; |
| |
800 list->cl->reverse(list); |
| |
801 } |
| |
802 |
| |
803 void cxListFree(CxList *list) { |
| |
804 if (list == NULL) return; |
| |
805 list->cl->deallocate(list); |
| |
806 } |