src/array_list.c

changeset 919
75da57d4634e
parent 890
54565fd74e74
--- a/src/array_list.c	Sun Oct 06 19:17:41 2024 +0200
+++ b/src/array_list.c	Mon Oct 07 20:20:21 2024 +0200
@@ -494,35 +494,58 @@
     }
 }
 
-static int cx_arl_remove(
+static size_t cx_arl_remove(
         struct cx_list_s *list,
-        size_t index
+        size_t index,
+        size_t num,
+        void *targetbuf
 ) {
     cx_array_list *arl = (cx_array_list *) list;
 
     // out-of-bounds check
+    size_t remove;
     if (index >= list->collection.size) {
-        return 1;
+        remove = 0;
+    } else if (index + num > list->collection.size) {
+        remove = list->collection.size - index;
+    } else {
+        remove = num;
     }
 
-    // content destruction
-    cx_invoke_destructor(list, ((char *) arl->data) + index * list->collection.elem_size);
+    // easy exit
+    if (remove == 0) return 0;
 
-    // short-circuit removal of last element
-    if (index == list->collection.size - 1) {
-        list->collection.size--;
-        return 0;
+    // destroy or copy contents
+    if (targetbuf == NULL) {
+        for (size_t idx = index; idx < index + remove; idx++) {
+            cx_invoke_destructor(
+                    list,
+                    ((char *) arl->data) + idx * list->collection.elem_size
+            );
+        }
+    } else {
+        memcpy(
+                targetbuf,
+                ((char *) arl->data) + index * list->collection.elem_size,
+                remove * list->collection.elem_size
+        );
     }
 
-    // just move the elements starting at index to the left
+    // short-circuit removal of last elements
+    if (index + remove == list->collection.size) {
+        list->collection.size -= remove;
+        return remove;
+    }
+
+    // just move the elements to the left
     int result = cx_array_copy(
             &arl->data,
             &list->collection.size,
             &arl->capacity,
             index,
-            ((char *) arl->data) + (index + 1) * list->collection.elem_size,
+            ((char *) arl->data) + (index + remove) * list->collection.elem_size,
             list->collection.elem_size,
-            list->collection.size - index - 1,
+            list->collection.size - index - remove,
             &arl->reallocator
     );
 
@@ -530,9 +553,9 @@
     assert(result == 0);
 
     // decrease the size
-    list->collection.size--;
+    list->collection.size -= remove;
 
-    return 0;
+    return remove;
 }
 
 static void cx_arl_clear(struct cx_list_s *list) {
@@ -594,7 +617,7 @@
     for (ssize_t i = 0; i < (ssize_t) list->collection.size; i++) {
         if (0 == list->collection.cmpfunc(elem, cur)) {
             if (remove) {
-                if (0 == cx_arl_remove(list, i)) {
+                if (1 == cx_arl_remove(list, i, 1, NULL)) {
                     return i;
                 } else {
                     return -1;
@@ -664,7 +687,7 @@
     struct cx_iterator_s *iter = it;
     if (iter->base.remove) {
         iter->base.remove = false;
-        cx_arl_remove(iter->src_handle.m, iter->index);
+        cx_arl_remove(iter->src_handle.m, iter->index, 1, NULL);
     } else {
         iter->index++;
         iter->elem_handle =
@@ -678,7 +701,7 @@
     const cx_array_list *list = iter->src_handle.c;
     if (iter->base.remove) {
         iter->base.remove = false;
-        cx_arl_remove(iter->src_handle.m, iter->index);
+        cx_arl_remove(iter->src_handle.m, iter->index, 1, NULL);
     }
     iter->index--;
     if (iter->index < list->base.collection.size) {

mercurial