Quelle ilist.h
Sprache: C
/*-------------------------------------------------------------------------
*
* ilist . h
* integrated / inline doubly - and singly - linked lists
*
* These list types are useful when there are only a predetermined set of
* lists that an object could be in . List links are embedded directly into
* the objects , and thus no extra memory management overhead is required .
* ( Of course , if only a small proportion of existing objects are in a list ,
* the link fields in the remainder would be wasted space . But usually ,
* it saves space to not have separately - allocated list nodes . )
*
* The doubly - linked list comes in 2 forms . dlist_head defines a head of a
* doubly - linked list of dlist_nodes , whereas dclist_head defines the head of
* a doubly - linked list of dlist_nodes with an additional ' count ' field to
* keep track of how many items are contained within the given list . For
* simplicity , dlist_head and dclist_head share the same node and iterator
* types . The functions to manipulate a dlist_head always have a name
* starting with " dlist " , whereas functions to manipulate a dclist_head have a
* name starting with " dclist " . dclist_head comes with an additional function
* ( dclist_count ) to return the number of entries in the list . dclists are
* able to store a maximum of PG_UINT32_MAX elements . It is up to the caller
* to ensure no more than this many items are added to a dclist .
*
* None of the functions here allocate any memory ; they just manipulate
* externally managed memory . With the exception doubly - linked count lists
* providing the ability to obtain the number of items in the list , the APIs
* for singly and both doubly linked lists are identical as far as
* capabilities of both allow .
*
* Each list has a list header , which exists even when the list is empty .
* An empty singly - linked list has a NULL pointer in its header .
*
* For both doubly - linked list types , there are two valid ways to represent an
* empty list . The head ' s ' next ' pointer can either be NULL or the head ' s
* ' next ' and ' prev ' links can both point back to the list head ( circular ) .
* ( If a dlist is modified and then all its elements are deleted , it will be
* in the circular state . ) . We prefer circular dlists because there are some
* operations that can be done without branches ( and thus faster ) on lists
* that use circular representation . However , it is often convenient to
* initialize list headers to zeroes rather than setting them up with an
* explicit initialization function , so we also allow the NULL initialization .
*
* EXAMPLES
*
* Here ' s a simple example demonstrating how this can be used . Let ' s assume
* we want to store information about the tables contained in a database .
*
* # include " lib / ilist . h "
*
* // Define struct for the databases including a list header that will be
* // used to access the nodes in the table list later on.
* typedef struct my_database
* {
* char * datname ;
* dlist_head tables ;
* // ...
* } my_database ;
*
* // Define struct for the tables. Note the list_node element which stores
* // prev/next list links. The list_node element need not be first.
* typedef struct my_table
* {
* char * tablename ;
* dlist_node list_node ;
* perm_t permissions ;
* // ...
* } my_table ;
*
* // create a database
* my_database * db = create_database ( ) ;
*
* // and add a few tables to its table list
* dlist_push_head ( & db - > tables , & create_table ( db , " a " ) - > list_node ) ;
* . . .
* dlist_push_head ( & db - > tables , & create_table ( db , " b " ) - > list_node ) ;
*
*
* To iterate over the table list , we allocate an iterator variable and use
* a specialized looping construct . Inside a dlist_foreach , the iterator ' s
* ' cur ' field can be used to access the current element . iter . cur points to
* a ' dlist_node ' , but most of the time what we want is the actual table
* information ; dlist_container ( ) gives us that , like so :
*
* dlist_iter iter ;
* dlist_foreach ( iter , & db - > tables )
* {
* my_table * tbl = dlist_container ( my_table , list_node , iter . cur ) ;
* printf ( " we have a table : % s in database % s \ n " ,
* tbl - > tablename , db - > datname ) ;
* }
*
*
* While a simple iteration is useful , we sometimes also want to manipulate
* the list while iterating . There is a different iterator element and looping
* construct for that . Suppose we want to delete tables that meet a certain
* criterion :
*
* dlist_mutable_iter miter ;
* dlist_foreach_modify ( miter , & db - > tables )
* {
* my_table * tbl = dlist_container ( my_table , list_node , miter . cur ) ;
*
* if ( ! tbl - > to_be_deleted )
* continue ; // don't touch this one
*
* // unlink the current table from the linked list
* dlist_delete ( miter . cur ) ;
* // as these lists never manage memory, we can still access the table
* // after it's been unlinked
* drop_table ( db , tbl ) ;
* }
*
*
* Portions Copyright ( c ) 1996 - 2025 , PostgreSQL Global Development Group
* Portions Copyright ( c ) 1994 , Regents of the University of California
*
* IDENTIFICATION
* src / include / lib / ilist . h
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
#ifndef ILIST_H
#define ILIST_H
/*
* Enable for extra debugging . This is rather expensive , so it ' s not enabled by
* default even when USE_ASSERT_CHECKING .
*/
/* #define ILIST_DEBUG */
/*
* Node of a doubly linked list .
*
* Embed this in structs that need to be part of a doubly linked list .
*/
typedef struct dlist_node dlist_node;
struct dlist_node
{
dlist_node *prev;
dlist_node *next;
};
/*
* Head of a doubly linked list .
*
* Non - empty lists are internally circularly linked . Circular lists have the
* advantage of not needing any branches in the most common list manipulations .
* An empty list can also be represented as a pair of NULL pointers , making
* initialization easier .
*/
typedef struct dlist_head
{
/*
* head . next either points to the first element of the list ; to & head if
* it ' s a circular empty list ; or to NULL if empty and not circular .
*
* head . prev either points to the last element of the list ; to & head if
* it ' s a circular empty list ; or to NULL if empty and not circular .
*/
dlist_node head;
} dlist_head;
/*
* Doubly linked list iterator type for dlist_head and dclist_head types .
*
* Used as state in dlist_foreach ( ) and dlist_reverse_foreach ( ) ( and the
* dclist variant thereof ) .
*
* To get the current element of the iteration use the ' cur ' member .
*
* Iterations using this are * not * allowed to change the list while iterating !
*
* NB : We use an extra " end " field here to avoid multiple evaluations of
* arguments in the dlist_foreach ( ) and dclist_foreach ( ) macros .
*/
typedef struct dlist_iter
{
dlist_node *cur; /* current element */
dlist_node *end; /* last node we'll iterate to */
} dlist_iter;
/*
* Doubly linked list iterator for both dlist_head and dclist_head types .
* This iterator type allows some modifications while iterating .
*
* Used as state in dlist_foreach_modify ( ) and dclist_foreach_modify ( ) .
*
* To get the current element of the iteration use the ' cur ' member .
*
* Iterations using this are only allowed to change the list at the current
* point of iteration . It is fine to delete the current node , but it is * not *
* fine to insert or delete adjacent nodes .
*
* NB : We need a separate type for mutable iterations so that we can store
* the ' next ' node of the current node in case it gets deleted or modified .
*/
typedef struct dlist_mutable_iter
{
dlist_node *cur; /* current element */
dlist_node *next; /* next node we'll iterate to */
dlist_node *end; /* last node we'll iterate to */
} dlist_mutable_iter;
/*
* Head of a doubly linked list with a count of the number of items
*
* This internally makes use of a dlist to implement the actual list . When
* items are added or removed from the list the count is updated to reflect
* the current number of items in the list .
*/
typedef struct dclist_head
{
dlist_head dlist; /* the actual list header */
uint32 count; /* the number of items in the list */
} dclist_head;
/*
* Node of a singly linked list .
*
* Embed this in structs that need to be part of a singly linked list .
*/
typedef struct slist_node slist_node;
struct slist_node
{
slist_node *next;
};
/*
* Head of a singly linked list .
*
* Singly linked lists are not circularly linked , in contrast to doubly linked
* lists ; we just set head . next to NULL if empty . This doesn ' t incur any
* additional branches in the usual manipulations .
*/
typedef struct slist_head
{
slist_node head;
} slist_head;
/*
* Singly linked list iterator .
*
* Used as state in slist_foreach ( ) . To get the current element of the
* iteration use the ' cur ' member .
*
* It ' s allowed to modify the list while iterating , with the exception of
* deleting the iterator ' s current node ; deletion of that node requires
* care if the iteration is to be continued afterward . ( Doing so and also
* deleting or inserting adjacent list elements might misbehave ; also , if
* the user frees the current node ' s storage , continuing the iteration is
* not safe . )
*
* NB : this wouldn ' t really need to be an extra struct , we could use an
* slist_node * directly . We prefer a separate type for consistency .
*/
typedef struct slist_iter
{
slist_node *cur;
} slist_iter;
/*
* Singly linked list iterator allowing some modifications while iterating .
*
* Used as state in slist_foreach_modify ( ) . To get the current element of the
* iteration use the ' cur ' member .
*
* The only list modification allowed while iterating is to remove the current
* node via slist_delete_current ( ) ( * not * slist_delete ( ) ) . Insertion or
* deletion of nodes adjacent to the current node would misbehave .
*/
typedef struct slist_mutable_iter
{
slist_node *cur; /* current element */
slist_node *next; /* next node we'll iterate to */
slist_node *prev; /* prev node, for deletions */
} slist_mutable_iter;
/* Static initializers */
#define DLIST_STATIC_INIT(name) {{&(name).head, &(name).head}}
#define DCLIST_STATIC_INIT(name) {{{&(name).dlist.head, &(name).dlist.head}}, 0 }
#define SLIST_STATIC_INIT(name) {{NULL}}
/* Prototypes for functions too big to be inline */
/* Caution: this is O(n); consider using slist_delete_current() instead */
extern void slist_delete(slist_head *head, const slist_node *node);
#ifdef ILIST_DEBUG
extern void dlist_member_check(const dlist_head *head, const dlist_node *node);
extern void dlist_check(const dlist_head *head);
extern void slist_check(const slist_head *head);
#else
/*
* These seemingly useless casts to void are here to keep the compiler quiet
* about the argument being unused in many functions in a non - debug compile ,
* in which functions the only point of passing the list head pointer is to be
* able to run these checks .
*/
#define dlist_member_check(head, node) ((void ) (head))
#define dlist_check(head) ((void ) (head))
#define slist_check(head) ((void ) (head))
#endif /* ILIST_DEBUG */
/* doubly linked list implementation */
/*
* Initialize a doubly linked list .
* Previous state will be thrown away without any cleanup .
*/
static inline void
dlist_init(dlist_head *head)
{
head->head.next = head->head.prev = &head->head;
}
/*
* Initialize a doubly linked list element .
*
* This is only needed when dlist_node_is_detached ( ) may be needed .
*/
static inline void
dlist_node_init(dlist_node *node)
{
node->next = node->prev = NULL;
}
/*
* Is the list empty ?
*
* An empty list has either its first ' next ' pointer set to NULL , or to itself .
*/
static inline bool
dlist_is_empty(const dlist_head *head)
{
dlist_check(head);
return head->head.next == NULL || head->head.next == &(head->head);
}
/*
* Insert a node at the beginning of the list .
*/
static inline void
dlist_push_head(dlist_head *head, dlist_node *node)
{
if (head->head.next == NULL) /* convert NULL header to circular */
dlist_init(head);
node->next = head->head.next;
node->prev = &head->head;
node->next->prev = node;
head->head.next = node;
dlist_check(head);
}
/*
* Insert a node at the end of the list .
*/
static inline void
dlist_push_tail(dlist_head *head, dlist_node *node)
{
if (head->head.next == NULL) /* convert NULL header to circular */
dlist_init(head);
node->next = &head->head;
node->prev = head->head.prev;
node->prev->next = node;
head->head.prev = node;
dlist_check(head);
}
/*
* Insert a node after another * in the same list *
*/
static inline void
dlist_insert_after(dlist_node *after, dlist_node *node)
{
node->prev = after;
node->next = after->next;
after->next = node;
node->next->prev = node;
}
/*
* Insert a node before another * in the same list *
*/
static inline void
dlist_insert_before(dlist_node *before, dlist_node *node)
{
node->prev = before->prev;
node->next = before;
before->prev = node;
node->prev->next = node;
}
/*
* Delete ' node ' from its list ( it must be in one ) .
*/
static inline void
dlist_delete(dlist_node *node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
}
/*
* Like dlist_delete ( ) , but also sets next / prev to NULL to signal not being in
* a list .
*/
static inline void
dlist_delete_thoroughly(dlist_node *node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
node->next = NULL;
node->prev = NULL;
}
/*
* Same as dlist_delete , but performs checks in ILIST_DEBUG builds to ensure
* that ' node ' belongs to ' head ' .
*/
static inline void
dlist_delete_from(dlist_head *head, dlist_node *node)
{
dlist_member_check(head, node);
dlist_delete(node);
}
/*
* Like dlist_delete_from , but also sets next / prev to NULL to signal not
* being in a list .
*/
static inline void
dlist_delete_from_thoroughly(dlist_head *head, dlist_node *node)
{
dlist_member_check(head, node);
dlist_delete_thoroughly(node);
}
/*
* Remove and return the first node from a list ( there must be one ) .
*/
static inline dlist_node *
dlist_pop_head_node(dlist_head *head)
{
dlist_node *node;
Assert(!dlist_is_empty(head));
node = head->head.next;
dlist_delete(node);
return node;
}
/*
* Move element from its current position in the list to the head position in
* the same list .
*
* Undefined behaviour if ' node ' is not already part of the list .
*/
static inline void
dlist_move_head(dlist_head *head, dlist_node *node)
{
/* fast path if it's already at the head */
if (head->head.next == node)
return ;
dlist_delete(node);
dlist_push_head(head, node);
dlist_check(head);
}
/*
* Move element from its current position in the list to the tail position in
* the same list .
*
* Undefined behaviour if ' node ' is not already part of the list .
*/
static inline void
dlist_move_tail(dlist_head *head, dlist_node *node)
{
/* fast path if it's already at the tail */
if (head->head.prev == node)
return ;
dlist_delete(node);
dlist_push_tail(head, node);
dlist_check(head);
}
/*
* Check whether ' node ' has a following node .
* Caution : unreliable if ' node ' is not in the list .
*/
static inline bool
dlist_has_next(const dlist_head *head, const dlist_node *node)
{
return node->next != &head->head;
}
/*
* Check whether ' node ' has a preceding node .
* Caution : unreliable if ' node ' is not in the list .
*/
static inline bool
dlist_has_prev(const dlist_head *head, const dlist_node *node)
{
return node->prev != &head->head;
}
/*
* Check if node is detached . A node is only detached if it either has been
* initialized with dlist_init_node ( ) , or deleted with
* dlist_delete_thoroughly ( ) / dlist_delete_from_thoroughly ( ) /
* dclist_delete_from_thoroughly ( ) .
*/
static inline bool
dlist_node_is_detached(const dlist_node *node)
{
Assert((node->next == NULL && node->prev == NULL) ||
(node->next != NULL && node->prev != NULL));
return node->next == NULL;
}
/*
* Return the next node in the list ( there must be one ) .
*/
static inline dlist_node *
dlist_next_node(dlist_head *head, dlist_node *node)
{
Assert(dlist_has_next(head, node));
return node->next;
}
/*
* Return previous node in the list ( there must be one ) .
*/
static inline dlist_node *
dlist_prev_node(dlist_head *head, dlist_node *node)
{
Assert(dlist_has_prev(head, node));
return node->prev;
}
/* internal support function to get address of head element's struct */
static inline void *
dlist_head_element_off(dlist_head *head, size_t off)
{
Assert(!dlist_is_empty(head));
return (char *) head->head.next - off;
}
/*
* Return the first node in the list ( there must be one ) .
*/
static inline dlist_node *
dlist_head_node(dlist_head *head)
{
return (dlist_node *) dlist_head_element_off(head, 0 );
}
/* internal support function to get address of tail element's struct */
static inline void *
dlist_tail_element_off(dlist_head *head, size_t off)
{
Assert(!dlist_is_empty(head));
return (char *) head->head.prev - off;
}
/*
* Return the last node in the list ( there must be one ) .
*/
static inline dlist_node *
dlist_tail_node(dlist_head *head)
{
return (dlist_node *) dlist_tail_element_off(head, 0 );
}
/*
* Return the containing struct of ' type ' where ' membername ' is the dlist_node
* pointed at by ' ptr ' .
*
* This is used to convert a dlist_node * back to its containing struct .
*/
#define dlist_container(type, membername, ptr) \
(AssertVariableIsOfTypeMacro(ptr, dlist_node *), \
AssertVariableIsOfTypeMacro(((type *) NULL)->membername, dlist_node), \
((type *) ((char *) (ptr) - offsetof(type, membername))))
/*
* Return the address of the first element in the list .
*
* The list must not be empty .
*/
#define dlist_head_element(type, membername, lhead) \
(AssertVariableIsOfTypeMacro(((type *) NULL)->membername, dlist_node), \
(type *) dlist_head_element_off(lhead, offsetof(type, membername)))
/*
* Return the address of the last element in the list .
*
* The list must not be empty .
*/
#define dlist_tail_element(type, membername, lhead) \
(AssertVariableIsOfTypeMacro(((type *) NULL)->membername, dlist_node), \
((type *) dlist_tail_element_off(lhead, offsetof(type, membername))))
/*
* Iterate through the list pointed at by ' lhead ' storing the state in ' iter ' .
*
* Access the current element with iter . cur .
*
* It is * not * allowed to manipulate the list during iteration .
*/
#define dlist_foreach(iter, lhead) \
for (AssertVariableIsOfTypeMacro(iter, dlist_iter), \
AssertVariableIsOfTypeMacro(lhead, dlist_head *), \
(iter).end = &(lhead)->head, \
(iter).cur = (iter).end->next ? (iter).end->next : (iter).end; \
(iter).cur != (iter).end; \
(iter).cur = (iter).cur->next)
/*
* Iterate through the list pointed at by ' lhead ' storing the state in ' iter ' .
*
* Access the current element with iter . cur .
*
* Iterations using this are only allowed to change the list at the current
* point of iteration . It is fine to delete the current node , but it is * not *
* fine to insert or delete adjacent nodes .
*/
#define dlist_foreach_modify(iter, lhead) \
for (AssertVariableIsOfTypeMacro(iter, dlist_mutable_iter), \
AssertVariableIsOfTypeMacro(lhead, dlist_head *), \
(iter).end = &(lhead)->head, \
(iter).cur = (iter).end->next ? (iter).end->next : (iter).end, \
(iter).next = (iter).cur->next; \
(iter).cur != (iter).end; \
(iter).cur = (iter).next, (iter).next = (iter).cur->next)
/*
* Iterate through the list in reverse order .
*
* It is * not * allowed to manipulate the list during iteration .
*/
#define dlist_reverse_foreach(iter, lhead) \
for (AssertVariableIsOfTypeMacro(iter, dlist_iter), \
AssertVariableIsOfTypeMacro(lhead, dlist_head *), \
(iter).end = &(lhead)->head, \
(iter).cur = (iter).end->prev ? (iter).end->prev : (iter).end; \
(iter).cur != (iter).end; \
(iter).cur = (iter).cur->prev)
/* doubly-linked count list implementation */
/*
* dclist_init
* Initialize a doubly linked count list .
*
* Previous state will be thrown away without any cleanup .
*/
static inline void
dclist_init(dclist_head *head)
{
dlist_init(&head->dlist);
head->count = 0 ;
}
/*
* dclist_is_empty
* Returns true if the list is empty , otherwise false .
*/
static inline bool
dclist_is_empty(const dclist_head *head)
{
Assert(dlist_is_empty(&head->dlist) == (head->count == 0 ));
return (head->count == 0 );
}
/*
* dclist_push_head
* Insert a node at the beginning of the list .
*/
static inline void
dclist_push_head(dclist_head *head, dlist_node *node)
{
if (head->dlist.head.next == NULL) /* convert NULL header to circular */
dclist_init(head);
dlist_push_head(&head->dlist, node);
head->count++;
Assert(head->count > 0 ); /* count overflow check */
}
/*
* dclist_push_tail
* Insert a node at the end of the list .
*/
static inline void
dclist_push_tail(dclist_head *head, dlist_node *node)
{
if (head->dlist.head.next == NULL) /* convert NULL header to circular */
dclist_init(head);
dlist_push_tail(&head->dlist, node);
head->count++;
Assert(head->count > 0 ); /* count overflow check */
}
/*
* dclist_insert_after
* Insert a node after another * in the same list *
*
* Caution : ' after ' must be a member of ' head ' .
*/
static inline void
dclist_insert_after(dclist_head *head, dlist_node *after, dlist_node *node)
{
dlist_member_check(&head->dlist, after);
Assert(head->count > 0 ); /* must be at least 1 already */
dlist_insert_after(after, node);
head->count++;
Assert(head->count > 0 ); /* count overflow check */
}
/*
* dclist_insert_before
* Insert a node before another * in the same list *
*
* Caution : ' before ' must be a member of ' head ' .
*/
static inline void
dclist_insert_before(dclist_head *head, dlist_node *before, dlist_node *node)
{
dlist_member_check(&head->dlist, before);
Assert(head->count > 0 ); /* must be at least 1 already */
dlist_insert_before(before, node);
head->count++;
Assert(head->count > 0 ); /* count overflow check */
}
/*
* dclist_delete_from
* Deletes ' node ' from ' head ' .
*
* Caution : ' node ' must be a member of ' head ' .
*/
static inline void
dclist_delete_from(dclist_head *head, dlist_node *node)
{
Assert(head->count > 0 );
dlist_delete_from(&head->dlist, node);
head->count--;
}
/*
* Like dclist_delete_from ( ) , but also sets next / prev to NULL to signal not
* being in a list .
*/
static inline void
dclist_delete_from_thoroughly(dclist_head *head, dlist_node *node)
{
Assert(head->count > 0 );
dlist_delete_from_thoroughly(&head->dlist, node);
head->count--;
}
/*
* dclist_pop_head_node
* Remove and return the first node from a list ( there must be one ) .
*/
static inline dlist_node *
dclist_pop_head_node(dclist_head *head)
{
dlist_node *node;
Assert(head->count > 0 );
node = dlist_pop_head_node(&head->dlist);
head->count--;
return node;
}
/*
* dclist_move_head
* Move ' node ' from its current position in the list to the head position
* in ' head ' .
*
* Caution : ' node ' must be a member of ' head ' .
*/
static inline void
dclist_move_head(dclist_head *head, dlist_node *node)
{
dlist_member_check(&head->dlist, node);
Assert(head->count > 0 );
dlist_move_head(&head->dlist, node);
}
/*
* dclist_move_tail
* Move ' node ' from its current position in the list to the tail position
* in ' head ' .
*
* Caution : ' node ' must be a member of ' head ' .
*/
static inline void
dclist_move_tail(dclist_head *head, dlist_node *node)
{
dlist_member_check(&head->dlist, node);
Assert(head->count > 0 );
dlist_move_tail(&head->dlist, node);
}
/*
* dclist_has_next
* Check whether ' node ' has a following node .
*
* Caution : ' node ' must be a member of ' head ' .
*/
static inline bool
dclist_has_next(const dclist_head *head, const dlist_node *node)
{
dlist_member_check(&head->dlist, node);
Assert(head->count > 0 );
return dlist_has_next(&head->dlist, node);
}
/*
* dclist_has_prev
* Check whether ' node ' has a preceding node .
*
* Caution : ' node ' must be a member of ' head ' .
*/
static inline bool
dclist_has_prev(const dclist_head *head, const dlist_node *node)
{
dlist_member_check(&head->dlist, node);
Assert(head->count > 0 );
return dlist_has_prev(&head->dlist, node);
}
/*
* dclist_next_node
* Return the next node in the list ( there must be one ) .
*/
static inline dlist_node *
dclist_next_node(dclist_head *head, dlist_node *node)
{
Assert(head->count > 0 );
return dlist_next_node(&head->dlist, node);
}
/*
* dclist_prev_node
* Return the prev node in the list ( there must be one ) .
*/
static inline dlist_node *
dclist_prev_node(dclist_head *head, dlist_node *node)
{
Assert(head->count > 0 );
return dlist_prev_node(&head->dlist, node);
}
/* internal support function to get address of head element's struct */
static inline void *
dclist_head_element_off(dclist_head *head, size_t off)
{
Assert(!dclist_is_empty(head));
return (char *) head->dlist.head.next - off;
}
/*
* dclist_head_node
* Return the first node in the list ( there must be one ) .
*/
static inline dlist_node *
dclist_head_node(dclist_head *head)
{
Assert(head->count > 0 );
return (dlist_node *) dlist_head_element_off(&head->dlist, 0 );
}
/* internal support function to get address of tail element's struct */
static inline void *
dclist_tail_element_off(dclist_head *head, size_t off)
{
Assert(!dclist_is_empty(head));
return (char *) head->dlist.head.prev - off;
}
/*
* Return the last node in the list ( there must be one ) .
*/
static inline dlist_node *
dclist_tail_node(dclist_head *head)
{
Assert(head->count > 0 );
return (dlist_node *) dlist_tail_element_off(&head->dlist, 0 );
}
/*
* dclist_count
* Returns the stored number of entries in ' head '
*/
static inline uint32
dclist_count(const dclist_head *head)
{
Assert(dlist_is_empty(&head->dlist) == (head->count == 0 ));
return head->count;
}
/*
* Return the containing struct of ' type ' where ' membername ' is the dlist_node
* pointed at by ' ptr ' .
*
* This is used to convert a dlist_node * back to its containing struct .
*
* Note : This is effectively just the same as dlist_container , so reuse that .
*/
#define dclist_container(type, membername, ptr) \
dlist_container(type, membername, ptr)
/*
* Return the address of the first element in the list .
*
* The list must not be empty .
*/
#define dclist_head_element(type, membername, lhead) \
(AssertVariableIsOfTypeMacro(((type *) NULL)->membername, dlist_node), \
(type *) dclist_head_element_off(lhead, offsetof(type, membername)))
/*
* Return the address of the last element in the list .
*
* The list must not be empty .
*/
#define dclist_tail_element(type, membername, lhead) \
(AssertVariableIsOfTypeMacro(((type *) NULL)->membername, dlist_node), \
((type *) dclist_tail_element_off(lhead, offsetof(type, membername))))
/* Iterators for dclists */
#define dclist_foreach(iter, lhead) \
dlist_foreach(iter, &((lhead)->dlist))
#define dclist_foreach_modify(iter, lhead) \
dlist_foreach_modify(iter, &((lhead)->dlist))
#define dclist_reverse_foreach(iter, lhead) \
dlist_reverse_foreach(iter, &((lhead)->dlist))
/* singly linked list implementation */
/*
* Initialize a singly linked list .
* Previous state will be thrown away without any cleanup .
*/
static inline void
slist_init(slist_head *head)
{
head->head.next = NULL;
}
/*
* Is the list empty ?
*/
static inline bool
slist_is_empty(const slist_head *head)
{
slist_check(head);
return head->head.next == NULL;
}
/*
* Insert a node at the beginning of the list .
*/
static inline void
slist_push_head(slist_head *head, slist_node *node)
{
node->next = head->head.next;
head->head.next = node;
slist_check(head);
}
/*
* Insert a node after another * in the same list *
*/
static inline void
slist_insert_after(slist_node *after, slist_node *node)
{
node->next = after->next;
after->next = node;
}
/*
* Remove and return the first node from a list ( there must be one ) .
*/
static inline slist_node *
slist_pop_head_node(slist_head *head)
{
slist_node *node;
Assert(!slist_is_empty(head));
node = head->head.next;
head->head.next = node->next;
slist_check(head);
return node;
}
/*
* Check whether ' node ' has a following node .
*/
static inline bool
slist_has_next(const slist_head *head, const slist_node *node)
{
slist_check(head);
return node->next != NULL;
}
/*
* Return the next node in the list ( there must be one ) .
*/
static inline slist_node *
slist_next_node(slist_head *head, slist_node *node)
{
Assert(slist_has_next(head, node));
return node->next;
}
/* internal support function to get address of head element's struct */
static inline void *
slist_head_element_off(slist_head *head, size_t off)
{
Assert(!slist_is_empty(head));
return (char *) head->head.next - off;
}
/*
* Return the first node in the list ( there must be one ) .
*/
static inline slist_node *
slist_head_node(slist_head *head)
{
return (slist_node *) slist_head_element_off(head, 0 );
}
/*
* Delete the list element the iterator currently points to .
*
* Caution : this modifies iter - > cur , so don ' t use that again in the current
* loop iteration .
*/
static inline void
slist_delete_current(slist_mutable_iter *iter)
{
/*
* Update previous element ' s forward link . If the iteration is at the
* first list element , iter - > prev will point to the list header ' s " head "
* field , so we don ' t need a special case for that .
*/
iter->prev->next = iter->next;
/*
* Reset cur to prev , so that prev will continue to point to the prior
* valid list element after slist_foreach_modify ( ) advances to the next .
*/
iter->cur = iter->prev;
}
/*
* Return the containing struct of ' type ' where ' membername ' is the slist_node
* pointed at by ' ptr ' .
*
* This is used to convert a slist_node * back to its containing struct .
*/
#define slist_container(type, membername, ptr) \
(AssertVariableIsOfTypeMacro(ptr, slist_node *), \
AssertVariableIsOfTypeMacro(((type *) NULL)->membername, slist_node), \
((type *) ((char *) (ptr) - offsetof(type, membername))))
/*
* Return the address of the first element in the list .
*
* The list must not be empty .
*/
#define slist_head_element(type, membername, lhead) \
(AssertVariableIsOfTypeMacro(((type *) NULL)->membername, slist_node), \
(type *) slist_head_element_off(lhead, offsetof(type, membername)))
/*
* Iterate through the list pointed at by ' lhead ' storing the state in ' iter ' .
*
* Access the current element with iter . cur .
*
* It ' s allowed to modify the list while iterating , with the exception of
* deleting the iterator ' s current node ; deletion of that node requires
* care if the iteration is to be continued afterward . ( Doing so and also
* deleting or inserting adjacent list elements might misbehave ; also , if
* the user frees the current node ' s storage , continuing the iteration is
* not safe . )
*/
#define slist_foreach(iter, lhead) \
for (AssertVariableIsOfTypeMacro(iter, slist_iter), \
AssertVariableIsOfTypeMacro(lhead, slist_head *), \
(iter).cur = (lhead)->head.next; \
(iter).cur != NULL; \
(iter).cur = (iter).cur->next)
/*
* Iterate through the list pointed at by ' lhead ' storing the state in ' iter ' .
*
* Access the current element with iter . cur .
*
* The only list modification allowed while iterating is to remove the current
* node via slist_delete_current ( ) ( * not * slist_delete ( ) ) . Insertion or
* deletion of nodes adjacent to the current node would misbehave .
*/
#define slist_foreach_modify(iter, lhead) \
for (AssertVariableIsOfTypeMacro(iter, slist_mutable_iter), \
AssertVariableIsOfTypeMacro(lhead, slist_head *), \
(iter).prev = &(lhead)->head, \
(iter).cur = (iter).prev->next, \
(iter).next = (iter).cur ? (iter).cur->next : NULL; \
(iter).cur != NULL; \
(iter).prev = (iter).cur, \
(iter).cur = (iter).next, \
(iter).next = (iter).next ? (iter).next->next : NULL)
#endif /* ILIST_H */
Messung V0.5 in Prozent C=90 H=96 G=93
¤ Dauer der Verarbeitung: 0.32 Sekunden
(vorverarbeitet am 2026-08-06)
¤
*© Formatika GbR, Deutschland
2026-08-25
Neuigkeiten
Aktuelles
Motto des Tages
Open Source Software
Jenseits des Üblichen ....
Besucherstatistik
Statistik
#Sources=277311
#Domains=752002