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