#include "ucx/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);
}
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);
}
void ucx_list_free(UcxList *l) {
ucx_list_free_a(ucx_default_allocator(), l);
}
void ucx_list_free_a(UcxAllocator *alloc, UcxList *l) {
UcxList *e = l, *f;
while (e !=
NULL) {
f = e;
e = e->next;
alfree(alloc, f);
}
}
void ucx_list_free_content(UcxList* list, ucx_destructor destr) {
if (!destr) destr = free;
while (list !=
NULL) {
destr(list->data);
list = list->next;
}
}
UcxList *ucx_list_append(UcxList *l,
void *data) {
return ucx_list_append_a(ucx_default_allocator(), l, data);
}
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;
}
}
UcxList *ucx_list_prepend(UcxList *l,
void *data) {
return ucx_list_prepend_a(ucx_default_allocator(), l, data);
}
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;
}
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;
}
}
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;
}
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;
}
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);
}
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;
}
int ucx_list_contains(
const UcxList *l,
void *elem,
cmp_func fnc,
void *cmpdata) {
return ucx_list_find(l, elem, fnc, cmpdata) > -
1;
}
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 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++;
}
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;
UcxList *ret = sorted[
0];
free(sorted);
return ret;
}
UcxList *ucx_list_sort(UcxList *l, cmp_func fnc,
void *data) {
if (l ==
NULL) {
return NULL;
}
UcxList *lc;
size_t ln =
1;
UcxList *ls = l, *le, *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;
}
else {
UcxList *rc;
size_t rn =
1;
rc = le;
while (rc->next !=
NULL && fnc(rc->next->data, rc->data, data) >
0) {
rc = rc->next;
rn++;
}
re = rc->next;
UcxList *sorted = ucx_list_sort_merge(ln+rn,
ls, le, re,
fnc, data);
size_t remainder_length = ucx_list_size(re);
if (remainder_length >
0) {
UcxList *remainder = ucx_list_sort(re, fnc, data);
l = ucx_list_sort_merge(ln+rn+remainder_length,
sorted, remainder,
NULL, fnc, data);
}
else {
l = sorted;
}
return l;
}
}
UcxList *ucx_list_first(
const UcxList *l) {
if (!l) {
return NULL;
}
const UcxList *e = l;
while (e->prev) {
e = e->prev;
}
return (UcxList *)e;
}
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 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;
}
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);
}
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);
}
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);
}
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);
}
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);
}