You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
244 lines
7.7 KiB
C
244 lines
7.7 KiB
C
/* Copyright (C) 2021,2022 fef <owo@fef.moe>. All rights reserved. */
|
|
|
|
/**
|
|
* @file gay/clist.h
|
|
* @brief Plain and simple circular list implementation.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <gay/config.h>
|
|
#include <gay/util.h>
|
|
|
|
/**
|
|
* @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))
|