| 636 if (index > list->collection.size || n == 0) return 0; |
636 if (index > list->collection.size || n == 0) return 0; |
| 637 |
637 |
| 638 // get a correctly typed pointer to the list |
638 // get a correctly typed pointer to the list |
| 639 cx_array_list *arl = (cx_array_list *) list; |
639 cx_array_list *arl = (cx_array_list *) list; |
| 640 |
640 |
| |
641 // guarantee enough capacity |
| |
642 if (arl->capacity < list->collection.size + n) { |
| |
643 size_t new_capacity = list->collection.size + n; |
| |
644 new_capacity = new_capacity - (new_capacity % 16) + 16; |
| |
645 if (cxReallocateArray( |
| |
646 list->collection.allocator, |
| |
647 &arl->data, new_capacity, |
| |
648 list->collection.elem_size) |
| |
649 ) { |
| |
650 return 0; |
| |
651 } |
| |
652 arl->capacity = new_capacity; |
| |
653 } |
| |
654 |
| |
655 // determine insert position |
| |
656 char *arl_data = arl->data; |
| |
657 char *insert_pos = arl_data + index * list->collection.elem_size; |
| |
658 |
| 641 // do we need to move some elements? |
659 // do we need to move some elements? |
| 642 if (index < list->collection.size) { |
660 if (index < list->collection.size) { |
| 643 const char *first_to_move = (const char *) arl->data; |
|
| 644 first_to_move += index * list->collection.elem_size; |
|
| 645 size_t elems_to_move = list->collection.size - index; |
661 size_t elems_to_move = list->collection.size - index; |
| 646 size_t start_of_moved = index + n; |
662 char *target = insert_pos + n * list->collection.elem_size; |
| 647 |
663 memmove(target, insert_pos, elems_to_move * list->collection.elem_size); |
| 648 if (cx_array_copy( |
664 } |
| 649 &arl->data, |
665 |
| 650 &list->collection.size, |
666 // place the new elements, if any |
| 651 &arl->capacity, |
667 if (array != NULL) { |
| 652 0, |
668 memcpy(insert_pos, array, n * list->collection.elem_size); |
| 653 start_of_moved, |
669 } |
| 654 first_to_move, |
670 list->collection.size += n; |
| 655 list->collection.elem_size, |
671 |
| 656 elems_to_move, |
672 return n; |
| 657 &arl->reallocator |
|
| 658 )) { |
|
| 659 // if moving existing elems is unsuccessful, abort |
|
| 660 return 0; |
|
| 661 } |
|
| 662 } |
|
| 663 |
|
| 664 // note that if we had to move the elements, the following operation |
|
| 665 // is guaranteed to succeed, because we have the memory already allocated |
|
| 666 // therefore, it is impossible to leave this function with an invalid array |
|
| 667 |
|
| 668 // place the new elements |
|
| 669 if (cx_array_copy( |
|
| 670 &arl->data, |
|
| 671 &list->collection.size, |
|
| 672 &arl->capacity, |
|
| 673 0, |
|
| 674 index, |
|
| 675 array, |
|
| 676 list->collection.elem_size, |
|
| 677 n, |
|
| 678 &arl->reallocator |
|
| 679 )) { |
|
| 680 // array list implementation is "all or nothing" |
|
| 681 return 0; |
|
| 682 } else { |
|
| 683 return n; |
|
| 684 } |
|
| 685 } |
673 } |
| 686 |
674 |
| 687 static size_t cx_arl_insert_sorted( |
675 static size_t cx_arl_insert_sorted( |
| 688 struct cx_list_s *list, |
676 struct cx_list_s *list, |
| 689 const void *sorted_data, |
677 const void *sorted_data, |
| 707 } else { |
695 } else { |
| 708 return n; |
696 return n; |
| 709 } |
697 } |
| 710 } |
698 } |
| 711 |
699 |
| 712 static int cx_arl_insert_element( |
700 static void *cx_arl_insert_element( |
| 713 struct cx_list_s *list, |
701 struct cx_list_s *list, |
| 714 size_t index, |
702 size_t index, |
| 715 const void *element |
703 const void *element |
| 716 ) { |
704 ) { |
| 717 return 1 != cx_arl_insert_array(list, index, element, 1); |
705 if (cx_arl_insert_array(list, index, element, 1) == 1) { |
| |
706 return ((char*)((cx_array_list *) list)->data) + index * list->collection.elem_size; |
| |
707 } else { |
| |
708 return NULL; |
| |
709 } |
| 718 } |
710 } |
| 719 |
711 |
| 720 static int cx_arl_insert_iter( |
712 static int cx_arl_insert_iter( |
| 721 struct cx_iterator_s *iter, |
713 struct cx_iterator_s *iter, |
| 722 const void *elem, |
714 const void *elem, |
| 723 int prepend |
715 int prepend |
| 724 ) { |
716 ) { |
| 725 struct cx_list_s *list = iter->src_handle.m; |
717 struct cx_list_s *list = iter->src_handle.m; |
| 726 if (iter->index < list->collection.size) { |
718 if (iter->index < list->collection.size) { |
| 727 int result = cx_arl_insert_element( |
719 if (cx_arl_insert_element(list, |
| 728 list, |
720 iter->index + 1 - prepend, elem) == NULL) { |
| 729 iter->index + 1 - prepend, |
721 return 1; |
| 730 elem |
722 } |
| 731 ); |
723 iter->elem_count++; |
| 732 if (result == 0) { |
724 if (prepend != 0) { |
| 733 iter->elem_count++; |
725 iter->index++; |
| 734 if (prepend != 0) { |
726 iter->elem_handle = ((char *) iter->elem_handle) + list->collection.elem_size; |
| 735 iter->index++; |
727 } |
| 736 iter->elem_handle = ((char *) iter->elem_handle) + list->collection.elem_size; |
728 return 0; |
| 737 } |
729 } else { |
| 738 } |
730 if (cx_arl_insert_element(list, list->collection.size, elem) == NULL) { |
| 739 return result; |
731 return 1; |
| 740 } else { |
732 } |
| 741 int result = cx_arl_insert_element(list, list->collection.size, elem); |
733 iter->elem_count++; |
| 742 if (result == 0) { |
734 iter->index = list->collection.size; |
| 743 iter->elem_count++; |
735 return 0; |
| 744 iter->index = list->collection.size; |
|
| 745 } |
|
| 746 return result; |
|
| 747 } |
736 } |
| 748 } |
737 } |
| 749 |
738 |
| 750 static size_t cx_arl_remove( |
739 static size_t cx_arl_remove( |
| 751 struct cx_list_s *list, |
740 struct cx_list_s *list, |