ucx update
[uwplayer.git] / ucx / list.c
index 293592c..ebfff65 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved.
+ * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "ucx/list.h"
+#include "cx/list.h"
 
-UcxList *ucx_list_clone(const UcxList *l, copy_func fnc, void *data) {
-    return ucx_list_clone_a(ucx_default_allocator(), l, fnc, data);
-}
+#include <string.h>
 
-UcxList *ucx_list_clone_a(UcxAllocator *alloc, const UcxList *l,
-        copy_func fnc, void *data) {
-    UcxList *ret = NULL;
-    while (l) {
-        if (fnc) {
-            ret = ucx_list_append_a(alloc, ret, fnc(l->data, data));
-        } else {
-            ret = ucx_list_append_a(alloc, ret, l->data);
-        }
-        l = l->next;
-    }
-    return ret;
-}
+// <editor-fold desc="Store Pointers Functionality">
 
-int ucx_list_equals(const UcxList *l1, const UcxList *l2,
-        cmp_func fnc, void* data) {
-    if (l1 == l2) return 1;
-    
-    while (l1 != NULL && l2 != NULL) {
-        if (fnc == NULL) {
-            if (l1->data != l2->data) return 0;
-        } else {
-            if (fnc(l1->data, l2->data, data) != 0) return 0;
-        }
-        l1 = l1->next;
-        l2 = l2->next;
-    }
-    
-    return (l1 == NULL && l2 == NULL);
-}
+static _Thread_local CxListComparator cx_pl_cmpfunc_impl;
 
-void ucx_list_free(UcxList *l) {
-    ucx_list_free_a(ucx_default_allocator(), l);
+static int cx_pl_cmpfunc(
+        void const *l,
+        void const *r
+) {
+    void *const *lptr = l;
+    void *const *rptr = r;
+    void const *left = lptr == NULL ? NULL : *lptr;
+    void const *right = rptr == NULL ? NULL : *rptr;
+    return cx_pl_cmpfunc_impl(left, right);
 }
 
-void ucx_list_free_a(UcxAllocator *alloc, UcxList *l) {
-    UcxList *e = l, *f;
-    while (e != NULL) {
-        f = e;
-        e = e->next;
-        alfree(alloc, f);
-    }
+static void cx_pl_hack_cmpfunc(struct cx_list_s const *list) {
+    // cast away const - this is the hacky thing
+    struct cx_list_s *l = (struct cx_list_s *) list;
+    cx_pl_cmpfunc_impl = l->cmpfunc;
+    l->cmpfunc = cx_pl_cmpfunc;
 }
 
-void ucx_list_free_content(UcxList* list, ucx_destructor destr) {
-    if (!destr) destr = free;
-    while (list != NULL) {
-        destr(list->data);
-        list = list->next;
-    }
+static void cx_pl_unhack_cmpfunc(struct cx_list_s const *list) {
+    // cast away const - this is the hacky thing
+    struct cx_list_s *l = (struct cx_list_s *) list;
+    l->cmpfunc = cx_pl_cmpfunc_impl;
 }
 
-UcxList *ucx_list_append(UcxList *l, void *data)  {
-    return ucx_list_append_a(ucx_default_allocator(), l, data);
+static void cx_pl_destructor(struct cx_list_s *list) {
+    list->climpl->destructor(list);
 }
 
-UcxList *ucx_list_append_a(UcxAllocator *alloc, UcxList *l, void *data)  {
-    UcxList *nl = (UcxList*) almalloc(alloc, sizeof(UcxList));
-    if (!nl) {
-        return NULL;
-    }
-    
-    nl->data = data;
-    nl->next = NULL;
-    if (l) {
-        UcxList *t = ucx_list_last(l);
-        t->next = nl;
-        nl->prev = t;
-        return l;
-    } else {
-        nl->prev = NULL;
-        return nl;
-    }
+static int cx_pl_insert_element(
+        struct cx_list_s *list,
+        size_t index,
+        void const *element
+) {
+    return list->climpl->insert_element(list, index, &element);
 }
 
-UcxList *ucx_list_prepend(UcxList *l, void *data) {
-    return ucx_list_prepend_a(ucx_default_allocator(), l, data);
+static size_t cx_pl_insert_array(
+        struct cx_list_s *list,
+        size_t index,
+        void const *array,
+        size_t n
+) {
+    return list->climpl->insert_array(list, index, array, n);
 }
 
-UcxList *ucx_list_prepend_a(UcxAllocator *alloc, UcxList *l, void *data) {
-    UcxList *nl = ucx_list_append_a(alloc, NULL, data);
-    if (!nl) {
-        return NULL;
-    }
-    l = ucx_list_first(l);
-    
-    if (l) {
-        nl->next = l;
-        l->prev = nl;
-    }
-    return nl;
+static int cx_pl_insert_iter(
+        struct cx_mut_iterator_s *iter,
+        void const *elem,
+        int prepend
+) {
+    struct cx_list_s *list = iter->src_handle;
+    return list->climpl->insert_iter(iter, &elem, prepend);
 }
 
-UcxList *ucx_list_concat(UcxList *l1, UcxList *l2) {
-    if (l1) {
-        UcxList *last = ucx_list_last(l1);
-        last->next = l2;
-        if (l2) {
-            l2->prev = last;
-        }
-        return l1;
-    } else {
-        return l2;
-    }
+static int cx_pl_remove(
+        struct cx_list_s *list,
+        size_t index
+) {
+    return list->climpl->remove(list, index);
 }
 
-UcxList *ucx_list_last(const UcxList *l) {
-    if (l == NULL) return NULL;
-    
-    const UcxList *e = l;
-    while (e->next != NULL) {
-        e = e->next;
-    }
-    return (UcxList*)e;
+static void cx_pl_clear(struct cx_list_s *list) {
+    list->climpl->clear(list);
 }
 
-ssize_t ucx_list_indexof(const UcxList *list, const UcxList *elem) {
-    ssize_t index = 0;
-    while (list) {
-        if (list == elem) {
-            return index;
-        }
-        list = list->next;
-        index++;
-    }
-    return -1;
+static int cx_pl_swap(
+        struct cx_list_s *list,
+        size_t i,
+        size_t j
+) {
+    return list->climpl->swap(list, i, j);
 }
 
-UcxList *ucx_list_get(const UcxList *l, size_t index) {
-    if (l == NULL) return NULL;
-
-    const UcxList *e = l;
-    while (e->next && index > 0) {
-        e = e->next;
-        index--;
-    }
-    
-    return (UcxList*)(index == 0 ? e : NULL);
+static void *cx_pl_at(
+        struct cx_list_s const *list,
+        size_t index
+) {
+    void **ptr = list->climpl->at(list, index);
+    return ptr == NULL ? NULL : *ptr;
 }
 
-ssize_t ucx_list_find(const UcxList *l, void *elem,
-        cmp_func fnc, void *cmpdata) {
-    ssize_t index = 0;
-    UCX_FOREACH(e, l) {
-        if (fnc) {
-            if (fnc(elem, e->data, cmpdata) == 0) {
-                return index;
-            }
-        } else {
-            if (elem == e->data) {
-                return index;
-            }
-        }
-        index++;
-    }
-    return -1;
+static size_t cx_pl_find(
+        struct cx_list_s const *list,
+        void const *elem
+) {
+    cx_pl_hack_cmpfunc(list);
+    size_t ret = list->climpl->find(list, &elem);
+    cx_pl_unhack_cmpfunc(list);
+    return ret;
 }
 
-int ucx_list_contains(const UcxList *l, void *elem,
-        cmp_func fnc, void *cmpdata) {
-    return ucx_list_find(l, elem, fnc, cmpdata) > -1;
+static void cx_pl_sort(struct cx_list_s *list) {
+    cx_pl_hack_cmpfunc(list);
+    list->climpl->sort(list);
+    cx_pl_unhack_cmpfunc(list);
 }
 
-size_t ucx_list_size(const UcxList *l) {
-    if (l == NULL) return 0;
-    
-    const UcxList *e = l;
-    size_t s = 1;
-    while (e->next != NULL) {
-        e = e->next;
-        s++;
-    }
-
-    return s;
+static int cx_pl_compare(
+        struct cx_list_s const *list,
+        struct cx_list_s const *other
+) {
+    cx_pl_hack_cmpfunc(list);
+    int ret = list->climpl->compare(list, other);
+    cx_pl_unhack_cmpfunc(list);
+    return ret;
 }
 
-static UcxList *ucx_list_sort_merge(size_t length,
-        UcxList* ls, UcxList* le, UcxList* re,
-        cmp_func fnc, void* data) {
+static void cx_pl_reverse(struct cx_list_s *list) {
+    list->climpl->reverse(list);
+}
 
-    UcxList** sorted = (UcxList**) malloc(sizeof(UcxList*)*length);
-    UcxList *rc, *lc;
+static void *cx_pl_iter_current(void const *it) {
+    struct cx_iterator_s const *iter = it;
+    void **ptr = iter->base.current_impl(it);
+    return ptr == NULL ? NULL : *ptr;
+}
 
-    lc = ls; rc = le;
-    size_t n = 0;
-    while (lc && lc != le && rc != re) {
-        if (fnc(lc->data, rc->data, data) <= 0) {
-            sorted[n] = lc;
-            lc = lc->next;
-        } else {
-            sorted[n] = rc;
-            rc = rc->next;
-        }
-        n++;
-    }
-    while (lc && lc != le) {
-        sorted[n] = lc;
-        lc = lc->next;
-        n++;
-    }
-    while (rc && rc != re) {
-        sorted[n] = rc;
-        rc = rc->next;
-        n++;
-    }
+static struct cx_iterator_s cx_pl_iterator(
+        struct cx_list_s const *list,
+        size_t index,
+        bool backwards
+) {
+    struct cx_iterator_s iter = list->climpl->iterator(list, index, backwards);
+    iter.base.current_impl = iter.base.current;
+    iter.base.current = cx_pl_iter_current;
+    return iter;
+}
 
-    // Update pointer
-    sorted[0]->prev = NULL;
-    for (int i = 0 ; i < length-1 ; i++) {
-        sorted[i]->next = sorted[i+1];
-        sorted[i+1]->prev = sorted[i];
+static cx_list_class cx_pointer_list_class = {
+        cx_pl_destructor,
+        cx_pl_insert_element,
+        cx_pl_insert_array,
+        cx_pl_insert_iter,
+        cx_pl_remove,
+        cx_pl_clear,
+        cx_pl_swap,
+        cx_pl_at,
+        cx_pl_find,
+        cx_pl_sort,
+        cx_pl_compare,
+        cx_pl_reverse,
+        cx_pl_iterator,
+};
+
+void cxListStoreObjects(CxList *list) {
+    if (list->climpl != NULL) {
+        list->cl = list->climpl;
+        list->climpl = NULL;
     }
-    sorted[length-1]->next = NULL;
-
-    UcxList *ret = sorted[0];
-    free(sorted);
-    return ret;
 }
 
-UcxList *ucx_list_sort(UcxList *l, cmp_func fnc, void *data) {
-    if (l == NULL) {
-        return NULL;
-    }
+void cxListStorePointers(CxList *list) {
+    list->itemsize = sizeof(void *);
+    list->climpl = list->cl;
+    list->cl = &cx_pointer_list_class;
+}
 
-    UcxList *lc;
-    size_t ln = 1;
+bool cxListIsStoringPointers(CxList const *list) {
+    return list->climpl != NULL;
+}
 
-    UcxList *ls = l, *le, *re;
-    
-    // check how many elements are already sorted
-    lc = ls;
-    while (lc->next != NULL && fnc(lc->next->data, lc->data, data) > 0) {
-        lc = lc->next;
-        ln++;
-    }
-    le = lc->next;
+// </editor-fold>
 
-    if (le == NULL) {
-        return l; // this list is already sorted :)
-    } else {
-        UcxList *rc;
-        size_t rn = 1;
-        rc = le;
-        // skip already sorted elements
-        while (rc->next != NULL && fnc(rc->next->data, rc->data, data) > 0) {
-            rc = rc->next;
-            rn++;
+void cx_list_invoke_destructor(
+        CxList const *list,
+        void *elem
+) {
+    switch (list->content_destructor_type) {
+        case CX_DESTRUCTOR_SIMPLE: {
+            cx_list_invoke_simple_destructor(list, elem);
+            break;
         }
-        re = rc->next;
-
-        // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them
-        UcxList *sorted = ucx_list_sort_merge(ln+rn,
-                ls, le, re,
-                fnc, data);
-        
-        // Something left? Sort it!
-        size_t remainder_length = ucx_list_size(re);
-        if (remainder_length > 0) {
-            UcxList *remainder = ucx_list_sort(re, fnc, data);
-
-            // merge sorted list with (also sorted) remainder
-            l = ucx_list_sort_merge(ln+rn+remainder_length,
-                    sorted, remainder, NULL, fnc, data);
-        } else {
-            // no remainder - we've got our sorted list
-            l = sorted;
+        case CX_DESTRUCTOR_ADVANCED: {
+            cx_list_invoke_advanced_destructor(list, elem);
+            break;
         }
-
-        return l;
+        case CX_DESTRUCTOR_NONE:
+            break; // nothing
     }
 }
 
-UcxList *ucx_list_first(const UcxList *l) {
-    if (!l) {
-        return NULL;
-    }
-    
-    const UcxList *e = l;
-    while (e->prev) {
-        e = e->prev;
+void cx_list_invoke_simple_destructor(
+        CxList const *list,
+        void *elem
+) {
+    if (cxListIsStoringPointers(list)) {
+        elem = *((void **) elem);
     }
-    return (UcxList *)e;
+    list->simple_destructor(elem);
 }
 
-UcxList *ucx_list_remove(UcxList *l, UcxList *e) {
-    return ucx_list_remove_a(ucx_default_allocator(), l, e);
-}
-    
-UcxList *ucx_list_remove_a(UcxAllocator *alloc, UcxList *l, UcxList *e) {
-    if (l == e) {
-        l = e->next;
-    }
-    
-    if (e->next) {
-        e->next->prev = e->prev;
+void cx_list_invoke_advanced_destructor(
+        CxList const *list,
+        void *elem
+) {
+    if (cxListIsStoringPointers(list)) {
+        elem = *((void **) elem);
     }
-    
-    if (e->prev) {
-        e->prev->next = e->next;
-    }
-    
-    alfree(alloc, e);
-    return l;
+    list->advanced_destructor.func(list->advanced_destructor.data, elem);
 }
 
-
-static UcxList* ucx_list_setoperation_a(UcxAllocator *allocator,
-        UcxList const *left, UcxList const *right,
-        cmp_func cmpfnc, void* cmpdata,
-        copy_func cpfnc, void* cpdata,
-        int op) {
-    
-    UcxList *res = NULL;
-    UcxList *cur = NULL;
-    const UcxList *src = left;
-    
-    do {
-        UCX_FOREACH(node, src) {
-            void* elem = node->data;
-            if (
-                (op == 0 && !ucx_list_contains(res, elem, cmpfnc, cmpdata)) ||
-                (op == 1 && ucx_list_contains(right, elem, cmpfnc, cmpdata)) ||
-                (op == 2 && !ucx_list_contains(right, elem, cmpfnc, cmpdata))) {
-                UcxList *nl = almalloc(allocator, sizeof(UcxList));
-                nl->prev = cur;
-                nl->next = NULL;
-                if (cpfnc) {
-                    nl->data = cpfnc(elem, cpdata);
-                } else {
-                    nl->data = elem;
-                }
-                if (cur != NULL)
-                    cur->next = nl;
-                cur = nl;
-                if (res == NULL)
-                    res = cur;
+void cxListDestroy(CxList *list) {
+    switch (list->content_destructor_type) {
+        case CX_DESTRUCTOR_SIMPLE: {
+            CxIterator iter = cxListIterator(list);
+            cx_foreach(void*, elem, iter) {
+                // already correctly resolved pointer - immediately invoke dtor
+                list->simple_destructor(elem);
             }
+            break;
         }
-        if (op == 0 && src == left)
-            src = right;
-        else
-            src = NULL;
-    } while (src != NULL);
-    
-    return res;
-}
-
-UcxList* ucx_list_union(UcxList const *left, UcxList const *right,
-        cmp_func cmpfnc, void* cmpdata,
-        copy_func cpfnc, void* cpdata) {
-    return ucx_list_union_a(ucx_default_allocator(),
-            left, right, cmpfnc, cmpdata, cpfnc, cpdata);
-}
-
-UcxList* ucx_list_union_a(UcxAllocator *allocator,
-        UcxList const *left, UcxList const *right,
-        cmp_func cmpfnc, void* cmpdata,
-        copy_func cpfnc, void* cpdata) {
-    
-    return ucx_list_setoperation_a(allocator, left, right,
-            cmpfnc, cmpdata, cpfnc, cpdata, 0);
-}
+        case CX_DESTRUCTOR_ADVANCED: {
+            CxIterator iter = cxListIterator(list);
+            cx_foreach(void*, elem, iter) {
+                // already correctly resolved pointer - immediately invoke dtor
+                list->advanced_destructor.func(list->advanced_destructor.data, elem);
+            }
+            break;
+        }
+        case CX_DESTRUCTOR_NONE:
+            break; // nothing
+    }
 
-UcxList* ucx_list_intersection(UcxList const *left, UcxList const *right,
-        cmp_func cmpfnc, void* cmpdata,
-        copy_func cpfnc, void* cpdata) {
-    return ucx_list_intersection_a(ucx_default_allocator(), left, right,
-            cmpfnc, cmpdata, cpfnc, cpdata);
+    list->cl->destructor(list);
+    cxFree(list->allocator, list);
 }
 
-UcxList* ucx_list_intersection_a(UcxAllocator *allocator,
-        UcxList const *left, UcxList const *right,
-        cmp_func cmpfnc, void* cmpdata,
-        copy_func cpfnc, void* cpdata) {
-    
-    return ucx_list_setoperation_a(allocator, left, right,
-            cmpfnc, cmpdata, cpfnc, cpdata, 1);
+int cxListCompare(
+        CxList const *list,
+        CxList const *other
+) {
+    if (list->cl->compare == other->cl->compare) {
+        // same compare function, lists are compatible
+        return list->cl->compare(list, other);
+    } else {
+        // different compare functions, use iterator
+        if (list->size == other->size) {
+            CxIterator left = cxListIterator(list);
+            CxIterator right = cxListIterator(other);
+            for (size_t i = 0; i < list->size; i++) {
+                void *leftValue = cxIteratorCurrent(left);
+                void *rightValue = cxIteratorCurrent(right);
+                int d = list->cmpfunc(leftValue, rightValue);
+                if (d != 0) {
+                    return d;
+                }
+                cxIteratorNext(left);
+                cxIteratorNext(right);
+            }
+            return 0;
+        } else {
+            return list->size < other->size ? -1 : 1;
+        }
+    }
 }
 
-UcxList* ucx_list_difference(UcxList const *left, UcxList const *right,
-        cmp_func cmpfnc, void* cmpdata,
-        copy_func cpfnc, void* cpdata) {
-    return ucx_list_difference_a(ucx_default_allocator(), left, right,
-            cmpfnc, cmpdata, cpfnc, cpdata);
+CxMutIterator 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;
 }
 
-UcxList* ucx_list_difference_a(UcxAllocator *allocator,
-        UcxList const *left, UcxList const *right,
-        cmp_func cmpfnc, void* cmpdata,
-        copy_func cpfnc, void* cpdata) {
-    
-    return ucx_list_setoperation_a(allocator, left, right,
-            cmpfnc, cmpdata, cpfnc, cpdata, 2);
+CxMutIterator 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;
 }