src/list.c

changeset 1423
9a72258446cd
parent 1422
8bfccb342895
--- 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(

mercurial