ucx/dlist.c

changeset 1
1bcaac272cdf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/dlist.c	Fri Nov 30 21:18:13 2012 +0100
@@ -0,0 +1,234 @@
+#include "dlist.h"
+
+UcxDlist *restrict ucx_dlist_clone(UcxDlist *restrict l,
+        copy_func fnc, void *data) {
+    UcxDlist *ret = NULL;
+    while (l != NULL) {
+        if (fnc != NULL) {
+            ret = ucx_dlist_append(ret, fnc(l->data, data));
+        } else {
+            ret = ucx_dlist_append(ret, l->data);
+        }
+        l = l->next;
+    }
+    return ret;
+}
+
+int ucx_dlist_equals(const UcxDlist *l1, const UcxDlist *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);
+}
+
+void ucx_dlist_free(UcxDlist *l) {
+    UcxDlist *e = l, *f;
+    while (e != NULL) {
+        f = e;
+        e = e->next;
+        free(f);
+    }
+}
+
+UcxDlist *ucx_dlist_append(UcxDlist *l, void *data)  {
+    UcxDlist *nl = (UcxDlist*) malloc(sizeof(UcxDlist));
+    if (nl == NULL) return NULL;
+    
+    nl->data = data;
+    nl->next = NULL;
+    if (l == NULL) {
+        nl->prev = NULL;
+        return nl;
+    } else {
+        UcxDlist *t = ucx_dlist_last(l);
+        t->next = nl;
+        nl->prev = t;
+        return l;
+    }
+}
+
+UcxDlist *ucx_dlist_prepend(UcxDlist *l, void *data) {
+    UcxDlist *nl = ucx_dlist_append(NULL, data);
+    if (nl == NULL) return NULL;
+    
+    if (l != NULL) {
+        nl->next = l;
+        l->prev = nl;
+    }
+    return nl;
+}
+
+UcxDlist *ucx_dlist_concat(UcxDlist *restrict l1, UcxDlist *restrict l2) {
+    if (l1 == NULL) {
+        return l2;
+    } else {
+        UcxDlist *last = ucx_dlist_last(l1);
+        last->next = l2;
+        l2->prev = last;
+        return l1;
+    }
+}
+
+UcxDlist *ucx_dlist_last(const UcxDlist *l) {
+    if (l == NULL) return NULL;
+    
+    const UcxDlist *e = l;
+    while (e->next != NULL) {
+        e = e->next;
+    }
+    return (UcxDlist*)e;
+}
+
+UcxDlist *ucx_dlist_get(const UcxDlist *l, int index) {
+    if (l == NULL) return NULL;
+
+    const UcxDlist *e = l;
+    while (e->next != NULL && index > 0) {
+        e = e->next;
+        index--;
+    }
+    
+    return (UcxDlist*)(index == 0 ? e : NULL);
+}
+
+size_t ucx_dlist_size(const UcxDlist *l) {
+    if (l == NULL) return 0;
+    
+    const UcxDlist *e = l;
+    size_t s = 1;
+    while (e->next != NULL) {
+        e = e->next;
+        s++;
+    }
+
+    return s;
+}
+
+UcxDlist *ucx_dlist_sort_merge(int length,
+        UcxDlist* restrict ls, UcxDlist* restrict le, UcxDlist* restrict re,
+        cmp_func fnc, void* data) {
+
+    UcxDlist** sorted = (UcxDlist**) malloc(sizeof(UcxDlist*)*length);
+    UcxDlist *rc, *lc;
+
+    lc = ls; rc = le;
+    int 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++;
+    }
+
+    // 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];
+    }
+    sorted[length-1]->next = NULL;
+
+    UcxDlist *ret = sorted[0];
+    free(sorted);
+    return ret;
+}
+
+UcxDlist *ucx_dlist_sort(UcxDlist *l, cmp_func fnc, void *data) {
+    if (l == NULL) {
+        return NULL;
+    }
+
+    UcxDlist *lc;
+    int ln = 1;
+
+    UcxDlist *restrict ls = l, *restrict le, *restrict re;
+    lc = ls;
+    while (lc->next != NULL && fnc(lc->next->data, lc->data, data) > 0) {
+        lc = lc->next;
+        ln++;
+    }
+    le = lc->next;
+
+    if (le == NULL) {
+        return l; // this list is already sorted :)
+    } else {
+        UcxDlist *rc;
+        int rn = 1;
+        rc = le;
+        while (rc->next != NULL && fnc(rc->next->data, rc->data, data) > 0) {
+            rc = rc->next;
+            rn++;
+        }
+        re = rc->next;
+
+        // Something left? Sort it!
+        UcxDlist *remainder = re;
+        size_t remainder_length = ucx_dlist_size(remainder);
+        if (remainder != NULL) {
+            remainder = ucx_dlist_sort(remainder, fnc, data);
+        }
+
+        // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them
+        UcxDlist *sorted = ucx_dlist_sort_merge(ln+rn,
+                ls, le, re,
+                fnc, data);
+
+        // merge sorted list with (also sorted) remainder
+        l = ucx_dlist_sort_merge(ln+rn+remainder_length,
+                sorted, remainder, NULL, fnc, data);
+
+        return l;
+    }
+}
+
+/* dlist specific functions */
+UcxDlist *ucx_dlist_first(const UcxDlist *l) {
+    if (l == NULL) return NULL;
+    
+    const UcxDlist *e = l;
+    while (e->prev != NULL) {
+        e = e->prev;
+    }
+    return (UcxDlist *)e;
+}
+
+UcxDlist *ucx_dlist_remove(UcxDlist *l, UcxDlist *e) {
+    if (e->prev == NULL) {
+        if(e->next != NULL) {
+            e->next->prev = NULL;
+            l = e->next;
+        } else {
+            l = NULL;
+        }
+        
+    } else {
+        e->prev->next = e->next;
+        e->next->prev = e->prev;
+    }
+    free(e);
+    return l;
+}

mercurial