src/array_list.c

changeset 1419
e46406fd1b3c
parent 1387
9bdd053820b7
equal deleted inserted replaced
1418:5e1579713bcf 1419:e46406fd1b3c
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 // handle the identical elements
424 size_t skip_len = 0;
425 while (copy_len < elem_count - si
426 && cmp_func(bptr, src+copy_len*elem_size) == 0) {
427 copy_len++;
428 if (!allow_duplicates) {
429 skip_len++;
430 }
431 }
432 copy_len -= skip_len;
421 433
422 // copy the source elements 434 // copy the source elements
423 bytes_copied = copy_len * elem_size; 435 bytes_copied = copy_len * elem_size;
424 memcpy(dest, src, bytes_copied); 436 memcpy(dest, src, bytes_copied);
425 dest += bytes_copied; 437 dest += bytes_copied;
426 src += bytes_copied; 438 src += bytes_copied;
427 si += copy_len; 439 si += copy_len;
440 di += copy_len;
441
442 // skip duplicates when they are not allowed
443 src += skip_len * elem_size;
444 si += skip_len;
445 *size -= skip_len;
428 446
429 // when all source elements are in place, we are done 447 // when all source elements are in place, we are done
430 if (si >= elem_count) break; 448 if (si >= elem_count) break;
431 449
432 // determine how many buffered elements need to be restored 450 // determine how many buffered elements need to be restored
441 // restore the buffered elements 459 // restore the buffered elements
442 bytes_copied = copy_len * elem_size; 460 bytes_copied = copy_len * elem_size;
443 memmove(dest, bptr, bytes_copied); 461 memmove(dest, bptr, bytes_copied);
444 dest += bytes_copied; 462 dest += bytes_copied;
445 bptr += bytes_copied; 463 bptr += bytes_copied;
464 di += copy_len;
446 bi += copy_len; 465 bi += copy_len;
466
467 // check if the last restored element is a duplicate of the next source
468 if (!allow_duplicates && copy_len > 0) {
469 char *last = dest - elem_size;
470 while (si < elem_count && cmp_func(last, src) == 0) {
471 src += elem_size;
472 si++;
473 (*size)--;
474 }
475 }
447 } 476 }
448 477
449 // still source elements left? simply append them 478 // still source elements left? simply append them
450 if (si < elem_count) { 479 if (si < elem_count) {
451 memcpy(dest, src, elem_size * (elem_count - si)); 480 memcpy(dest, src, elem_size * (elem_count - si));
452 } 481 }
453 482
454 // still buffer elements left? 483 // buffered elements need to be moved when we skipped duplicates
455 // don't worry, we already moved them to the correct place 484 size_t total_skipped = new_size - *size;
485 if (bi < new_size && total_skipped > 0) {
486 // move the remaining buffer to the end of the array
487 memmove(dest, bptr, elem_size * (new_size - bi));
488 }
456 489
457 return 0; 490 return 0;
491 }
492
493 int cx_array_insert_sorted(
494 void **target,
495 size_t *size,
496 size_t *capacity,
497 cx_compare_func cmp_func,
498 const void *sorted_data,
499 size_t elem_size,
500 size_t elem_count,
501 CxArrayReallocator *reallocator
502 ) {
503 return cx_array_insert_sorted_impl(target, size, capacity,
504 cmp_func, sorted_data, elem_size, elem_count, reallocator, true);
505 }
506
507 int cx_array_insert_unique(
508 void **target,
509 size_t *size,
510 size_t *capacity,
511 cx_compare_func cmp_func,
512 const void *sorted_data,
513 size_t elem_size,
514 size_t elem_count,
515 CxArrayReallocator *reallocator
516 ) {
517 return cx_array_insert_sorted_impl(target, size, capacity,
518 cmp_func, sorted_data, elem_size, elem_count, reallocator, false);
458 } 519 }
459 520
460 size_t cx_array_binary_search_inf( 521 size_t cx_array_binary_search_inf(
461 const void *arr, 522 const void *arr,
462 size_t size, 523 size_t size,
500 pivot_index = left_index + (right_index - left_index) / 2; 561 pivot_index = left_index + (right_index - left_index) / 2;
501 const char *arr_elem = array + pivot_index * elem_size; 562 const char *arr_elem = array + pivot_index * elem_size;
502 result = cmp_func(elem, arr_elem); 563 result = cmp_func(elem, arr_elem);
503 if (result == 0) { 564 if (result == 0) {
504 // found it! 565 // found it!
566 // check previous elements;
567 // when they are equal, report the smallest index
568 arr_elem -= elem_size;
569 while (pivot_index > 0 && cmp_func(elem, arr_elem) == 0) {
570 pivot_index--;
571 arr_elem -= elem_size;
572 }
505 return pivot_index; 573 return pivot_index;
506 } else if (result < 0) { 574 } else if (result < 0) {
507 // element is smaller than pivot, continue search left 575 // element is smaller than pivot, continue search left
508 right_index = pivot_index - 1; 576 right_index = pivot_index - 1;
509 } else { 577 } else {
698 } else { 766 } else {
699 return n; 767 return n;
700 } 768 }
701 } 769 }
702 770
771 static size_t cx_arl_insert_unique(
772 struct cx_list_s *list,
773 const void *sorted_data,
774 size_t n
775 ) {
776 // get a correctly typed pointer to the list
777 cx_array_list *arl = (cx_array_list *) list;
778
779 if (cx_array_insert_unique(
780 &arl->data,
781 &list->collection.size,
782 &arl->capacity,
783 list->collection.cmpfunc,
784 sorted_data,
785 list->collection.elem_size,
786 n,
787 &arl->reallocator
788 )) {
789 // array list implementation is "all or nothing"
790 return 0;
791 } else {
792 return n;
793 }
794 }
795
703 static void *cx_arl_insert_element( 796 static void *cx_arl_insert_element(
704 struct cx_list_s *list, 797 struct cx_list_s *list,
705 size_t index, 798 size_t index,
706 const void *element 799 const void *element
707 ) { 800 ) {
991 static cx_list_class cx_array_list_class = { 1084 static cx_list_class cx_array_list_class = {
992 cx_arl_destructor, 1085 cx_arl_destructor,
993 cx_arl_insert_element, 1086 cx_arl_insert_element,
994 cx_arl_insert_array, 1087 cx_arl_insert_array,
995 cx_arl_insert_sorted, 1088 cx_arl_insert_sorted,
1089 cx_arl_insert_unique,
996 cx_arl_insert_iter, 1090 cx_arl_insert_iter,
997 cx_arl_remove, 1091 cx_arl_remove,
998 cx_arl_clear, 1092 cx_arl_clear,
999 cx_arl_swap, 1093 cx_arl_swap,
1000 cx_arl_at, 1094 cx_arl_at,

mercurial