ucx/list.c

branch
newapi
changeset 324
ce13a778654a
parent 253
087cc9216f28
--- a/ucx/list.c	Thu Oct 03 18:54:19 2024 +0200
+++ b/ucx/list.c	Sun Oct 06 12:00:31 2024 +0200
@@ -35,26 +35,26 @@
 static _Thread_local cx_compare_func cx_pl_cmpfunc_impl;
 
 static int cx_pl_cmpfunc(
-        void const *l,
-        void const *r
+        const void *l,
+        const void *r
 ) {
     void *const *lptr = l;
     void *const *rptr = r;
-    void const *left = lptr == NULL ? NULL : *lptr;
-    void const *right = rptr == NULL ? NULL : *rptr;
+    const void *left = lptr == NULL ? NULL : *lptr;
+    const void *right = rptr == NULL ? NULL : *rptr;
     return cx_pl_cmpfunc_impl(left, right);
 }
 
-static void cx_pl_hack_cmpfunc(struct cx_list_s const *list) {
+static void cx_pl_hack_cmpfunc(const struct cx_list_s *list) {
     // cast away const - this is the hacky thing
-    struct cx_list_s *l = (struct cx_list_s *) list;
+    struct cx_collection_s *l = (struct cx_collection_s*) &list->collection;
     cx_pl_cmpfunc_impl = l->cmpfunc;
     l->cmpfunc = cx_pl_cmpfunc;
 }
 
-static void cx_pl_unhack_cmpfunc(struct cx_list_s const *list) {
+static void cx_pl_unhack_cmpfunc(const struct cx_list_s *list) {
     // cast away const - this is the hacky thing
-    struct cx_list_s *l = (struct cx_list_s *) list;
+    struct cx_collection_s *l = (struct cx_collection_s*) &list->collection;
     l->cmpfunc = cx_pl_cmpfunc_impl;
 }
 
@@ -65,7 +65,7 @@
 static int cx_pl_insert_element(
         struct cx_list_s *list,
         size_t index,
-        void const *element
+        const void *element
 ) {
     return list->climpl->insert_element(list, index, &element);
 }
@@ -73,18 +73,29 @@
 static size_t cx_pl_insert_array(
         struct cx_list_s *list,
         size_t index,
-        void const *array,
+        const void *array,
         size_t n
 ) {
     return list->climpl->insert_array(list, index, array, n);
 }
 
+static size_t cx_pl_insert_sorted(
+        struct cx_list_s *list,
+        const void *array,
+        size_t n
+) {
+    cx_pl_hack_cmpfunc(list);
+    size_t result = list->climpl->insert_sorted(list, array, n);
+    cx_pl_unhack_cmpfunc(list);
+    return result;
+}
+
 static int cx_pl_insert_iter(
-        struct cx_mut_iterator_s *iter,
-        void const *elem,
+        struct cx_iterator_s *iter,
+        const void *elem,
         int prepend
 ) {
-    struct cx_list_s *list = iter->src_handle;
+    struct cx_list_s *list = iter->src_handle.m;
     return list->climpl->insert_iter(iter, &elem, prepend);
 }
 
@@ -108,7 +119,7 @@
 }
 
 static void *cx_pl_at(
-        struct cx_list_s const *list,
+        const struct cx_list_s *list,
         size_t index
 ) {
     void **ptr = list->climpl->at(list, index);
@@ -117,7 +128,7 @@
 
 static ssize_t cx_pl_find_remove(
         struct cx_list_s *list,
-        void const *elem,
+        const void *elem,
         bool remove
 ) {
     cx_pl_hack_cmpfunc(list);
@@ -133,8 +144,8 @@
 }
 
 static int cx_pl_compare(
-        struct cx_list_s const *list,
-        struct cx_list_s const *other
+        const struct cx_list_s *list,
+        const struct cx_list_s *other
 ) {
     cx_pl_hack_cmpfunc(list);
     int ret = list->climpl->compare(list, other);
@@ -146,14 +157,14 @@
     list->climpl->reverse(list);
 }
 
-static void *cx_pl_iter_current(void const *it) {
-    struct cx_iterator_s const *iter = it;
+static void *cx_pl_iter_current(const void *it) {
+    const struct cx_iterator_s *iter = it;
     void **ptr = iter->base.current_impl(it);
     return ptr == NULL ? NULL : *ptr;
 }
 
 static struct cx_iterator_s cx_pl_iterator(
-        struct cx_list_s const *list,
+        const struct cx_list_s *list,
         size_t index,
         bool backwards
 ) {
@@ -167,6 +178,7 @@
         cx_pl_destructor,
         cx_pl_insert_element,
         cx_pl_insert_array,
+        cx_pl_insert_sorted,
         cx_pl_insert_iter,
         cx_pl_remove,
         cx_pl_clear,
@@ -180,7 +192,7 @@
 };
 
 void cxListStoreObjects(CxList *list) {
-    list->store_pointer = false;
+    list->collection.store_pointer = false;
     if (list->climpl != NULL) {
         list->cl = list->climpl;
         list->climpl = NULL;
@@ -188,8 +200,8 @@
 }
 
 void cxListStorePointers(CxList *list) {
-    list->item_size = sizeof(void *);
-    list->store_pointer = true;
+    list->collection.elem_size = sizeof(void *);
+    list->collection.store_pointer = true;
     list->climpl = list->cl;
     list->cl = &cx_pointer_list_class;
 }
@@ -203,7 +215,7 @@
 }
 
 static void *cx_emptyl_at(
-        __attribute__((__unused__)) struct cx_list_s const *list,
+        __attribute__((__unused__)) const struct cx_list_s *list,
         __attribute__((__unused__)) size_t index
 ) {
     return NULL;
@@ -211,31 +223,23 @@
 
 static ssize_t cx_emptyl_find_remove(
         __attribute__((__unused__)) struct cx_list_s *list,
-        __attribute__((__unused__)) void const *elem,
+        __attribute__((__unused__)) const void *elem,
         __attribute__((__unused__)) bool remove
 ) {
     return -1;
 }
 
-static int cx_emptyl_compare(
-        __attribute__((__unused__)) struct cx_list_s const *list,
-        struct cx_list_s const *other
-) {
-    if (other->size == 0) return 0;
-    return -1;
-}
-
-static bool cx_emptyl_iter_valid(__attribute__((__unused__)) void const *iter) {
+static bool cx_emptyl_iter_valid(__attribute__((__unused__)) const void *iter) {
     return false;
 }
 
 static CxIterator cx_emptyl_iterator(
-        struct cx_list_s const *list,
+        const struct cx_list_s *list,
         size_t index,
         __attribute__((__unused__)) bool backwards
 ) {
     CxIterator iter = {0};
-    iter.src_handle = list;
+    iter.src_handle.c = list;
     iter.index = index;
     iter.base.valid = cx_emptyl_iter_valid;
     return iter;
@@ -247,25 +251,28 @@
         NULL,
         NULL,
         NULL,
+        NULL,
         cx_emptyl_noop,
         NULL,
         cx_emptyl_at,
         cx_emptyl_find_remove,
         cx_emptyl_noop,
-        cx_emptyl_compare,
+        NULL,
         cx_emptyl_noop,
         cx_emptyl_iterator,
 };
 
 CxList cx_empty_list = {
-        NULL,
-        NULL,
-        0,
-        0,
-        NULL,
-        NULL,
-        NULL,
-        false,
+        {
+                NULL,
+                NULL,
+                0,
+                0,
+                NULL,
+                NULL,
+                NULL,
+                false
+        },
         &cx_empty_list_class,
         NULL
 };
@@ -274,33 +281,177 @@
 
 // </editor-fold>
 
+#define invoke_list_func(name, list, ...) \
+    ((list)->climpl == NULL ? (list)->cl->name : (list)->climpl->name) \
+    (list, __VA_ARGS__)
+
+size_t cx_list_default_insert_array(
+        struct cx_list_s *list,
+        size_t index,
+        const void *data,
+        size_t n
+) {
+    size_t elem_size = list->collection.elem_size;
+    const char *src = data;
+    size_t i = 0;
+    for (; i < n; i++) {
+        if (0 != invoke_list_func(insert_element,
+                                  list, index + i, src + (i * elem_size))) {
+            return i;
+        }
+    }
+    return i;
+}
+
+size_t cx_list_default_insert_sorted(
+        struct cx_list_s *list,
+        const void *sorted_data,
+        size_t n
+) {
+    // corner case
+    if (n == 0) return 0;
+
+    size_t elem_size = list->collection.elem_size;
+    cx_compare_func cmp = list->collection.cmpfunc;
+    const char *src = sorted_data;
+
+    // track indices and number of inserted items
+    size_t di = 0, si = 0, inserted = 0;
+
+    // search the list for insertion points
+    for (; di < list->collection.size; di++) {
+        const void *list_elm = invoke_list_func(at, list, di);
+
+        // compare current list element with first source element
+        // if less or equal, skip
+        if (cmp(list_elm, src) <= 0) {
+            continue;
+        }
+
+        // determine number of consecutive elements that can be inserted
+        size_t ins = 1;
+        const char *next = src;
+        while (++si < n) {
+            next += elem_size;
+            // once we become larger than the list elem, break
+            if (cmp(list_elm, next) <= 0) {
+                break;
+            }
+            // otherwise, we can insert one more
+            ins++;
+        }
+
+        // insert the elements at location si
+        if (ins == 1) {
+            if (0 != invoke_list_func(insert_element,
+                                      list, di, src))
+                return inserted;
+        } else {
+            size_t r = invoke_list_func(insert_array, list, di, src, ins);
+            if (r < ins) return inserted + r;
+        }
+        inserted += ins;
+        di += ins;
+
+        // everything inserted?
+        if (inserted == n) return inserted;
+        src = next;
+    }
+
+    // insert remaining items
+    if (si < n) {
+        inserted += invoke_list_func(insert_array, list, di, src, n - si);
+    }
+
+    return inserted;
+}
+
+void cx_list_default_sort(struct cx_list_s *list) {
+    size_t elem_size = list->collection.elem_size;
+    size_t list_size = list->collection.size;
+    void *tmp = malloc(elem_size * list_size);
+    if (tmp == NULL) abort();
+
+    // copy elements from source array
+    char *loc = tmp;
+    for (size_t i = 0; i < list_size; i++) {
+        void *src = invoke_list_func(at, list, i);
+        memcpy(loc, src, elem_size);
+        loc += elem_size;
+    }
+
+    // qsort
+    qsort(tmp, list_size, elem_size,
+          list->collection.cmpfunc);
+
+    // copy elements back
+    loc = tmp;
+    for (size_t i = 0; i < list_size; i++) {
+        void *dest = invoke_list_func(at, list, i);
+        memcpy(dest, loc, elem_size);
+        loc += elem_size;
+    }
+
+    free(tmp);
+}
+
+int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j) {
+    if (i == j) return 0;
+    if (i >= list->collection.size) return 1;
+    if (j >= list->collection.size) return 1;
+
+    size_t elem_size = list->collection.elem_size;
+
+    void *tmp = malloc(elem_size);
+    if (tmp == NULL) return 1;
+
+    void *ip = invoke_list_func(at, list, i);
+    void *jp = invoke_list_func(at, list, j);
+
+    memcpy(tmp, ip, elem_size);
+    memcpy(ip, jp, elem_size);
+    memcpy(jp, tmp, elem_size);
+
+    free(tmp);
+
+    return 0;
+}
+
 void cxListDestroy(CxList *list) {
     list->cl->destructor(list);
 }
 
 int cxListCompare(
-        CxList const *list,
-        CxList const *other
+        const CxList *list,
+        const CxList *other
 ) {
-    if (
-        // if one is storing pointers but the other is not
-        (list->store_pointer ^ other->store_pointer) ||
+    bool cannot_optimize = false;
+
+    // if one is storing pointers but the other is not
+    cannot_optimize |= list->collection.store_pointer ^ other->collection.store_pointer;
+
+    // if one class is wrapped but the other is not
+    cannot_optimize |= (list->climpl == NULL) ^ (other->climpl == NULL);
 
-        // if one class is wrapped but the other is not
-        ((list->climpl == NULL) ^ (other->climpl == NULL)) ||
+    // if the compare functions do not match or both are NULL
+    if (!cannot_optimize) {
+        cx_compare_func list_cmp = (cx_compare_func) (list->climpl != NULL ?
+                                                      list->climpl->compare : list->cl->compare);
+        cx_compare_func other_cmp = (cx_compare_func) (other->climpl != NULL ?
+                                                       other->climpl->compare : other->cl->compare);
+        cannot_optimize |= list_cmp != other_cmp;
+        cannot_optimize |= list_cmp == NULL;
+    }
 
-        // if the resolved compare functions are not the same
-        ((list->climpl != NULL ? list->climpl->compare : list->cl->compare) !=
-         (other->climpl != NULL ? other->climpl->compare : other->cl->compare))
-    ) {
+    if (cannot_optimize) {
         // lists are definitely different - cannot use internal compare function
-        if (list->size == other->size) {
+        if (list->collection.size == other->collection.size) {
             CxIterator left = list->cl->iterator(list, 0, false);
             CxIterator right = other->cl->iterator(other, 0, false);
-            for (size_t i = 0; i < list->size; i++) {
+            for (size_t i = 0; i < list->collection.size; i++) {
                 void *leftValue = cxIteratorCurrent(left);
                 void *rightValue = cxIteratorCurrent(right);
-                int d = list->cmpfunc(leftValue, rightValue);
+                int d = list->collection.cmpfunc(leftValue, rightValue);
                 if (d != 0) {
                     return d;
                 }
@@ -309,7 +460,7 @@
             }
             return 0;
         } else {
-            return list->size < other->size ? -1 : 1;
+            return list->collection.size < other->collection.size ? -1 : 1;
         }
     } else {
         // lists are compatible
@@ -317,28 +468,20 @@
     }
 }
 
-CxMutIterator cxListMutIteratorAt(
+CxIterator cxListMutIteratorAt(
         CxList *list,
         size_t index
 ) {
     CxIterator it = list->cl->iterator(list, index, false);
     it.base.mutating = true;
-
-    // we know the iterators share the same memory layout
-    CxMutIterator iter;
-    memcpy(&iter, &it, sizeof(CxMutIterator));
-    return iter;
+    return it;
 }
 
-CxMutIterator cxListMutBackwardsIteratorAt(
+CxIterator cxListMutBackwardsIteratorAt(
         CxList *list,
         size_t index
 ) {
     CxIterator it = list->cl->iterator(list, index, true);
     it.base.mutating = true;
-
-    // we know the iterators share the same memory layout
-    CxMutIterator iter;
-    memcpy(&iter, &it, sizeof(CxMutIterator));
-    return iter;
+    return it;
 }

mercurial