#include "cx/list.h"
#include <string.h>
static _Thread_local cx_compare_func cx_pl_cmpfunc_impl;
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);
}
static void cx_pl_hack_cmpfunc(
struct cx_list_s
const *list) {
struct cx_list_s *l = (
struct cx_list_s *) list;
cx_pl_cmpfunc_impl = l->cmpfunc;
l->cmpfunc = cx_pl_cmpfunc;
}
static void cx_pl_unhack_cmpfunc(
struct cx_list_s
const *list) {
struct cx_list_s *l = (
struct cx_list_s *) list;
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,
void const *element
) {
return list->climpl->insert_element(list, index, &element);
}
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);
}
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);
}
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(
struct cx_list_s
const *list,
size_t index
) {
void **ptr = list->climpl->at(list, index);
return ptr ==
NULL ?
NULL : *ptr;
}
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;
}
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(
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 void cx_pl_reverse(
struct cx_list_s *list) {
list->climpl->reverse(list);
}
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;
}
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;
}
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;
}
}
void cxListStorePointers(CxList *list) {
list->item_size =
sizeof(
void *);
list->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__))
struct cx_list_s
const *list,
__attribute__((__unused__))
size_t index
) {
return NULL;
}
static ssize_t cx_emptyl_find(
__attribute__((__unused__))
struct cx_list_s
const *list,
__attribute__((__unused__))
void const *elem
) {
return -
1;
}
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;
}
static bool cx_emptyl_iter_valid(__attribute__((__unused__))
void const *iter) {
return false;
}
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;
}
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);
}
int cxListCompare(
CxList
const *list,
CxList
const *other
) {
if (
(list->store_pointer ^ other->store_pointer) ||
((list->climpl ==
NULL) ^ (other->climpl ==
NULL)) ||
((list->climpl !=
NULL ? list->climpl->compare : list->cl->compare) !=
(other->climpl !=
NULL ? other->climpl->compare : other->cl->compare))
) {
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 {
return list->cl->compare(list, other);
}
}
CxMutIterator cxListMutIteratorAt(
CxList *list,
size_t index
) {
CxIterator it = list->cl->iterator(list, index, false);
it.base.mutating = true;
CxMutIterator iter;
memcpy(&iter, &it,
sizeof(CxMutIterator));
return iter;
}
CxMutIterator cxListMutBackwardsIteratorAt(
CxList *list,
size_t index
) {
CxIterator it = list->cl->iterator(list, index, true);
it.base.mutating = true;
CxMutIterator iter;
memcpy(&iter, &it,
sizeof(CxMutIterator));
return iter;
}