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}