X-Git-Url: https://develop.uap-core.de/gitweb/uwplayer.git/blobdiff_plain/67b35790d6ab8581c96b3182e63eb2c0ffab5123..01d5015ba093f8c5fdb18b669943c7da6450e72f:/ucx/list.c diff --git a/ucx/list.c b/ucx/list.c index 293592c..cc96710 100644 --- a/ucx/list.c +++ b/ucx/list.c @@ -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: @@ -26,403 +26,317 @@ * 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 -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; -} +// -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 cx_compare_func 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 ssize_t cx_pl_find( + struct cx_list_s const *list, + void const *elem +) { + cx_pl_hack_cmpfunc(list); + ssize_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) { - - UcxList** sorted = (UcxList**) malloc(sizeof(UcxList*)*length); - UcxList *rc, *lc; - - 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 void cx_pl_reverse(struct cx_list_s *list) { + list->climpl->reverse(list); +} - // 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; +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; +} - UcxList *ret = sorted[0]; - free(sorted); - return ret; +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; } -UcxList *ucx_list_sort(UcxList *l, cmp_func fnc, void *data) { - if (l == NULL) { - return NULL; +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) { + list->store_pointer = false; + if (list->climpl != NULL) { + list->cl = list->climpl; + list->climpl = NULL; } +} - UcxList *lc; - size_t ln = 1; +void cxListStorePointers(CxList *list) { + list->item_size = sizeof(void *); + list->store_pointer = true; + list->climpl = list->cl; + list->cl = &cx_pointer_list_class; +} - 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; +// - 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++; - } - 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; - } +// - return l; - } +static void cx_emptyl_noop(__attribute__((__unused__)) CxList *list) { + // this is a noop, but MUST be implemented } -UcxList *ucx_list_first(const UcxList *l) { - if (!l) { - return NULL; - } - - const UcxList *e = l; - while (e->prev) { - e = e->prev; - } - return (UcxList *)e; +static void *cx_emptyl_at( + __attribute__((__unused__)) struct cx_list_s const *list, + __attribute__((__unused__)) size_t index +) { + return NULL; } -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; - } - - if (e->prev) { - e->prev->next = e->next; - } - - alfree(alloc, e); - return l; +static ssize_t cx_emptyl_find( + __attribute__((__unused__)) struct cx_list_s const *list, + __attribute__((__unused__)) void const *elem +) { + return -1; } - -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; - } - } - if (op == 0 && src == left) - src = right; - else - src = NULL; - } while (src != NULL); - - return res; +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; } -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); +static bool cx_emptyl_iter_valid(__attribute__((__unused__)) void const *iter) { + return false; } -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); +static CxIterator cx_emptyl_iterator( + struct cx_list_s const *list, + size_t index, + __attribute__((__unused__)) bool backwards +) { + CxIterator iter = {0}; + iter.src_handle = list; + iter.index = index; + iter.base.valid = cx_emptyl_iter_valid; + return iter; } -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); +static cx_list_class cx_empty_list_class = { + cx_emptyl_noop, + NULL, + NULL, + NULL, + NULL, + cx_emptyl_noop, + NULL, + cx_emptyl_at, + cx_emptyl_find, + cx_emptyl_noop, + cx_emptyl_compare, + cx_emptyl_noop, + cx_emptyl_iterator, +}; + +CxList cx_empty_list = { + NULL, + NULL, + 0, + 0, + NULL, + NULL, + NULL, + false, + &cx_empty_list_class, + NULL +}; + +CxList *const cxEmptyList = &cx_empty_list; + +// + +void cxListDestroy(CxList *list) { + list->cl->destructor(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 ( + // if one is storing pointers but the other is not + (list->store_pointer ^ other->store_pointer) || + + // if one class is wrapped but the other is not + ((list->climpl == NULL) ^ (other->climpl == 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)) + ) { + // lists are definitely different - cannot use internal compare function + 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; + } + } else { + // lists are compatible + return list->cl->compare(list, other); + } } -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; }