liblist-c

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

list.h (5981B)


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