/* Copyright (C) 2021,2022 fef . All rights reserved. */ /** * @file gay/clist.h * @brief Plain and simple circular list implementation. */ #pragma once #include #include /** * @brief Simple circular list header. * Embed this into other structures to make them part of a list. */ struct clist { struct clist *next; struct clist *prev; }; #define CLIST_DEFINE(name) { \ .next = &(name), \ .prev = &(name), \ } /** * @brief Statically declare and define a clist. * * @param name Name of the list */ #define CLIST(name) struct clist name = CLIST_DEFINE(name) /** * @brief Initialize a new clist. * Use this only for dynamically allocated lists, * there is the `CLIST()` macro for globals. * * @param list List to initialize */ void clist_init(struct clist *list); /** * @brief Add a new node at the end of a clist. * * @param head Head of the list * @param new New node to insert at the end */ void clist_add(struct clist *head, struct clist *new); #define clist_insert_before(node, new) clist_add(node, new) /** * @brief Add a new node at the beginning of a clist. * * @param head Head of the list * @param new New node to insert at the beginning */ void clist_add_first(struct clist *head, struct clist *new); #define clist_insert_after(node, new) clist_add_first(node, new) /** * @brief Remove a node from a clist. * * @param node Node to remove */ void clist_del(struct clist *node); /** * @brief Remove and return the first node in a clist. * If the list is empty and `CFG_DEBUG_CLIST` is defined, this returns nil. * If `CFG_DEBUG_CLIST` is not defined in this case, it will blow up. * * @param head Head of the list * @return The deleted node */ struct clist *clist_del_first(struct clist *head); /** * @brief Remove and return the last node in a clist. * If the list is empty and `CFG_DEBUG_CLIST` is defined, this returns nil. * If `CFG_DEBUG_CLIST` is not defined in this case, it will blow up. * * @param head Head of the list * @return The deleted node */ struct clist *clist_del_last(struct clist *head); /** * @brief Return whether a clist is empty. * * @param head The `struct clist *` acting as the head of the clist * @returns An expression that evaluates true if the list is empty */ #define clist_is_empty(head) ((head)->next == (head)) /** * @brief Iterate over every node in a clist. * * @param head The `struct clist *` acting as the head of the clist * @param cursor A `struct clist *` to use as a cursor for iteration */ #define clist_foreach(head, cursor) \ for ((cursor) = (head)->next; \ (cursor) != (head); \ (cursor) = (cursor)->next) /** * @brief Iterate over every node in a clist in reverse order. * * @param head The `struct clist *` acting as the head of the clist * @param cursor A `struct clist *` to use as a cursor for iteration */ #define clist_foreach_rev(head, cursor, member) \ for ((cursor) = (head)->prev; \ (cursor) != (head); \ (cursor) = (cursor)->prev) /** * @brief Get the structure embedding a clist. * * @param node The `struct clist *` to cast out of * @param type Type of the containing structure * @param member Name of the `struct clist` within the containing structure * @returns The `struct *` the list node is embedded in */ #define clist_entry(node, type, member) \ container_of(node, type, member) /** * @brief Get the first entry in a list. * * @param head The `struct clist *` that is the head node * @param type Type of the structure embedding the list nodes * @param member Name of the `struct clist` within the embedding structure * @returns The last `struct *` in the list */ #define clist_first_entry(head, type, member) \ clist_entry((head)->next, type, member) #define clist_del_first_entry(head, type, member) ({ \ struct clist *__first = clist_del_first(head); \ clist_entry(__first, type, member); \ }) /** * @brief Get the last entry in a list. * * @param head The `struct clist *` that is the head node * @param type Type of the structure embedding the list nodes * @param member Name of the `struct clist` within the embedding structure * @returns The last `struct *` in the list */ #define clist_last_entry(head, type, member) \ clist_entry((head)->prev, type, member) #define clist_del_last_entry(head, type, member) ({ \ struct clist *__last = clist_del_last(head); \ clist_entry(__last, type, member); \ }) /** * @brief Get the next entry in a clist. * * @param entry The `struct *` embedding a clist to get the successor of * @param member Name of the `struct clist` embedded within the entry * @returns The next `struct *` in the list */ #define clist_next_entry(entry, member) \ clist_entry((entry)->member.next, typeof(*(entry)), member) /** * @brief Get the previous entry in a clist. * * @param entry the `struct *` embedding a clist to the the predecessor of * @param emember Name of the `struct clist` embedded within the entry * @returns The previous `struct *` in the list */ #define clist_prev_entry(entry, member) \ clist_entry((entry)->member.prev, typeof(*(entry)), member) /** * @brief Iterate over each entry within a list. * * @param head The `struct clist *` that is the head node in the list * @param cursor A `struct *` the list nodes are embedded in to use as the cursor * @param member Name of the `struct clist` within the embedding structure */ #define clist_foreach_entry(head, cursor, member) \ for ((cursor) = clist_first_entry(head, typeof(*(cursor)), member); \ &(cursor)->member != (head); \ (cursor) = clist_next_entry(cursor, member)) /** * @brief Continue iterating over each entry within a clist. * * @param head The `struct clist *` that is the head node in the list * @param cursor The `struct *` list entry from which to continue * @param member Name of the `struct clist` within the embedding structure */ #define clist_foreach_entry_continue(head, cursor, member) \ for ((cursor) = clist_next_entry(cursor, member); \ &(cursor)->member != (head); \ (cursor) = clist_next_entry(cursor, member)) /** * @brief Iterate over a clist in reverse order. * * @param head The `struct clist *` that is the head node in the list * @param cursor A `struct *` the list nodes are embedded in to use as a cursor * @param member Name of the `struct clist` within the embedding structure */ #define clist_foreach_entry_rev(head, cursor, member) \ for ((cursor) = clist_last_entry(head, typeof(*(cursor)), member); \ &(cursor)->member != (head); \ (cursor) = clist_prev_entry(cursor, member)) /** * @brief Continue iterating over a clist in reverse order. * * @param head The `struct clist *` that is the head node in the list * @param cursor The `struct *` list entry from which to continue * @param member Name of the `struct clist` within the embedding structure */ #define clist_foreach_entry_rev_continue(head, cursor, member) \ for ((cursor) = clist_prev_entry(cursor, member); \ &(cursor)->member != (head); \ (cursor) = clist_prev_entry(cursor, member)) /** * @brief Iterate over each entry within a list, this is safe from element removal. * * @param head The `struct clist *` that is the head node in the list * @param cursor A `struct *` the list nodes are embedded in to use as the cursor. * This is the element that may be removed from the list. * @param tmp An addional `struct *` of the same type as `cursor` (don't touch) * @param member Name of the `struct clist` within the embedding structure */ #define clist_foreach_entry_safe(head, cursor, tmp, member) \ for ((cursor) = clist_first_entry(head, typeof(*(cursor)), member), \ (tmp) = clist_next_entry(cursor, member); \ &(cursor)->member != (head); \ (cursor) = (tmp), \ (tmp) = clist_next_entry(tmp, member))