| 289 // perform reallocation |
289 // perform reallocation |
| 290 void *newmem = reallocator->realloc( |
290 void *newmem = reallocator->realloc( |
| 291 *target, oldcap, newcap, elem_size, reallocator |
291 *target, oldcap, newcap, elem_size, reallocator |
| 292 ); |
292 ); |
| 293 if (newmem == NULL) { |
293 if (newmem == NULL) { |
| 294 return 1; |
294 return 1; // LCOV_EXCL_LINE |
| 295 } |
295 } |
| 296 |
296 |
| 297 // repair src pointer, if necessary |
297 // repair src pointer, if necessary |
| 298 if (repairsrc) { |
298 if (repairsrc) { |
| 299 src = ((char *) newmem) + (srcaddr - targetaddr); |
299 src = ((char *) newmem) + (srcaddr - targetaddr); |
| 333 |
333 |
| 334 // return successfully |
334 // return successfully |
| 335 return 0; |
335 return 0; |
| 336 } |
336 } |
| 337 |
337 |
| 338 int cx_array_insert_sorted( |
338 static int cx_array_insert_sorted_impl( |
| 339 void **target, |
339 void **target, |
| 340 size_t *size, |
340 size_t *size, |
| 341 size_t *capacity, |
341 size_t *capacity, |
| 342 cx_compare_func cmp_func, |
342 cx_compare_func cmp_func, |
| 343 const void *sorted_data, |
343 const void *sorted_data, |
| 344 size_t elem_size, |
344 size_t elem_size, |
| 345 size_t elem_count, |
345 size_t elem_count, |
| 346 CxArrayReallocator *reallocator |
346 CxArrayReallocator *reallocator, |
| |
347 bool allow_duplicates |
| 347 ) { |
348 ) { |
| 348 // assert pointers |
349 // assert pointers |
| 349 assert(target != NULL); |
350 assert(target != NULL); |
| 350 assert(size != NULL); |
351 assert(size != NULL); |
| 351 assert(capacity != NULL); |
352 assert(capacity != NULL); |
| 367 } |
368 } |
| 368 |
369 |
| 369 // store some counts |
370 // store some counts |
| 370 size_t old_size = *size; |
371 size_t old_size = *size; |
| 371 size_t old_capacity = *capacity; |
372 size_t old_capacity = *capacity; |
| |
373 // the necessary capacity is the worst case assumption, including duplicates |
| 372 size_t needed_capacity = old_size + elem_count; |
374 size_t needed_capacity = old_size + elem_count; |
| 373 |
375 |
| 374 // if we need more than we have, try a reallocation |
376 // if we need more than we have, try a reallocation |
| 375 if (needed_capacity > old_capacity) { |
377 if (needed_capacity > old_capacity) { |
| 376 size_t new_capacity = cx_array_align_capacity(needed_capacity, 16, SIZE_MAX); |
378 size_t new_capacity = cx_array_align_capacity(needed_capacity, 16, SIZE_MAX); |
| 416 elem_count - si, |
418 elem_count - si, |
| 417 elem_size, |
419 elem_size, |
| 418 bptr, |
420 bptr, |
| 419 cmp_func |
421 cmp_func |
| 420 ); |
422 ); |
| |
423 // binary search gives us the smallest index; |
| |
424 // we also want to include equal elements here |
| |
425 while (si + copy_len < elem_count |
| |
426 && cmp_func(bptr, src+copy_len*elem_size) == 0) { |
| |
427 copy_len++; |
| |
428 } |
| 421 |
429 |
| 422 // copy the source elements |
430 // copy the source elements |
| 423 bytes_copied = copy_len * elem_size; |
431 if (copy_len > 0) { |
| 424 memcpy(dest, src, bytes_copied); |
432 if (allow_duplicates) { |
| 425 dest += bytes_copied; |
433 // we can copy the entire chunk |
| 426 src += bytes_copied; |
434 bytes_copied = copy_len * elem_size; |
| 427 si += copy_len; |
435 memcpy(dest, src, bytes_copied); |
| |
436 dest += bytes_copied; |
| |
437 src += bytes_copied; |
| |
438 si += copy_len; |
| |
439 di += copy_len; |
| |
440 } else { |
| |
441 // first, check the end of the source chunk |
| |
442 // for being a duplicate of the bptr |
| |
443 const char *end_of_src = src + (copy_len - 1) * elem_size; |
| |
444 size_t skip_len = 0; |
| |
445 while (copy_len > 0 && cmp_func(bptr, end_of_src) == 0) { |
| |
446 end_of_src -= elem_size; |
| |
447 skip_len++; |
| |
448 copy_len--; |
| |
449 } |
| |
450 char *last = dest == *target ? NULL : dest - elem_size; |
| |
451 // then iterate through the source chunk |
| |
452 // and skip all duplicates with the last element in the array |
| |
453 size_t more_skipped = 0; |
| |
454 for (unsigned j = 0; j < copy_len; j++) { |
| |
455 if (last != NULL && cmp_func(last, src) == 0) { |
| |
456 // duplicate - skip |
| |
457 src += elem_size; |
| |
458 si++; |
| |
459 more_skipped++; |
| |
460 } else { |
| |
461 memcpy(dest, src, elem_size); |
| |
462 src += elem_size; |
| |
463 last = dest; |
| |
464 dest += elem_size; |
| |
465 si++; |
| |
466 di++; |
| |
467 } |
| |
468 } |
| |
469 // skip the previously identified elements as well |
| |
470 src += skip_len * elem_size; |
| |
471 si += skip_len; |
| |
472 skip_len += more_skipped; |
| |
473 // reduce the actual size by the number of skipped elements |
| |
474 *size -= skip_len; |
| |
475 } |
| |
476 } |
| 428 |
477 |
| 429 // when all source elements are in place, we are done |
478 // when all source elements are in place, we are done |
| 430 if (si >= elem_count) break; |
479 if (si >= elem_count) break; |
| 431 |
480 |
| 432 // determine how many buffered elements need to be restored |
481 // determine how many buffered elements need to be restored |
| 441 // restore the buffered elements |
490 // restore the buffered elements |
| 442 bytes_copied = copy_len * elem_size; |
491 bytes_copied = copy_len * elem_size; |
| 443 memmove(dest, bptr, bytes_copied); |
492 memmove(dest, bptr, bytes_copied); |
| 444 dest += bytes_copied; |
493 dest += bytes_copied; |
| 445 bptr += bytes_copied; |
494 bptr += bytes_copied; |
| |
495 di += copy_len; |
| 446 bi += copy_len; |
496 bi += copy_len; |
| 447 } |
497 } |
| 448 |
498 |
| 449 // still source elements left? simply append them |
499 // still source elements left? |
| 450 if (si < elem_count) { |
500 if (si < elem_count) { |
| 451 memcpy(dest, src, elem_size * (elem_count - si)); |
501 if (allow_duplicates) { |
| 452 } |
502 // duplicates allowed or nothing inserted yet: simply copy everything |
| 453 |
503 memcpy(dest, src, elem_size * (elem_count - si)); |
| 454 // still buffer elements left? |
504 } else { |
| 455 // don't worry, we already moved them to the correct place |
505 if (dest != *target) { |
| |
506 // skip all source elements that equal the last element |
| |
507 char *last = dest - elem_size; |
| |
508 while (si < elem_count) { |
| |
509 if (last != NULL && cmp_func(last, src) == 0) { |
| |
510 src += elem_size; |
| |
511 si++; |
| |
512 (*size)--; |
| |
513 } else { |
| |
514 break; |
| |
515 } |
| |
516 } |
| |
517 } |
| |
518 // we must check the elements in the chunk one by one |
| |
519 while (si < elem_count) { |
| |
520 // find a chain of elements that can be copied |
| |
521 size_t copy_len = 1, skip_len = 0; |
| |
522 { |
| |
523 const char *left_src = src; |
| |
524 while (si + copy_len < elem_count) { |
| |
525 const char *right_src = left_src + elem_size; |
| |
526 int d = cmp_func(left_src, right_src); |
| |
527 if (d < 0) { |
| |
528 if (skip_len > 0) { |
| |
529 // new larger element found; |
| |
530 // handle it in the next cycle |
| |
531 break; |
| |
532 } |
| |
533 left_src += elem_size; |
| |
534 copy_len++; |
| |
535 } else if (d == 0) { |
| |
536 left_src += elem_size; |
| |
537 skip_len++; |
| |
538 } else { |
| |
539 break; |
| |
540 } |
| |
541 } |
| |
542 } |
| |
543 size_t bytes_copied = copy_len * elem_size; |
| |
544 memcpy(dest, src, bytes_copied); |
| |
545 dest += bytes_copied; |
| |
546 src += bytes_copied + skip_len * elem_size; |
| |
547 si += copy_len + skip_len; |
| |
548 di += copy_len; |
| |
549 *size -= skip_len; |
| |
550 } |
| |
551 } |
| |
552 } |
| |
553 |
| |
554 // buffered elements need to be moved when we skipped duplicates |
| |
555 size_t total_skipped = new_size - *size; |
| |
556 if (bi < new_size && total_skipped > 0) { |
| |
557 // move the remaining buffer to the end of the array |
| |
558 memmove(dest, bptr, elem_size * (new_size - bi)); |
| |
559 } |
| 456 |
560 |
| 457 return 0; |
561 return 0; |
| |
562 } |
| |
563 |
| |
564 int cx_array_insert_sorted( |
| |
565 void **target, |
| |
566 size_t *size, |
| |
567 size_t *capacity, |
| |
568 cx_compare_func cmp_func, |
| |
569 const void *sorted_data, |
| |
570 size_t elem_size, |
| |
571 size_t elem_count, |
| |
572 CxArrayReallocator *reallocator |
| |
573 ) { |
| |
574 return cx_array_insert_sorted_impl(target, size, capacity, |
| |
575 cmp_func, sorted_data, elem_size, elem_count, reallocator, true); |
| |
576 } |
| |
577 |
| |
578 int cx_array_insert_unique( |
| |
579 void **target, |
| |
580 size_t *size, |
| |
581 size_t *capacity, |
| |
582 cx_compare_func cmp_func, |
| |
583 const void *sorted_data, |
| |
584 size_t elem_size, |
| |
585 size_t elem_count, |
| |
586 CxArrayReallocator *reallocator |
| |
587 ) { |
| |
588 return cx_array_insert_sorted_impl(target, size, capacity, |
| |
589 cmp_func, sorted_data, elem_size, elem_count, reallocator, false); |
| 458 } |
590 } |
| 459 |
591 |
| 460 size_t cx_array_binary_search_inf( |
592 size_t cx_array_binary_search_inf( |
| 461 const void *arr, |
593 const void *arr, |
| 462 size_t size, |
594 size_t size, |
| 500 pivot_index = left_index + (right_index - left_index) / 2; |
632 pivot_index = left_index + (right_index - left_index) / 2; |
| 501 const char *arr_elem = array + pivot_index * elem_size; |
633 const char *arr_elem = array + pivot_index * elem_size; |
| 502 result = cmp_func(elem, arr_elem); |
634 result = cmp_func(elem, arr_elem); |
| 503 if (result == 0) { |
635 if (result == 0) { |
| 504 // found it! |
636 // found it! |
| |
637 // check previous elements; |
| |
638 // when they are equal, report the smallest index |
| |
639 arr_elem -= elem_size; |
| |
640 while (pivot_index > 0 && cmp_func(elem, arr_elem) == 0) { |
| |
641 pivot_index--; |
| |
642 arr_elem -= elem_size; |
| |
643 } |
| 505 return pivot_index; |
644 return pivot_index; |
| 506 } else if (result < 0) { |
645 } else if (result < 0) { |
| 507 // element is smaller than pivot, continue search left |
646 // element is smaller than pivot, continue search left |
| 508 right_index = pivot_index - 1; |
647 right_index = pivot_index - 1; |
| 509 } else { |
648 } else { |
| 698 } else { |
837 } else { |
| 699 return n; |
838 return n; |
| 700 } |
839 } |
| 701 } |
840 } |
| 702 |
841 |
| |
842 static size_t cx_arl_insert_unique( |
| |
843 struct cx_list_s *list, |
| |
844 const void *sorted_data, |
| |
845 size_t n |
| |
846 ) { |
| |
847 // get a correctly typed pointer to the list |
| |
848 cx_array_list *arl = (cx_array_list *) list; |
| |
849 |
| |
850 if (cx_array_insert_unique( |
| |
851 &arl->data, |
| |
852 &list->collection.size, |
| |
853 &arl->capacity, |
| |
854 list->collection.cmpfunc, |
| |
855 sorted_data, |
| |
856 list->collection.elem_size, |
| |
857 n, |
| |
858 &arl->reallocator |
| |
859 )) { |
| |
860 // array list implementation is "all or nothing" |
| |
861 return 0; |
| |
862 } else { |
| |
863 return n; |
| |
864 } |
| |
865 } |
| |
866 |
| 703 static void *cx_arl_insert_element( |
867 static void *cx_arl_insert_element( |
| 704 struct cx_list_s *list, |
868 struct cx_list_s *list, |
| 705 size_t index, |
869 size_t index, |
| 706 const void *element |
870 const void *element |
| 707 ) { |
871 ) { |
| 940 static void cx_arl_iter_next(void *it) { |
1104 static void cx_arl_iter_next(void *it) { |
| 941 struct cx_iterator_s *iter = it; |
1105 struct cx_iterator_s *iter = it; |
| 942 if (iter->base.remove) { |
1106 if (iter->base.remove) { |
| 943 iter->base.remove = false; |
1107 iter->base.remove = false; |
| 944 cx_arl_remove(iter->src_handle.m, iter->index, 1, NULL); |
1108 cx_arl_remove(iter->src_handle.m, iter->index, 1, NULL); |
| |
1109 iter->elem_count--; |
| 945 } else { |
1110 } else { |
| 946 iter->index++; |
1111 iter->index++; |
| 947 iter->elem_handle = |
1112 iter->elem_handle = |
| 948 ((char *) iter->elem_handle) |
1113 ((char *) iter->elem_handle) |
| 949 + ((const struct cx_list_s *) iter->src_handle.c)->collection.elem_size; |
1114 + ((const struct cx_list_s *) iter->src_handle.c)->collection.elem_size; |
| 954 struct cx_iterator_s *iter = it; |
1119 struct cx_iterator_s *iter = it; |
| 955 const cx_array_list *list = iter->src_handle.c; |
1120 const cx_array_list *list = iter->src_handle.c; |
| 956 if (iter->base.remove) { |
1121 if (iter->base.remove) { |
| 957 iter->base.remove = false; |
1122 iter->base.remove = false; |
| 958 cx_arl_remove(iter->src_handle.m, iter->index, 1, NULL); |
1123 cx_arl_remove(iter->src_handle.m, iter->index, 1, NULL); |
| |
1124 iter->elem_count--; |
| 959 } |
1125 } |
| 960 iter->index--; |
1126 iter->index--; |
| 961 if (iter->index < list->base.collection.size) { |
1127 if (iter->index < list->base.collection.size) { |
| 962 iter->elem_handle = ((char *) list->data) |
1128 iter->elem_handle = ((char *) list->data) |
| 963 + iter->index * list->base.collection.elem_size; |
1129 + iter->index * list->base.collection.elem_size; |