diff -r 8bfccb342895 -r 9a72258446cd src/list.c --- a/src/list.c Sat Oct 11 11:55:46 2025 +0200 +++ b/src/list.c Sat Oct 11 15:42:48 2025 +0200 @@ -327,38 +327,54 @@ const char *src = sorted_data; // track indices and number of inserted items - size_t di = 0, si = 0, inserted = 0; + size_t di = 0, si = 0, processed = 0; // search the list for insertion points - for (; di < list->collection.size; di++) { + while (di < list->collection.size) { const void *list_elm = invoke_list_func(at, list, di); - // compare current list element with first source element - // if less or equal, skip + // compare the current list element with the first source element + // if less, skip the list elements + // if equal, skip the list elements and optionally the source elements { int d = cmp(list_elm, src); if (d <= 0) { if (!allow_duplicates && d == 0) { src += elem_size; si++; - inserted++; // we also count duplicates for the return value + processed++; // we also count duplicates for the return value while (si < n && cmp(list_elm, src) == 0) { src += elem_size; si++; - inserted++; + processed++; } - if (inserted == n) { - return inserted; + if (processed == n) { + return processed; } } + di++; continue; } } - // determine number of consecutive elements that can be inserted - size_t ins = 1; + // determine the number of consecutive elements that can be inserted + size_t ins = 1, skip = 0; const char *next = src; while (++si < n) { + if (!allow_duplicates) { + // skip duplicates within the source + if (cmp(next, next + elem_size) == 0) { + next += elem_size; + skip++; + continue; + } else { + if (skip > 0) { + // if we had to skip something, we must wait for the next run + next += elem_size; + break; + } + } + } next += elem_size; // once we become larger than the list elem, break if (cmp(list_elm, next) <= 0) { @@ -371,30 +387,46 @@ // insert the elements at location si if (ins == 1) { if (NULL == invoke_list_func(insert_element, list, di, src)) { - return inserted; // LCOV_EXCL_LINE + return processed; // LCOV_EXCL_LINE } } else { size_t r = invoke_list_func(insert_array, list, di, src, ins); if (r < ins) { - return inserted + r; // LCOV_EXCL_LINE + return processed + r; // LCOV_EXCL_LINE } } - inserted += ins; + processed += ins + skip; di += ins; // everything inserted? - if (inserted == n) { - return inserted; + if (processed == n) { + return processed; } src = next; } // insert remaining items if (si < n) { - inserted += invoke_list_func(insert_array, list, di, src, n - si); + if (allow_duplicates) { + processed += invoke_list_func(insert_array, list, di, src, n - si); + } else { + const void *last = di == 0 ? NULL : invoke_list_func(at, list, di - 1); + for (; si < n; si++) { + // skip duplicates within the source + if (last == NULL || cmp(last, src) != 0) { + if (NULL == invoke_list_func(insert_element, list, di, src)) { + return processed; // LCOV_EXCL_LINE + } + last = src; + di++; + } + processed++; + src += elem_size; + } + } } - return inserted; + return processed; } size_t cx_list_default_insert_sorted(