liblist-c

C type-agnostic linked-list library
git clone https://git.sinitax.com/sinitax/liblist-c
Log | Files | Refs | LICENSE | sfeed.txt

list.c (4072B)


      1#include "list.h"
      2
      3void
      4list_init(struct list *list)
      5{
      6	LIST_ABORT_ON_ARGS(!list);
      7
      8	list->head.prev = NULL;
      9	list->head.next = &list->tail;
     10	list->tail.prev = &list->head;
     11	list->tail.next = NULL;
     12}
     13
     14void
     15list_clear(struct list *list)
     16{
     17	LIST_ABORT_ON_ARGS(!list);
     18
     19	while (!list_empty(list))
     20		list_pop_back(list);
     21}
     22
     23void
     24list_free_items(struct list *list, list_item_free_fn free_item, size_t offset)
     25{
     26	struct list_link *item;
     27
     28	LIST_ABORT_ON_ARGS(!list || !free_item);
     29
     30	while (!list_empty(list)) {
     31		item = list_link_pop(list->head.next);
     32		free_item(((void *) item) - offset);
     33	}
     34}
     35
     36size_t
     37list_len(const struct list *list)
     38{
     39	const struct list_link *link;
     40	size_t len;
     41
     42	LIST_ABORT_ON_ARGS(!list);
     43
     44	len = 0;
     45	for (LIST_ITER(list, link))
     46		len += 1;
     47
     48	return len;
     49}
     50
     51ssize_t
     52list_index(const struct list *list, const struct list_link *target)
     53{
     54	struct list_link *link;
     55	ssize_t index;
     56
     57	LIST_ABORT_ON_ARGS(!list || !target);
     58
     59	index = 0;
     60	for (LIST_ITER(list, link)) {
     61		if (link == target)
     62			return index;
     63		index++;
     64	}
     65
     66	return -1;
     67}
     68
     69struct list_link *
     70list_at(struct list *list, size_t n)
     71{
     72	struct list_link *link;
     73
     74	LIST_ABORT_ON_ARGS(!list);
     75
     76	link = list_iter_fwd(list->head.next, n);
     77
     78	return LIST_INNER(link) ? link : NULL;
     79}
     80
     81struct list_link *
     82list_at_back(struct list *list, size_t n)
     83{
     84	struct list_link *link;
     85
     86	LIST_ABORT_ON_ARGS(!list);
     87
     88	link = list_iter_bwd(&list->tail, n);
     89
     90	return LIST_INNER(link) ? link : NULL;
     91}
     92
     93void
     94list_insert_sorted(struct list *list, struct list_link *insert,
     95	bool reverse, list_sort_order_fn in_order, size_t offset, void *user)
     96{
     97	struct list_link *link;
     98	void *link_item, *insert_item;
     99
    100	LIST_ABORT_ON_ARGS(!list || !insert || !in_order);
    101
    102	insert_item = ((void *) insert) - offset;
    103	for (LIST_ITER(list, link)) {
    104		link_item = ((void *) link) - offset;
    105		if (in_order(insert_item, link_item, user) == !reverse) {
    106			list_link_prepend(link, insert);
    107			return;
    108		}
    109	}
    110
    111	list_insert_back(list, insert);
    112}
    113
    114void
    115list_insert_sorted_bwd(struct list *list, struct list_link *insert,
    116	bool reverse, list_sort_order_fn in_order, size_t offset, void *user)
    117{
    118	struct list_link *link;
    119	void *link_item, *insert_item;
    120
    121	LIST_ABORT_ON_ARGS(!list || !insert || !in_order);
    122
    123	insert_item = ((void *) insert) - offset;
    124	for (LIST_ITER_BWD(list, link)) {
    125		link_item = ((void *) link) - offset;
    126		if (in_order(link_item, insert_item, user) == !reverse) {
    127			list_link_append(link, insert);
    128			return;
    129		}
    130	}
    131
    132	list_insert_front(list, insert);
    133}
    134
    135void
    136list_insertion_sort(struct list *list, bool reverse,
    137	list_sort_order_fn in_order, size_t offset, void *user)
    138{
    139	struct list_link *link, *cmp, *next;
    140	void *link_item, *cmp_item;
    141
    142	LIST_ABORT_ON_ARGS(!list || !in_order);
    143
    144	link = list->head.next;
    145	while (LIST_INNER(link)) {
    146		next = link->next;
    147		cmp = link->prev;
    148		link_item = ((void *) link) - offset;
    149		while (LIST_INNER(cmp)) {
    150			cmp_item = ((void *) cmp) - offset;
    151			if (in_order(cmp_item, link_item, user) == !reverse)
    152				break;
    153			cmp = cmp->prev;
    154		}
    155		if (cmp != link->prev)
    156			list_link_append(cmp, list_link_pop(link));
    157		link = next;
    158	}
    159}
    160
    161struct list_link *
    162list_pop_front(struct list *list)
    163{
    164	LIST_ABORT_ON_ARGS(!list);
    165
    166	if (list_empty(list)) return NULL;
    167
    168	return list_link_pop(list->head.next);
    169}
    170
    171struct list_link *
    172list_pop_back(struct list *list)
    173{
    174	LIST_ABORT_ON_ARGS(!list);
    175
    176	if (list_empty(list)) return NULL;
    177
    178	return list_link_pop(list->tail.prev);
    179}
    180
    181struct list_link *
    182list_link_pop(struct list_link *link)
    183{
    184	LIST_ABORT_ON_ARGS(!link);
    185
    186	if (link->prev)
    187		link->prev->next = link->next;
    188	if (link->next)
    189		link->next->prev = link->prev;
    190	*link = LIST_LINK_INIT;
    191
    192	return link;
    193}
    194
    195struct list_link *
    196list_iter_fwd(struct list_link *link, size_t n)
    197{
    198	size_t i;
    199
    200	LIST_ABORT_ON_ARGS(!link);
    201
    202	for (i = 0; i < n; i++) {
    203		if (!link) return NULL;
    204		link = link->next;
    205	}
    206
    207	return link;
    208}
    209
    210struct list_link *
    211list_iter_bwd(struct list_link *link, size_t n)
    212{
    213	size_t i;
    214
    215	LIST_ABORT_ON_ARGS(!link);
    216
    217	for (i = 0; i < n; i++) {
    218		if (!link) return NULL;
    219		link = link->prev;
    220	}
    221
    222	return link;
    223}
    224