Workshop o mikrokontrolérech na SKSP 2024.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

234 lines
5.3 KiB

3 months ago
/*
* UCW Library -- Single-Linked Lists
*
* (c) 2005 Martin Mares <mj@ucw.cz>
* (c) 2017 Pavel Charvat <pchar@ucw.cz>
*
* This software may be freely distributed and used according to the terms
* of the GNU Lesser General Public License.
*/
#ifndef _UCW_SLISTS_H
#define _UCW_SLISTS_H
#ifdef CONFIG_UCW_CLEAN_ABI
#define slist_insert_before ucw_slist_insert_before
#define slist_prev ucw_slist_prev
#define slist_remove ucw_slist_remove
#endif
/**
* Common header for list nodes.
**/
typedef struct snode {
struct snode *next;
} snode;
/**
* Single-linked list.
**/
typedef struct slist {
struct snode head, *last;
} slist;
/**
* Initialize a new single-linked list. Must be called before any other function.
**/
static inline void slist_init(slist *l)
{
l->head.next = l->last = NULL;
}
/**
* Return the first node of @l or NULL if @l is empty.
**/
static inline void *slist_head(slist *l)
{
return l->head.next;
}
/**
* Return the last node of @l or NULL if @l is empty.
**/
static inline void *slist_tail(slist *l)
{
return l->last;
}
/**
* Find the next node to @n or NULL if @n is the last one.
**/
static inline void *slist_next(snode *n)
{
return n->next;
}
/**
* Return a non-zero value iff @l is empty.
**/
static inline int slist_empty(slist *l)
{
return !l->head.next;
}
/**
* Insert a new node in front of all other nodes.
**/
static inline void slist_add_head(slist *l, snode *n)
{
n->next = l->head.next;
l->head.next = n;
if (!l->last)
l->last = n;
}
/**
* Insert a new node after all other nodes.
**/
static inline void slist_add_tail(slist *l, snode *n)
{
if (l->last)
l->last->next = n;
else
l->head.next = n;
n->next = NULL;
l->last = n;
}
/**
* Insert a new node just after the node @after. To insert a new head, use @slist_add_head() instead.
**/
static inline void slist_insert_after(slist *l, snode *what, snode *after)
{
what->next = after->next;
after->next = what;
if (!what->next)
l->last = what;
}
/**
* Quickly remove the node next to @after. The node may not exist.
**/
static inline void slist_remove_after(slist *l, snode *after)
{
snode *n = after->next;
if (n)
{
after->next = n->next;
if (l->last == n)
l->last = (after == &l->head) ? NULL : after;
}
}
/**
* Remove the first node in @l. The list can be empty.
**/
static inline void *slist_remove_head(slist *l)
{
snode *n = slist_head(l);
if (n)
slist_remove_after(l, &l->head);
return n;
}
/* Loops */
/**
* Loop over all nodes in the @list and perform the next C statement on them. The current node is stored in @n which must be defined before as pointer to any type.
* The list should not be changed during this loop command.
**/
#define SLIST_WALK(n,list) for(n=(void*)(list).head.next; (n); (n)=(void*)((snode*)(n))->next)
/**
* Same as @SLIST_WALK(), but allows removal of the current node. This macro requires one more variable to store the pointer to the previous node (useful for @slist_remove_after()).
**/
#define SLIST_WALK_DELSAFE(n,list,prev) for((prev)=(void*)&(list).head; (n)=(void*)((snode*)prev)->next; (prev)=(((snode*)(prev))->next==(snode*)(n) ? (void*)(n) : (void*)(prev)))
/**
* Same as @SLIST_WALK(), but it defines the variable for the current node in place. @type should be a pointer type.
**/
#define SLIST_FOR_EACH(type,n,list) for(type n=(void*)(list).head.next; n; n=(void*)((snode*)(n))->next)
/* Non-trivial functions */
/**
* Find the previous node to @n or NULL if @n is the first one. Beware linear time complexity.
**/
void *slist_prev(slist *l, snode *n);
/**
* Insert a new node just before the node @before. To insert a new tail, use @slist_add_tail(). Beware linear time complexity.
**/
void slist_insert_before(slist *l, snode *what, snode *before);
/**
* Remove node @n. Beware linear time complexity.
**/
void slist_remove(slist *l, snode *n);
/**
* Remove the last node in @l. The list can be empty.
**/
static inline void slist_remove_tail(slist *l)
{
slist_remove(l, l->last);
}
/**
* Merge two lists by inserting the list @what in front of all other nodes in a different list @l.
* The first list is then cleared.
**/
static inline void slist_add_list_head(slist *l, slist *what)
{
if (!slist_empty(what))
{
if (!slist_empty(l))
what->last->next = l->head.next;
else
l->last = what->last;
l->head.next = what->head.next;
slist_init(what);
}
}
/**
* Merge two lists by inserting the list @what after all other nodes in a different list @l.
* The first list is then cleared.
**/
static inline void slist_add_list_tail(slist *l, slist *what)
{
if (!slist_empty(what))
{
if (!slist_empty(l))
l->last->next = what->head.next;
else
l->head.next = what->head.next;
l->last = what->last;
slist_init(what);
}
}
/**
* Move all items from a source list to a destination list. The source list
* becomes empty, the original contents of the destination list are destroyed.
**/
static inline void slist_move(slist *to, slist *from)
{
to->head.next = from->head.next;
to->last = from->last;
slist_init(from);
}
/**
* Compute the number of nodes in @l. Beware linear time complexity.
**/
static inline uint slist_size(slist *l)
{
uint i = 0;
SLIST_FOR_EACH(snode *, n, *l)
i++;
return i;
}
#endif