ucx/array_list.c

changeset 112
c3f2f16fa4b8
parent 108
77254bd6dccb
child 113
dde28a806552
equal deleted inserted replaced
111:81c4f73236a4 112:c3f2f16fa4b8
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;
989 static cx_list_class cx_array_list_class = { 1155 static cx_list_class cx_array_list_class = {
990 cx_arl_destructor, 1156 cx_arl_destructor,
991 cx_arl_insert_element, 1157 cx_arl_insert_element,
992 cx_arl_insert_array, 1158 cx_arl_insert_array,
993 cx_arl_insert_sorted, 1159 cx_arl_insert_sorted,
1160 cx_arl_insert_unique,
994 cx_arl_insert_iter, 1161 cx_arl_insert_iter,
995 cx_arl_remove, 1162 cx_arl_remove,
996 cx_arl_clear, 1163 cx_arl_clear,
997 cx_arl_swap, 1164 cx_arl_swap,
998 cx_arl_at, 1165 cx_arl_at,

mercurial