#include "cx/list.h"
#include <string.h>
static _Thread_local cx_compare_func cx_pl_cmpfunc_impl;
static int cx_pl_cmpfunc(
const void *l,
const void *r
) {
void *
const *lptr = l;
void *
const *rptr = r;
const void *left = lptr ==
NULL ?
NULL : *lptr;
const void *right = rptr ==
NULL ?
NULL : *rptr;
return cx_pl_cmpfunc_impl(left, right);
}
static void cx_pl_hack_cmpfunc(
const struct cx_list_s *list) {
struct cx_collection_s *l = (
struct cx_collection_s*) &list->collection;
cx_pl_cmpfunc_impl = l->cmpfunc;
l->cmpfunc = cx_pl_cmpfunc;
}
static void cx_pl_unhack_cmpfunc(
const struct cx_list_s *list) {
struct cx_collection_s *l = (
struct cx_collection_s*) &list->collection;
l->cmpfunc = cx_pl_cmpfunc_impl;
}
static void cx_pl_destructor(
struct cx_list_s *list) {
list->climpl->destructor(list);
}
static int cx_pl_insert_element(
struct cx_list_s *list,
size_t index,
const void *element
) {
return list->climpl->insert_element(list, index, &element);
}
static size_t cx_pl_insert_array(
struct cx_list_s *list,
size_t index,
const void *array,
size_t n
) {
return list->climpl->insert_array(list, index, array, n);
}
static size_t cx_pl_insert_sorted(
struct cx_list_s *list,
const void *array,
size_t n
) {
cx_pl_hack_cmpfunc(list);
size_t result = list->climpl->insert_sorted(list, array, n);
cx_pl_unhack_cmpfunc(list);
return result;
}
static int cx_pl_insert_iter(
struct cx_iterator_s *iter,
const void *elem,
int prepend
) {
struct cx_list_s *list = iter->src_handle.m;
return list->climpl->insert_iter(iter, &elem, prepend);
}
static int cx_pl_remove(
struct cx_list_s *list,
size_t index
) {
return list->climpl->remove(list, index);
}
static void cx_pl_clear(
struct cx_list_s *list) {
list->climpl->clear(list);
}
static int cx_pl_swap(
struct cx_list_s *list,
size_t i,
size_t j
) {
return list->climpl->swap(list, i, j);
}
static void *cx_pl_at(
const struct cx_list_s *list,
size_t index
) {
void **ptr = list->climpl->at(list, index);
return ptr ==
NULL ?
NULL : *ptr;
}
static ssize_t cx_pl_find_remove(
struct cx_list_s *list,
const void *elem,
bool remove
) {
cx_pl_hack_cmpfunc(list);
ssize_t ret = list->climpl->find_remove(list, &elem, remove);
cx_pl_unhack_cmpfunc(list);
return ret;
}
static void cx_pl_sort(
struct cx_list_s *list) {
cx_pl_hack_cmpfunc(list);
list->climpl->sort(list);
cx_pl_unhack_cmpfunc(list);
}
static int cx_pl_compare(
const struct cx_list_s *list,
const struct cx_list_s *other
) {
cx_pl_hack_cmpfunc(list);
int ret = list->climpl->compare(list, other);
cx_pl_unhack_cmpfunc(list);
return ret;
}
static void cx_pl_reverse(
struct cx_list_s *list) {
list->climpl->reverse(list);
}
static void *cx_pl_iter_current(
const void *it) {
const struct cx_iterator_s *iter = it;
void **ptr = iter->base.current_impl(it);
return ptr ==
NULL ?
NULL : *ptr;
}
static struct cx_iterator_s cx_pl_iterator(
const struct cx_list_s *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;
}
static cx_list_class cx_pointer_list_class = {
cx_pl_destructor,
cx_pl_insert_element,
cx_pl_insert_array,
cx_pl_insert_sorted,
cx_pl_insert_iter,
cx_pl_remove,
cx_pl_clear,
cx_pl_swap,
cx_pl_at,
cx_pl_find_remove,
cx_pl_sort,
cx_pl_compare,
cx_pl_reverse,
cx_pl_iterator,
};
void cxListStoreObjects(CxList *list) {
list->collection.store_pointer = false;
if (list->climpl !=
NULL) {
list->cl = list->climpl;
list->climpl =
NULL;
}
}
void cxListStorePointers(CxList *list) {
list->collection.elem_size =
sizeof(
void *);
list->collection.store_pointer = true;
list->climpl = list->cl;
list->cl = &cx_pointer_list_class;
}
static void cx_emptyl_noop(__attribute__((__unused__)) CxList *list) {
}
static void *cx_emptyl_at(
__attribute__((__unused__))
const struct cx_list_s *list,
__attribute__((__unused__))
size_t index
) {
return NULL;
}
static ssize_t cx_emptyl_find_remove(
__attribute__((__unused__))
struct cx_list_s *list,
__attribute__((__unused__))
const void *elem,
__attribute__((__unused__)) bool remove
) {
return -
1;
}
static bool cx_emptyl_iter_valid(__attribute__((__unused__))
const void *iter) {
return false;
}
static CxIterator cx_emptyl_iterator(
const struct cx_list_s *list,
size_t index,
__attribute__((__unused__)) bool backwards
) {
CxIterator iter = {
0};
iter.src_handle.c = list;
iter.index = index;
iter.base.valid = cx_emptyl_iter_valid;
return iter;
}
static cx_list_class cx_empty_list_class = {
cx_emptyl_noop,
NULL,
NULL,
NULL,
NULL,
NULL,
cx_emptyl_noop,
NULL,
cx_emptyl_at,
cx_emptyl_find_remove,
cx_emptyl_noop,
NULL,
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;
#define invoke_list_func(name, list, ...) \
((list)->climpl ==
NULL ? (list)->cl->name : (list)->climpl->name) \
(list,
__VA_ARGS__)
size_t cx_list_default_insert_array(
struct cx_list_s *list,
size_t index,
const void *data,
size_t n
) {
size_t elem_size = list->collection.elem_size;
const char *src = data;
size_t i =
0;
for (; i < n; i++) {
if (
0 != invoke_list_func(insert_element,
list, index + i, src + (i * elem_size))) {
return i;
}
}
return i;
}
size_t cx_list_default_insert_sorted(
struct cx_list_s *list,
const void *sorted_data,
size_t n
) {
if (n ==
0)
return 0;
size_t elem_size = list->collection.elem_size;
cx_compare_func cmp = list->collection.cmpfunc;
const char *src = sorted_data;
size_t di =
0, si =
0, inserted =
0;
for (; di < list->collection.size; di++) {
const void *list_elm = invoke_list_func(at, list, di);
if (cmp(list_elm, src) <=
0) {
continue;
}
size_t ins =
1;
const char *next = src;
while (++si < n) {
next += elem_size;
if (cmp(list_elm, next) <=
0) {
break;
}
ins++;
}
if (ins ==
1) {
if (
0 != invoke_list_func(insert_element,
list, di, src))
return inserted;
}
else {
size_t r = invoke_list_func(insert_array, list, di, src, ins);
if (r < ins)
return inserted + r;
}
inserted += ins;
di += ins;
if (inserted == n)
return inserted;
src = next;
}
if (si < n) {
inserted += invoke_list_func(insert_array, list, di, src, n - si);
}
return inserted;
}
void cx_list_default_sort(
struct cx_list_s *list) {
size_t elem_size = list->collection.elem_size;
size_t list_size = list->collection.size;
void *tmp = malloc(elem_size * list_size);
if (tmp ==
NULL) abort();
char *loc = tmp;
for (
size_t i =
0; i < list_size; i++) {
void *src = invoke_list_func(at, list, i);
memcpy(loc, src, elem_size);
loc += elem_size;
}
qsort(tmp, list_size, elem_size,
list->collection.cmpfunc);
loc = tmp;
for (
size_t i =
0; i < list_size; i++) {
void *dest = invoke_list_func(at, list, i);
memcpy(dest, loc, elem_size);
loc += elem_size;
}
free(tmp);
}
int cx_list_default_swap(
struct cx_list_s *list,
size_t i,
size_t j) {
if (i == j)
return 0;
if (i >= list->collection.size)
return 1;
if (j >= list->collection.size)
return 1;
size_t elem_size = list->collection.elem_size;
void *tmp = malloc(elem_size);
if (tmp ==
NULL)
return 1;
void *ip = invoke_list_func(at, list, i);
void *jp = invoke_list_func(at, list, j);
memcpy(tmp, ip, elem_size);
memcpy(ip, jp, elem_size);
memcpy(jp, tmp, elem_size);
free(tmp);
return 0;
}
void cxListDestroy(CxList *list) {
list->cl->destructor(list);
}
int cxListCompare(
const CxList *list,
const CxList *other
) {
bool cannot_optimize = false;
cannot_optimize |= list->collection.store_pointer ^ other->collection.store_pointer;
cannot_optimize |= (list->climpl ==
NULL) ^ (other->climpl ==
NULL);
if (!cannot_optimize) {
cx_compare_func list_cmp = (cx_compare_func) (list->climpl !=
NULL ?
list->climpl->compare : list->cl->compare);
cx_compare_func other_cmp = (cx_compare_func) (other->climpl !=
NULL ?
other->climpl->compare : other->cl->compare);
cannot_optimize |= list_cmp != other_cmp;
cannot_optimize |= list_cmp ==
NULL;
}
if (cannot_optimize) {
if (list->collection.size == other->collection.size) {
CxIterator left = list->cl->iterator(list,
0, false);
CxIterator right = other->cl->iterator(other,
0, false);
for (
size_t i =
0; i < list->collection.size; i++) {
void *leftValue = cxIteratorCurrent(left);
void *rightValue = cxIteratorCurrent(right);
int d = list->collection.cmpfunc(leftValue, rightValue);
if (d !=
0) {
return d;
}
cxIteratorNext(left);
cxIteratorNext(right);
}
return 0;
}
else {
return list->collection.size < other->collection.size ? -
1 :
1;
}
}
else {
return list->cl->compare(list, other);
}
}
CxIterator cxListMutIteratorAt(
CxList *list,
size_t index
) {
CxIterator it = list->cl->iterator(list, index, false);
it.base.mutating = true;
return it;
}
CxIterator cxListMutBackwardsIteratorAt(
CxList *list,
size_t index
) {
CxIterator it = list->cl->iterator(list, index, true);
it.base.mutating = true;
return it;
}