universe@39: /* universe@39: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. universe@39: * universe@39: * Copyright 2015 Olaf Wintermann. All rights reserved. universe@39: * universe@39: * Redistribution and use in source and binary forms, with or without universe@39: * modification, are permitted provided that the following conditions are met: universe@39: * universe@39: * 1. Redistributions of source code must retain the above copyright universe@39: * notice, this list of conditions and the following disclaimer. universe@39: * universe@39: * 2. Redistributions in binary form must reproduce the above copyright universe@39: * notice, this list of conditions and the following disclaimer in the universe@39: * documentation and/or other materials provided with the distribution. universe@39: * universe@39: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" universe@39: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE universe@39: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE universe@39: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE universe@39: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR universe@39: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF universe@39: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS universe@39: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN universe@39: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) universe@39: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE universe@39: * POSSIBILITY OF SUCH DAMAGE. universe@39: */ universe@39: universe@39: #include "list.h" universe@39: universe@39: UcxList *ucx_list_clone(UcxList *l, copy_func fnc, void *data) { universe@39: return ucx_list_clone_a(ucx_default_allocator(), l, fnc, data); universe@39: } universe@39: universe@39: UcxList *ucx_list_clone_a(UcxAllocator *alloc, UcxList *l, universe@39: copy_func fnc, void *data) { universe@39: UcxList *ret = NULL; universe@39: while (l) { universe@39: if (fnc) { universe@39: ret = ucx_list_append_a(alloc, ret, fnc(l->data, data)); universe@39: } else { universe@39: ret = ucx_list_append_a(alloc, ret, l->data); universe@39: } universe@39: l = l->next; universe@39: } universe@39: return ret; universe@39: } universe@39: universe@39: int ucx_list_equals(const UcxList *l1, const UcxList *l2, universe@39: cmp_func fnc, void* data) { universe@39: if (l1 == l2) return 1; universe@39: universe@39: while (l1 != NULL && l2 != NULL) { universe@39: if (fnc == NULL) { universe@39: if (l1->data != l2->data) return 0; universe@39: } else { universe@39: if (fnc(l1->data, l2->data, data) != 0) return 0; universe@39: } universe@39: l1 = l1->next; universe@39: l2 = l2->next; universe@39: } universe@39: universe@39: return (l1 == NULL && l2 == NULL); universe@39: } universe@39: universe@39: void ucx_list_free(UcxList *l) { universe@39: ucx_list_free_a(ucx_default_allocator(), l); universe@39: } universe@39: universe@39: void ucx_list_free_a(UcxAllocator *alloc, UcxList *l) { universe@39: UcxList *e = l, *f; universe@39: while (e != NULL) { universe@39: f = e; universe@39: e = e->next; universe@39: alfree(alloc, f); universe@39: } universe@39: } universe@39: universe@39: void ucx_list_free_content(UcxList* list, ucx_destructor destr) { universe@39: while (list != NULL) { universe@39: destr(list->data); universe@39: list = list->next; universe@39: } universe@39: } universe@39: universe@39: UcxList *ucx_list_append(UcxList *l, void *data) { universe@39: return ucx_list_append_a(ucx_default_allocator(), l, data); universe@39: } universe@39: universe@39: UcxList *ucx_list_append_a(UcxAllocator *alloc, UcxList *l, void *data) { universe@39: UcxList *nl = (UcxList*) almalloc(alloc, sizeof(UcxList)); universe@39: if (!nl) { universe@39: return NULL; universe@39: } universe@39: universe@39: nl->data = data; universe@39: nl->next = NULL; universe@39: if (l) { universe@39: UcxList *t = ucx_list_last(l); universe@39: t->next = nl; universe@39: nl->prev = t; universe@39: return l; universe@39: } else { universe@39: nl->prev = NULL; universe@39: return nl; universe@39: } universe@39: } universe@39: universe@39: UcxList *ucx_list_prepend(UcxList *l, void *data) { universe@39: return ucx_list_prepend_a(ucx_default_allocator(), l, data); universe@39: } universe@39: universe@39: UcxList *ucx_list_prepend_a(UcxAllocator *alloc, UcxList *l, void *data) { universe@39: UcxList *nl = ucx_list_append_a(alloc, NULL, data); universe@39: if (!nl) { universe@39: return NULL; universe@39: } universe@39: l = ucx_list_first(l); universe@39: universe@39: if (l) { universe@39: nl->next = l; universe@39: l->prev = nl; universe@39: } universe@39: return nl; universe@39: } universe@39: universe@39: UcxList *ucx_list_concat(UcxList *l1, UcxList *l2) { universe@39: if (l1) { universe@39: UcxList *last = ucx_list_last(l1); universe@39: last->next = l2; universe@39: if (l2) { universe@39: l2->prev = last; universe@39: } universe@39: return l1; universe@39: } else { universe@39: return l2; universe@39: } universe@39: } universe@39: universe@39: UcxList *ucx_list_last(const UcxList *l) { universe@39: if (l == NULL) return NULL; universe@39: universe@39: const UcxList *e = l; universe@39: while (e->next != NULL) { universe@39: e = e->next; universe@39: } universe@39: return (UcxList*)e; universe@39: } universe@39: universe@39: ssize_t ucx_list_indexof(const UcxList *list, const UcxList *elem) { universe@39: ssize_t index = 0; universe@39: while (list) { universe@39: if (list == elem) { universe@39: return index; universe@39: } universe@39: list = list->next; universe@39: index++; universe@39: } universe@39: return -1; universe@39: } universe@39: universe@39: UcxList *ucx_list_get(const UcxList *l, size_t index) { universe@39: if (l == NULL) return NULL; universe@39: universe@39: const UcxList *e = l; universe@39: while (e->next && index > 0) { universe@39: e = e->next; universe@39: index--; universe@39: } universe@39: universe@39: return (UcxList*)(index == 0 ? e : NULL); universe@39: } universe@39: universe@39: ssize_t ucx_list_find(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) { universe@39: ssize_t index = 0; universe@39: UCX_FOREACH(e, l) { universe@39: if (fnc) { universe@39: if (fnc(elem, e->data, cmpdata) == 0) { universe@39: return index; universe@39: } universe@39: } else { universe@39: if (elem == e->data) { universe@39: return index; universe@39: } universe@39: } universe@39: index++; universe@39: } universe@39: return -1; universe@39: } universe@39: universe@39: int ucx_list_contains(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) { universe@39: return ucx_list_find(l, elem, fnc, cmpdata) > -1; universe@39: } universe@39: universe@39: size_t ucx_list_size(const UcxList *l) { universe@39: if (l == NULL) return 0; universe@39: universe@39: const UcxList *e = l; universe@39: size_t s = 1; universe@39: while (e->next != NULL) { universe@39: e = e->next; universe@39: s++; universe@39: } universe@39: universe@39: return s; universe@39: } universe@39: universe@39: static UcxList *ucx_list_sort_merge(int length, universe@39: UcxList* restrict ls, UcxList* restrict le, UcxList* restrict re, universe@39: cmp_func fnc, void* data) { universe@39: universe@39: UcxList** sorted = (UcxList**) malloc(sizeof(UcxList*)*length); universe@39: UcxList *rc, *lc; universe@39: universe@39: lc = ls; rc = le; universe@39: int n = 0; universe@39: while (lc && lc != le && rc != re) { universe@39: if (fnc(lc->data, rc->data, data) <= 0) { universe@39: sorted[n] = lc; universe@39: lc = lc->next; universe@39: } else { universe@39: sorted[n] = rc; universe@39: rc = rc->next; universe@39: } universe@39: n++; universe@39: } universe@39: while (lc && lc != le) { universe@39: sorted[n] = lc; universe@39: lc = lc->next; universe@39: n++; universe@39: } universe@39: while (rc && rc != re) { universe@39: sorted[n] = rc; universe@39: rc = rc->next; universe@39: n++; universe@39: } universe@39: universe@39: // Update pointer universe@39: sorted[0]->prev = NULL; universe@39: for (int i = 0 ; i < length-1 ; i++) { universe@39: sorted[i]->next = sorted[i+1]; universe@39: sorted[i+1]->prev = sorted[i]; universe@39: } universe@39: sorted[length-1]->next = NULL; universe@39: universe@39: UcxList *ret = sorted[0]; universe@39: free(sorted); universe@39: return ret; universe@39: } universe@39: universe@39: UcxList *ucx_list_sort(UcxList *l, cmp_func fnc, void *data) { universe@39: if (l == NULL) { universe@39: return NULL; universe@39: } universe@39: universe@39: UcxList *lc; universe@39: int ln = 1; universe@39: universe@39: UcxList *restrict ls = l, *restrict le, *restrict re; universe@39: universe@39: // check how many elements are already sorted universe@39: lc = ls; universe@39: while (lc->next != NULL && fnc(lc->next->data, lc->data, data) > 0) { universe@39: lc = lc->next; universe@39: ln++; universe@39: } universe@39: le = lc->next; universe@39: universe@39: if (le == NULL) { universe@39: return l; // this list is already sorted :) universe@39: } else { universe@39: UcxList *rc; universe@39: int rn = 1; universe@39: rc = le; universe@39: // skip already sorted elements universe@39: while (rc->next != NULL && fnc(rc->next->data, rc->data, data) > 0) { universe@39: rc = rc->next; universe@39: rn++; universe@39: } universe@39: re = rc->next; universe@39: universe@39: // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them universe@39: UcxList *sorted = ucx_list_sort_merge(ln+rn, universe@39: ls, le, re, universe@39: fnc, data); universe@39: universe@39: // Something left? Sort it! universe@39: size_t remainder_length = ucx_list_size(re); universe@39: if (remainder_length > 0) { universe@39: UcxList *remainder = ucx_list_sort(re, fnc, data); universe@39: universe@39: // merge sorted list with (also sorted) remainder universe@39: l = ucx_list_sort_merge(ln+rn+remainder_length, universe@39: sorted, remainder, NULL, fnc, data); universe@39: } else { universe@39: // no remainder - we've got our sorted list universe@39: l = sorted; universe@39: } universe@39: universe@39: return l; universe@39: } universe@39: } universe@39: universe@39: UcxList *ucx_list_first(const UcxList *l) { universe@39: if (!l) { universe@39: return NULL; universe@39: } universe@39: universe@39: const UcxList *e = l; universe@39: while (e->prev) { universe@39: e = e->prev; universe@39: } universe@39: return (UcxList *)e; universe@39: } universe@39: universe@39: UcxList *ucx_list_remove(UcxList *l, UcxList *e) { universe@39: return ucx_list_remove_a(ucx_default_allocator(), l, e); universe@39: } universe@39: universe@39: UcxList *ucx_list_remove_a(UcxAllocator *alloc, UcxList *l, UcxList *e) { universe@39: if (l == e) { universe@39: l = e->next; universe@39: } universe@39: universe@39: if (e->next) { universe@39: e->next->prev = e->prev; universe@39: } universe@39: universe@39: if (e->prev) { universe@39: e->prev->next = e->next; universe@39: } universe@39: universe@39: alfree(alloc, e); universe@39: return l; universe@39: }