#ifndef _AL_LIST_H #define _AL_LIST_H #include "lib.h" #define AL_LIST_DEFINE(type, name) \ typedef struct list_##name list_##name; \ struct list_##name { \ type value; \ list_##name *next; \ list_##name *prev; \ }; \ static inline list_##name *list_new_node_##name(type value) \ { \ list_##name *node = (list_##name *)al_malloc(sizeof(list_##name)); \ node->value = value; \ return node; \ } \ static inline void list_free_node_##name(list_##name *l) \ { \ free(l); \ } \ static inline list_##name *list_last_##name(list_##name *l) \ { \ if (l) while (l->next) l = l->next; \ return l; \ } \ static inline list_##name *list_nth_##name(list_##name *l, u32 n) \ { \ while (n-- > 0 && l) l = l->next; \ return l; \ } \ static inline list_##name *list_append_##name(list_##name *l, type value) \ { \ list_##name *node = list_new_node_##name(value); \ node->next = NULL; \ if (l) { \ list_##name *last = list_last_##name(l); \ node->prev = last; \ last->next = node; \ return l; \ } else { \ node->prev = NULL; \ return node; \ } \ } \ static inline list_##name *list_prepend_##name(list_##name *l, type value) \ { \ list_##name *node = list_new_node_##name(value); \ node->next = l; \ node->prev = NULL; \ if (l) l->prev = node; \ return node; \ } \ static inline list_##name *list_insert_after_##name(list_##name *l, list_##name *s, type value) \ { \ if (!l) { \ list_##name *node = list_new_node_##name(value); \ node->next = NULL; \ node->prev = NULL; \ return node; \ } else if (!s || !s->next) { \ return list_append_##name(l, value); \ } else { \ list_##name *node = list_new_node_##name(value); \ s->next->prev = node; \ node->next = s->next; \ node->prev = s; \ s->next = node; \ return l; \ } \ } \ static inline list_##name *list_insert_before_##name(list_##name *l, list_##name *s, type value) \ { \ if (!l) { \ list_##name *node = list_new_node_##name(value); \ node->next = NULL; \ node->prev = NULL; \ return node; \ } else if (!s) { \ return list_append_##name(l, value); \ } else if (s == l) { \ return list_prepend_##name(l, value); \ } else { \ list_##name *node = list_new_node_##name(value); \ s->prev->next = node; \ node->prev = s->prev; \ node->next = s; \ s->prev = node; \ return l; \ } \ } \ static inline list_##name *list_remove_##name(list_##name *l, list_##name *n) \ { \ if (!l) { \ return l; \ } else if (l == n) { \ if (n->next) { \ n->next->prev = NULL; \ } \ l = n->next; \ list_free_node_##name(n); \ } else { \ n->prev->next = n->next; \ if (n->next) { \ n->next->prev = n->prev; \ } \ list_free_node_##name(n); \ } \ return l; \ } #define list(name) list_##name #define al_list_nth(name, list, n) list_nth_##name(list, n) #define al_list_last(name, list) list_last_##name(list) // If list is NULL, a new list is created. #define al_list_append(name, list, value) list_append_##name(list, value) #define al_list_prepend(name, list, value) list_prepend_##name(list, value) // If sibiling->next is NULL (or just sibiling for before) append the value to the end of the list. #define al_list_insert_after(name, list, sibling, value) list_insert_after_##name(list, sibling, value) #define al_list_insert_before(name, list, sibling, value) list_insert_before_##name(list, sibling, value) #define al_list_remove(name, list, node) list_remove_##name(list, node) #define al_list_foreach(name, list, node) \ for (list_##name *node = list; node; node = node->next) #endif // _AL_LIST_H