summaryrefslogtreecommitdiff
path: root/src/include/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/include/lib')
-rw-r--r--src/include/lib/dllist.h85
-rw-r--r--src/include/lib/ilist.h767
2 files changed, 767 insertions, 85 deletions
diff --git a/src/include/lib/dllist.h b/src/include/lib/dllist.h
deleted file mode 100644
index 25ed64c7c4e..00000000000
--- a/src/include/lib/dllist.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * dllist.h
- * simple doubly linked list primitives
- * the elements of the list are void* so the lists can contain anything
- * Dlelem can only be in one list at a time
- *
- *
- * Here's a small example of how to use Dllists:
- *
- * Dllist *lst;
- * Dlelem *elt;
- * void *in_stuff; -- stuff to stick in the list
- * void *out_stuff
- *
- * lst = DLNewList(); -- make a new dllist
- * DLAddHead(lst, DLNewElem(in_stuff)); -- add a new element to the list
- * with in_stuff as the value
- * ...
- * elt = DLGetHead(lst); -- retrieve the head element
- * out_stuff = (void*)DLE_VAL(elt); -- get the stuff out
- * DLRemove(elt); -- removes the element from its list
- * DLFreeElem(elt); -- free the element since we don't
- * use it anymore
- *
- *
- * It is also possible to use Dllist objects that are embedded in larger
- * structures instead of being separately malloc'd. To do this, use
- * DLInitElem() to initialize a Dllist field within a larger object.
- * Don't forget to DLRemove() each field from its list (if any) before
- * freeing the larger object!
- *
- *
- * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * src/include/lib/dllist.h
- *
- *-------------------------------------------------------------------------
- */
-
-#ifndef DLLIST_H
-#define DLLIST_H
-
-struct Dllist;
-struct Dlelem;
-
-typedef struct Dlelem
-{
- struct Dlelem *dle_next; /* next element */
- struct Dlelem *dle_prev; /* previous element */
- void *dle_val; /* value of the element */
- struct Dllist *dle_list; /* what list this element is in */
-} Dlelem;
-
-typedef struct Dllist
-{
- Dlelem *dll_head;
- Dlelem *dll_tail;
-} Dllist;
-
-extern Dllist *DLNewList(void); /* allocate and initialize a list header */
-extern void DLInitList(Dllist *list); /* init a header alloced by caller */
-extern void DLFreeList(Dllist *list); /* free up a list and all the nodes in
- * it */
-extern Dlelem *DLNewElem(void *val);
-extern void DLInitElem(Dlelem *e, void *val);
-extern void DLFreeElem(Dlelem *e);
-extern void DLRemove(Dlelem *e); /* removes node from list */
-extern void DLAddHead(Dllist *list, Dlelem *node);
-extern void DLAddTail(Dllist *list, Dlelem *node);
-extern Dlelem *DLRemHead(Dllist *list); /* remove and return the head */
-extern Dlelem *DLRemTail(Dllist *list);
-extern void DLMoveToFront(Dlelem *e); /* move node to front of its list */
-
-/* These are macros for speed */
-#define DLGetHead(list) ((list)->dll_head)
-#define DLGetTail(list) ((list)->dll_tail)
-#define DLGetSucc(elem) ((elem)->dle_next)
-#define DLGetPred(elem) ((elem)->dle_prev)
-#define DLGetListHdr(elem) ((elem)->dle_list)
-
-#define DLE_VAL(elem) ((elem)->dle_val)
-
-#endif /* DLLIST_H */
diff --git a/src/include/lib/ilist.h b/src/include/lib/ilist.h
new file mode 100644
index 00000000000..54514423358
--- /dev/null
+++ b/src/include/lib/ilist.h
@@ -0,0 +1,767 @@
+/*-------------------------------------------------------------------------
+ *
+ * ilist.h
+ * integrated/inline doubly- and singly-linked lists
+ *
+ * This implementation is as efficient as possible: the lists don't have
+ * any memory management overhead, because the list pointers are embedded
+ * within some larger structure.
+ *
+ * There are two kinds of empty doubly linked lists: those that have been
+ * initialized to NULL, and those that have been initialized to circularity.
+ * The second kind is useful for tight optimization, because there are some
+ * operations that can be done without branches (and thus faster) on lists that
+ * have been initialized to circularity. Most users don't care all that much,
+ * and so can skip the initialization step until really required.
+ *
+ * NOTES
+ * This is intended to be used in situations where memory for a struct and
+ * its contents already needs to be allocated and the overhead of
+ * allocating extra list cells for every list element is noticeable. Thus,
+ * none of the functions here allocate any memory; they just manipulate
+ * externally managed memory. The API for singly/doubly linked lists is
+ * identical as far as capabilities of both allow.
+ *
+ * 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 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
+ * // information about prev/next list nodes.
+ * 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 element 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(&db->tables, miter.cur);
+ * // as these lists never manage memory, we can freely access the table
+ * // after it's been deleted
+ * drop_table(db, tbl);
+ * }
+ *
+ * Portions Copyright (c) 1996-2012, 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.
+ *
+ * Used as state in dlist_foreach() and dlist_reverse_foreach(). 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 type for this to make it possible to avoid multiple
+ * evaluations of arguments in the dlist_foreach() macro.
+ */
+typedef struct dlist_iter
+{
+ dlist_node *end; /* last node we iterate to */
+ dlist_node *cur; /* current element */
+} dlist_iter;
+
+/*
+ * Doubly linked list iterator allowing some modifications while iterating
+ *
+ * Used as state in dlist_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 modify other nodes.
+ *
+ * NB: We need a separate type for mutable iterations to avoid having to pass
+ * in two iterators or some other state variable as we need to store the
+ * '->next' node of the current node so it can be deleted or modified by the
+ * user.
+ */
+typedef struct dlist_mutable_iter
+{
+ dlist_node *end; /* last node we iterate to */
+ dlist_node *cur; /* current element */
+ dlist_node *next; /* next node we iterate to, so we can delete
+ * cur */
+} dlist_mutable_iter;
+
+/*
+ * 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. As no pointer to the last list element and to the previous node needs
+ * to be maintained 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 in slist_foreach(). To get the current element of the iteration use the
+ * 'cur' member.
+ *
+ * Do *not* manipulate the list while iterating!
+ *
+ * NB: this wouldn't really need to be an extra struct, we could use a
+ * slist_node * directly. We still use a separate type for consistency.
+ */
+typedef struct slist_iter
+{
+ slist_node *cur;
+} slist_iter;
+
+/*
+ * Singly linked list iterator allowing some modifications while iterating
+ *
+ * Used in slist_foreach_modify.
+ *
+ * Iterations using this are allowed to remove the current node and to add more
+ * nodes to the beginning of the list.
+ */
+typedef struct slist_mutable_iter
+{
+ slist_node *cur;
+ slist_node *next;
+} slist_mutable_iter;
+
+
+/* Prototypes for functions too big to be inline */
+
+/* Attention: O(n) */
+extern void slist_delete(slist_head *head, slist_node *node);
+
+#ifdef ILIST_DEBUG
+extern void dlist_check(dlist_head *head);
+extern void slist_check(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_check(head) (void) (head)
+#define slist_check(head) (void) (head)
+#endif /* ILIST_DEBUG */
+
+/* Static initializers */
+#define DLIST_STATIC_INIT(name) {{&name.head, &name.head}}
+#define SLIST_STATIC_INIT(name) {{NULL}}
+
+
+/*
+ * We want the functions below to be inline; but if the compiler doesn't
+ * support that, fall back on providing them as regular functions. See
+ * STATIC_IF_INLINE in c.h.
+ */
+#ifndef PG_USE_INLINE
+extern void dlist_init(dlist_head *head);
+extern bool dlist_is_empty(dlist_head *head);
+extern void dlist_push_head(dlist_head *head, dlist_node *node);
+extern void dlist_push_tail(dlist_head *head, dlist_node *node);
+extern void dlist_insert_after(dlist_head *head,
+ dlist_node *after, dlist_node *node);
+extern void dlist_insert_before(dlist_head *head,
+ dlist_node *before, dlist_node *node);
+extern void dlist_delete(dlist_head *head, dlist_node *node);
+extern dlist_node *dlist_pop_head_node(dlist_head *head);
+extern void dlist_move_head(dlist_head *head, dlist_node *node);
+extern bool dlist_has_next(dlist_head *head, dlist_node *node);
+extern bool dlist_has_prev(dlist_head *head, dlist_node *node);
+extern dlist_node *dlist_next_node(dlist_head *head, dlist_node *node);
+extern dlist_node *dlist_prev_node(dlist_head *head, dlist_node *node);
+extern dlist_node *dlist_head_node(dlist_head *head);
+extern dlist_node *dlist_tail_node(dlist_head *head);
+
+/* dlist macro support functions */
+extern void *dlist_tail_element_off(dlist_head *head, size_t off);
+extern void *dlist_head_element_off(dlist_head *head, size_t off);
+#endif /* !PG_USE_INLINE */
+
+#if defined(PG_USE_INLINE) || defined(ILIST_INCLUDE_DEFINITIONS)
+/*
+ * Initialize the head of a list. Previous state will be thrown away without
+ * any cleanup.
+ */
+STATIC_IF_INLINE void
+dlist_init(dlist_head *head)
+{
+ head->head.next = head->head.prev = &head->head;
+
+ dlist_check(head);
+}
+
+/*
+ * Insert a node at the beginning of the list.
+ */
+STATIC_IF_INLINE void
+dlist_push_head(dlist_head *head, dlist_node *node)
+{
+ if (head->head.next == NULL)
+ dlist_init(head);
+
+ node->next = head->head.next;
+ node->prev = &head->head;
+ node->next->prev = node;
+ head->head.next = node;
+
+ dlist_check(head);
+}
+
+/*
+ * Inserts a node at the end of the list.
+ */
+STATIC_IF_INLINE void
+dlist_push_tail(dlist_head *head, dlist_node *node)
+{
+ if (head->head.next == NULL)
+ 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_IF_INLINE void
+dlist_insert_after(dlist_head *head, dlist_node *after, dlist_node *node)
+{
+ dlist_check(head);
+ /* XXX: assert 'after' is in 'head'? */
+
+ node->prev = after;
+ node->next = after->next;
+ after->next = node;
+ node->next->prev = node;
+
+ dlist_check(head);
+}
+
+/*
+ * Insert a node before another *in the same list*
+ */
+STATIC_IF_INLINE void
+dlist_insert_before(dlist_head *head, dlist_node *before, dlist_node *node)
+{
+ dlist_check(head);
+ /* XXX: assert 'before' is in 'head'? */
+
+ node->prev = before->prev;
+ node->next = before;
+ before->prev = node;
+ node->prev->next = node;
+
+ dlist_check(head);
+}
+
+/*
+ * Delete 'node' from list.
+ *
+ * It is not allowed to delete a 'node' which is is not in the list 'head'
+ */
+STATIC_IF_INLINE void
+dlist_delete(dlist_head *head, dlist_node *node)
+{
+ dlist_check(head);
+
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+
+ dlist_check(head);
+}
+
+/*
+ * Delete and return the first node from a list.
+ *
+ * Undefined behaviour when the list is empty. Check with dlist_is_empty if
+ * necessary.
+ */
+STATIC_IF_INLINE dlist_node *
+dlist_pop_head_node(dlist_head *head)
+{
+ dlist_node *ret;
+
+ Assert(&head->head != head->head.next);
+
+ ret = head->head.next;
+ dlist_delete(head, head->head.next);
+ return ret;
+}
+
+/*
+ * 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_IF_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(head, node);
+ dlist_push_head(head, node);
+
+ dlist_check(head);
+}
+
+/*
+ * Check whether the passed node is the last element in the list.
+ */
+STATIC_IF_INLINE bool
+dlist_has_next(dlist_head *head, dlist_node *node)
+{
+ return node->next != &head->head;
+}
+
+/*
+ * Check whether the passed node is the first element in the list.
+ */
+STATIC_IF_INLINE bool
+dlist_has_prev(dlist_head *head, dlist_node *node)
+{
+ return node->prev != &head->head;
+}
+
+/*
+ * Return the next node in the list.
+ *
+ * Undefined behaviour when no next node exists. Use dlist_has_next to make
+ * sure.
+ */
+STATIC_IF_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.
+ *
+ * Undefined behaviour when no prev node exists. Use dlist_has_prev to make
+ * sure.
+ */
+STATIC_IF_INLINE dlist_node *
+dlist_prev_node(dlist_head *head, dlist_node *node)
+{
+ Assert(dlist_has_prev(head, node));
+ return node->prev;
+}
+
+/*
+ * Return whether the list is empty.
+ *
+ * An empty list has either its first 'next' pointer set to NULL, or to itself.
+ */
+STATIC_IF_INLINE bool
+dlist_is_empty(dlist_head *head)
+{
+ dlist_check(head);
+
+ return head->head.next == NULL || head->head.next == &(head->head);
+}
+
+/* internal support function */
+STATIC_IF_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.
+ *
+ * Use dlist_is_empty to make sure the list is not empty if not sure.
+ */
+STATIC_IF_INLINE dlist_node *
+dlist_head_node(dlist_head *head)
+{
+ return dlist_head_element_off(head, 0);
+}
+
+/* internal support function */
+STATIC_IF_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.
+ *
+ * Use dlist_is_empty to make sure the list is not empty if not sure.
+ */
+STATIC_IF_INLINE dlist_node *
+dlist_tail_node(dlist_head *head)
+{
+ return dlist_tail_element_off(head, 0);
+}
+#endif /* PG_USE_INLINE || ILIST_INCLUDE_DEFINITIONS */
+
+/*
+ * 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 that AssertVariableIsOfTypeMacro is a compile-time only check, so we
+ * don't have multiple evaluation dangers here.
+ */
+#define dlist_container(type, membername, ptr) \
+ (AssertVariableIsOfTypeMacro(ptr, dlist_node *), \
+ AssertVariableIsOfTypeMacro(((type *) NULL)->membername, dlist_node), \
+ ((type *)((char *)(ptr) - offsetof(type, membername))))
+
+/*
+ * Return the value of first element in the list.
+ *
+ * The list must not be empty.
+ *
+ * Note that AssertVariableIsOfTypeMacro is a compile-time only check, so we
+ * don't have multiple evaluation dangers here.
+ */
+#define dlist_head_element(type, membername, ptr) \
+ (AssertVariableIsOfTypeMacro(((type *) NULL)->membername, dlist_node), \
+ ((type *)dlist_head_element_off(ptr, offsetof(type, membername))))
+
+/*
+ * Return the value of first element in the list.
+ *
+ * The list must not be empty.
+ *
+ * Note that AssertVariableIsOfTypeMacro is a compile-time only check, so we
+ * don't have multiple evaluation dangers here.
+ */
+#define dlist_tail_element(type, membername, ptr) \
+ (AssertVariableIsOfTypeMacro(((type *) NULL)->membername, dlist_node), \
+ ((type *)dlist_tail_element_off(ptr, offsetof(type, membername))))
+
+/*
+ * Iterate through the list pointed at by 'ptr' 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, ptr) \
+ AssertVariableIsOfType(iter, dlist_iter); \
+ AssertVariableIsOfType(ptr, dlist_head *); \
+ for (iter.end = &(ptr)->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 'ptr' storing the state in 'iter'.
+ *
+ * Access the current element with iter.cur.
+ *
+ * It is allowed to delete the current element from the list. Every other
+ * manipulation can lead to corruption.
+ */
+#define dlist_foreach_modify(iter, ptr) \
+ AssertVariableIsOfType(iter, dlist_mutable_iter); \
+ AssertVariableIsOfType(ptr, dlist_head *); \
+ for (iter.end = &(ptr)->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, ptr) \
+ AssertVariableIsOfType(iter, dlist_iter); \
+ AssertVariableIsOfType(ptr, dlist_head *); \
+ for (iter.end = &(ptr)->head, \
+ iter.cur = iter.end->prev ? iter.end->prev : iter.end; \
+ iter.cur != iter.end; \
+ iter.cur = iter.cur->prev)
+
+
+/*
+ * We want the functions below to be inline; but if the compiler doesn't
+ * support that, fall back on providing them as regular functions. See
+ * STATIC_IF_INLINE in c.h.
+ */
+#ifndef PG_USE_INLINE
+extern void slist_init(slist_head *head);
+extern bool slist_is_empty(slist_head *head);
+extern slist_node *slist_head_node(slist_head *head);
+extern void slist_push_head(slist_head *head, slist_node *node);
+extern slist_node *slist_pop_head_node(slist_head *head);
+extern void slist_insert_after(slist_head *head,
+ slist_node *after, slist_node *node);
+extern bool slist_has_next(slist_head *head, slist_node *node);
+extern slist_node *slist_next_node(slist_head *head, slist_node *node);
+
+/* slist macro support function */
+extern void *slist_head_element_off(slist_head *head, size_t off);
+#endif
+
+#if defined(PG_USE_INLINE) || defined(ILIST_INCLUDE_DEFINITIONS)
+/*
+ * Initialize a singly linked list.
+ */
+STATIC_IF_INLINE void
+slist_init(slist_head *head)
+{
+ head->head.next = NULL;
+
+ slist_check(head);
+}
+
+/*
+ * Is the list empty?
+ */
+STATIC_IF_INLINE bool
+slist_is_empty(slist_head *head)
+{
+ slist_check(head);
+
+ return head->head.next == NULL;
+}
+
+/* internal support function */
+STATIC_IF_INLINE void *
+slist_head_element_off(slist_head *head, size_t off)
+{
+ Assert(!slist_is_empty(head));
+ return (char *) head->head.next - off;
+}
+
+/*
+ * Push 'node' as the new first node in the list, pushing the original head to
+ * the second position.
+ */
+STATIC_IF_INLINE void
+slist_push_head(slist_head *head, slist_node *node)
+{
+ node->next = head->head.next;
+ head->head.next = node;
+
+ slist_check(head);
+}
+
+/*
+ * Remove and return the first node in the list
+ *
+ * Undefined behaviour if the list is empty.
+ */
+STATIC_IF_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 = head->head.next->next;
+
+ slist_check(head);
+
+ return node;
+}
+
+/*
+ * Insert a new node after another one
+ *
+ * Undefined behaviour if 'after' is not part of the list already.
+ */
+STATIC_IF_INLINE void
+slist_insert_after(slist_head *head, slist_node *after,
+ slist_node *node)
+{
+ node->next = after->next;
+ after->next = node;
+
+ slist_check(head);
+}
+
+/*
+ * Return whether 'node' has a following node
+ */
+STATIC_IF_INLINE bool
+slist_has_next(slist_head *head,
+ slist_node *node)
+{
+ slist_check(head);
+
+ return node->next != NULL;
+}
+#endif /* PG_USE_INLINE || ILIST_INCLUDE_DEFINITIONS */
+
+/*
+ * 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.
+ *
+ * Note that AssertVariableIsOfTypeMacro is a compile-time only check, so we
+ * don't have multiple evaluation dangers here.
+ */
+#define slist_container(type, membername, ptr) \
+ (AssertVariableIsOfTypeMacro(ptr, slist_node *), \
+ AssertVariableIsOfTypeMacro(((type *) NULL)->membername, slist_node), \
+ ((type *)((char *)(ptr) - offsetof(type, membername))))
+
+/*
+ * Return the value of first element in the list.
+ */
+#define slist_head_element(type, membername, ptr) \
+ (AssertVariableIsOfTypeMacro(((type *) NULL)->membername, slist_node), \
+ slist_head_element_off(ptr, offsetoff(type, membername)))
+
+/*
+ * Iterate through the list 'ptr' using the iterator 'iter'.
+ *
+ * It is *not* allowed to manipulate the list during iteration.
+ */
+#define slist_foreach(iter, ptr) \
+ AssertVariableIsOfType(iter, slist_iter); \
+ AssertVariableIsOfType(ptr, slist_head *); \
+ for (iter.cur = (ptr)->head.next; \
+ iter.cur != NULL; \
+ iter.cur = iter.cur->next)
+
+/*
+ * Iterate through the list 'ptr' using the iterator 'iter' allowing some
+ * modifications.
+ *
+ * It is allowed to delete the current element from the list and add new nodes
+ * before the current position. Other manipulations can lead to corruption.
+ */
+#define slist_foreach_modify(iter, ptr) \
+ AssertVariableIsOfType(iter, slist_mutable_iter); \
+ AssertVariableIsOfType(ptr, slist_head *); \
+ for (iter.cur = (ptr)->head.next, \
+ iter.next = iter.cur ? iter.cur->next : NULL; \
+ iter.cur != NULL; \
+ iter.cur = iter.next, \
+ iter.next = iter.next ? iter.next->next : NULL)
+
+#endif /* ILIST_H */