/*
* 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;
}