Skip to content

Instantly share code, notes, and snippets.

@jstimpfle
Last active January 19, 2021 10:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jstimpfle/c89670a86445082ecbbbcaeb7c3133d5 to your computer and use it in GitHub Desktop.
Save jstimpfle/c89670a86445082ecbbbcaeb7c3133d5 to your computer and use it in GitHub Desktop.
// 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