Last active
January 19, 2021 10:12
-
-
Save jstimpfle/c89670a86445082ecbbbcaeb7c3133d5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Intrusively doubly linked lists boilerplate. Similar to Linux list.h | |
// 2020, Jens Stimpfle | |
typedef struct _ListNode ListNode; | |
typedef struct _List List; | |
struct _ListNode { | |
ListNode *next; | |
ListNode *prev; | |
}; | |
static inline void link_listnode_after_listnode(ListNode *node, ListNode *before) | |
{ | |
node->prev = before; | |
node->next = before->next; | |
node->prev->next = node; | |
node->next->prev = node; | |
} | |
static inline void link_listnode_before_listnode(ListNode *node, ListNode *after) | |
{ | |
node->prev = after->prev; | |
node->next = after; | |
node->prev->next = node; | |
node->next->prev = node; | |
} | |
static inline void unlink_listnode(ListNode *node) | |
{ | |
node->prev->next = node->next; | |
node->next->prev = node->prev; | |
node->prev = NULL; | |
node->next = NULL; | |
} | |
struct _List { | |
ListNode front_sentinel; | |
ListNode back_sentinel; | |
}; | |
#define LIST_INITIALIZER(list) { \ | |
{ .prev = NULL, .next = &(list)->back_sentinel }, \ | |
{ .prev = &(list)->front_sentinel, .next = NULL }, \ | |
} | |
#define DEFINE_LIST(name) List name = LIST_INITIALIZER(&name) | |
static inline void list_initialize(List *list) | |
{ | |
list->front_sentinel.prev = NULL; | |
list->front_sentinel.next = &list->back_sentinel; | |
list->back_sentinel.prev = &list->front_sentinel; | |
list->back_sentinel.next = NULL; | |
} | |
static inline int list_is_empty(List *list) | |
{ | |
return list->front_sentinel.next == &list->back_sentinel; | |
} | |
static inline void list_enqueue(List *list, ListNode *node) | |
{ | |
link_listnode_before_listnode(node, &list->back_sentinel); | |
} | |
static inline ListNode *list_dequeue(List *list) | |
{ | |
ListNode *node = list->front_sentinel.next; | |
if (node == &list->back_sentinel) | |
return NULL; | |
unlink_listnode(node); | |
return node; | |
} | |
static inline void *list_container(ListNode *node, int offset) | |
{ | |
return node ? (char *) node - offset : NULL; | |
} | |
static inline ListNode *list_first(List *list) | |
{ | |
return list->front_sentinel.next; | |
} | |
static inline ListNode *list_last(List *list) | |
{ | |
return list->back_sentinel.prev; | |
} | |
#define list_container_typed(node, type, member) ((type *) list_container(node, offsetof(type, member))) | |
#define list_first_typed(list, type, member) list_container_typed(list_first(list), type, member) | |
#define list_last_typed(list, type, member) list_container_typed(list_last(list), type, member) | |
#define list_next_typed(thing, type, member) list_container_typed((thing)->member.next, type, member) | |
#define list_dequeue_typed(list, type, member) list_container_typed(list_dequeue(list), type, member) | |
#define list_foreach_typed(name, type, member, list) \ | |
for (type *name = list_first_typed((list), type, member); \ | |
name != list_container_typed(&(list)->back_sentinel, type, member); \ | |
name = list_next_typed(name, type, member)) | |
#define list_foreach_next_typed(name, type, member, list) \ | |
for (type *___next, *name = list_first_typed((list), type, member); \ | |
name != list_container_typed(&(list)->back_sentinel, type, member) && \ | |
((___next = list_next_typed(name, type, member)), 1); \ | |
name = ___next) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment