From 5274d608523393cb849044b629513d5680fd572a Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Fri, 28 Sep 2012 16:41:20 +0200
Subject: [PATCH 2/4] Add [ds]list's which can be used to embed lists in
 bigger data structures without additional memory
 management

Alvaro, Andres, Review by Peter G. and Tom

Changes since last submission:
* naming is now [ds]list_*
* README is split back into the header
* README is rewritten
* much improved comments
* no error checking for empty lists anymore, Asserts added everywhere
* no multiple evaluation at all anymore
* introduction of [ds]list_iterator structs
* typechecking added to macros
* DLIST_STATIC_INIT added to initialize list elements at declaration time.
* added some more functions (symetry, new users)
* s/ILIST_USE_DEFINITION/ILIST_DEFINE_FUNCTIONS/
* don't declare ILIST_DEFINE_FUNCTIONS in the header, rely on USE_INLINE
* pgindent compatible styling
---
 src/backend/lib/Makefile |   2 +-
 src/backend/lib/ilist.c  | 117 ++++++++
 src/include/lib/ilist.h  | 760 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 878 insertions(+), 1 deletion(-)
 create mode 100644 src/backend/lib/ilist.c
 create mode 100644 src/include/lib/ilist.h

diff --git a/src/backend/lib/Makefile b/src/backend/lib/Makefile
index 2e1061e..c94297a 100644
--- a/src/backend/lib/Makefile
+++ b/src/backend/lib/Makefile
@@ -12,6 +12,6 @@ subdir = src/backend/lib
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = dllist.o stringinfo.o
+OBJS = dllist.o stringinfo.o ilist.o
 
 include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/lib/ilist.c b/src/backend/lib/ilist.c
new file mode 100644
index 0000000..de4a27d
--- /dev/null
+++ b/src/backend/lib/ilist.c
@@ -0,0 +1,117 @@
+/*-------------------------------------------------------------------------
+ *
+ * ilist.c
+ *	  support for integrated/inline doubly- and singly- linked lists
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/backend/lib/ilist.c
+ *
+ * NOTES
+ *	  This file only contains functions that are too big to be considered
+ *	  for inlining.  See ilist.h for most of the goodies.
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+/*
+ * If inlines are in use, include the header normally which will get us only
+ * the function definitions as inlines.  But if inlines aren't available,
+ * include the header with ILIST_DEFINE_FUNCTIONS defined; this makes it pour
+ * in regular (not inline) function declarations and the corresponding (non
+ * inline) definitions.
+ */
+#ifndef USE_INLINE
+#define ILIST_DEFINE_FUNCTIONS
+#endif
+
+#include "lib/ilist.h"
+
+/*
+ * removes a node from a list
+ *
+ * Attention: O(n)
+ */
+void
+slist_delete(slist_head *head, slist_node *node)
+{
+	slist_node *last = &head->head;
+	slist_node *cur;
+	bool found	PG_USED_FOR_ASSERTS_ONLY = false;
+
+	while ((cur = last->next) != NULL)
+	{
+		if (cur == node)
+		{
+			last->next = cur->next;
+#ifdef USE_ASSERT_CHECKING
+			found = true;
+#endif
+			break;
+		}
+		last = cur;
+	}
+
+	slist_check(head);
+	Assert(found);
+}
+
+#ifdef ILIST_DEBUG
+/*
+ * Verify integrity of a doubly linked list
+ */
+void
+dlist_check(dlist_head *head)
+{
+	dlist_node *cur;
+
+	if (head == NULL || !(&head->head))
+		elog(ERROR, "doubly linked list head is not properly initialized");
+
+	/* iterate in forward direction */
+	for (cur = head->head.next; cur != &head->head; cur = cur->next)
+	{
+		if (cur == NULL ||
+			cur->next == NULL ||
+			cur->prev == NULL ||
+			cur->prev->next != cur ||
+			cur->next->prev != cur)
+			elog(ERROR, "doubly linked list is corrupted");
+	}
+
+	/* iterate in backward direction */
+	for (cur = head->head.prev; cur != &head->head; cur = cur->prev)
+	{
+		if (cur == NULL ||
+			cur->next == NULL ||
+			cur->prev == NULL ||
+			cur->prev->next != cur ||
+			cur->next->prev != cur)
+			elog(ERROR, "doubly linked list is corrupted");
+	}
+}
+
+/*
+ * Verify integrity of a singly linked list
+ */
+void
+slist_check(slist_head *head)
+{
+	slist_node *cur;
+
+	if (head == NULL)
+		elog(ERROR, "singly linked is NULL");
+
+	/*
+	 * there isn't much we can test in a singly linked list other that it
+	 * actually ends sometime, i.e. hasn't introduced a circle or similar
+	 */
+	for (cur = head->head.next; cur != NULL; cur = cur->next)
+		;
+}
+
+#endif   /* ILIST_DEBUG */
diff --git a/src/include/lib/ilist.h b/src/include/lib/ilist.h
new file mode 100644
index 0000000..388e953
--- /dev/null
+++ b/src/include/lib/ilist.h
@@ -0,0 +1,760 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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.
+
+ * Also, the circular lists are always circularly linked, even when empty; this
+ * enables many manipulations to be done without branches, which is beneficial
+ * performance-wise.
+ *
+ * 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. The API for singly/doubly
+ * linked lists is identical as far as capabilities of both allow.
+ *
+ * // A oversimplified example demonstrating how this can be used:
+ *
+ * #include "lib/ilist.h"
+ *
+ * // Lets assume we want to store information about the tables contained in a
+ * // database.
+ *
+ * // 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;
+ *	   ...
+ * } value_in_a_list;
+ *
+ * // create a database
+ * my_database *db = create_database();
+ *
+ * // and a few tables
+ * 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 we allocate an iterator element to store
+ * // information about the current position
+ * dlist_iter iter;
+ *
+ * dlist_foreach (iter, &db->tables)
+ * {
+ *	   // inside an *_foreach the iterator's .cur field can be used to access
+ *	   // the current element
+ *	   // iter.cur points to a 'dlist_node', but we want the actual table
+ *	   // information, use dlist_container to convert
+ *	   my_table *tbl = dlist_container(my_table, list_node, iter->cur);
+ *	   elog(NOTICE, 'we have a table: %s in database %s',
+ *			val->tablename, db->datname);
+ * }
+ *
+ * // while a simple iteration is useful we sometimes also want to manipulate
+ * // the list while iterating. Say, we want to delete all tables!
+ *
+ * // declare an iterator that allows some list manipulations
+ * dlist_mutable_iter miter;
+ *
+ * // iterate
+ * dlist_foreach_modify(miter, &db->tables)
+ * {
+ *	   my_table *tbl = dlist_container(my_table, list_node, iter->cur);
+ *	   // unlink the current table from the linked list
+ *	   dlist_delete(&db->tables, iter->cur);
+ *	   // as ilists never manage memory, we can freely access the table
+ *	   drop_table(db, tbl);
+ * }
+ *
+ * // Note that none of the dlist_* functions did do any memory
+ * // management. They just manipulated externally managed memory.
+ *
+ *
+ * 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 with --enable-cassert.
+ */
+/* #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.
+ *
+ * Lists are internally *always* circularly linked, even when empty. Circular
+ * lists have the advantage of not needing any branches in the most common list
+ * manipulations.
+ */
+typedef struct dlist_head
+{
+	/*
+	 * head->next either points to the first element of the list or to &head
+	 * if empty.
+	 *
+	 * head->prev either points to the last element of the list or to &head if
+	 * empty.
+	 */
+	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 (how could they be?) in
+ * contrast to the 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. For consistency reasons with dlist_*iter and
+ * slist_mutable_iter we still use a separate type.
+ */
+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;
+
+
+/*
+ * We take quite some pain to allow this 'module' to be used on compilers
+ * without usable 'static inline' support. If configure detects its not
+ * available all the inline functions will be defined in ilist.c instead by
+ * #define'ing ILIST_USE_DEFINITION there.
+ */
+#ifdef USE_INLINE
+#define INLINE_IF_POSSIBLE static inline
+#else
+/* hide inline declarations from compiler */
+#define INLINE_IF_POSSIBLE
+
+/* Prototypes for functions we want to be inlined if possible */
+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);
+
+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   /* !USE_INLINE */
+
+/* These functions are too big to be inline, so they are in the C file always */
+
+/* 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 */
+
+#define DLIST_STATIC_INIT(name) {{&name.head, &name.head}}
+#define SLIST_STATIC_INIT(name) {{NULL}}
+
+/*
+ * The following function definitions are only used if inlining is supported by
+ * the compiler, or when included from a file that explicitly declares
+ * ILIST_USE_DEFINITION.
+ */
+#if defined(USE_INLINE) || defined(ILIST_DEFINE_FUNCTIONS)
+
+/*
+ * Initialize the head of a list. Previous state will be thrown away without
+ * any cleanup.
+ */
+INLINE_IF_POSSIBLE 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.
+ */
+INLINE_IF_POSSIBLE void
+dlist_push_head(dlist_head *head, dlist_node *node)
+{
+	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.
+ */
+INLINE_IF_POSSIBLE void
+dlist_push_tail(dlist_head *head, dlist_node *node)
+{
+	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*
+ */
+INLINE_IF_POSSIBLE 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*
+ */
+INLINE_IF_POSSIBLE void
+dlist_insert_before(dlist_head *head, dlist_node *before,
+					dlist_node *node)
+{
+	dlist_check(head);
+	/* XXX: assert 'after' 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'
+ */
+INLINE_IF_POSSIBLE 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.
+ */
+INLINE_IF_POSSIBLE 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 any position in the list to the head position in the same
+ * list.
+ *
+ * Undefined behaviour if 'node' is not already part of the list.
+ */
+INLINE_IF_POSSIBLE void
+dlist_move_head(dlist_head *head, dlist_node *node)
+{
+	/* fast path if it's already at the head */
+	if (&head->head == 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.
+ */
+INLINE_IF_POSSIBLE 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.
+ */
+INLINE_IF_POSSIBLE bool
+dlist_has_prev(dlist_head *head, dlist_node *node)
+{
+	return node->prev != &head->head;
+}
+
+/*
+ * Return the next node in the list.
+ *
+ * Undefined bheaviour when no next node exists, use dlist_has_next to make
+ * sure.
+ */
+INLINE_IF_POSSIBLE dlist_node *
+dlist_next_node(dlist_head *head, dlist_node *node)
+{
+	Assert(dlist_has_next(head, node));
+	return node->next;
+}
+
+/*
+ * Return previous node if there is one, NULL otherwise
+ *
+ * Undefined bheaviour when no prev node exists, use dlist_has_prev to make
+ * sure.
+ */
+INLINE_IF_POSSIBLE 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.
+ */
+INLINE_IF_POSSIBLE bool
+dlist_is_empty(dlist_head *head)
+{
+	return head->head.next == &(head->head);
+}
+
+/* internal support function */
+INLINE_IF_POSSIBLE 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.
+ */
+INLINE_IF_POSSIBLE dlist_node *
+dlist_head_node(dlist_head *head)
+{
+	return dlist_head_element_off(head, 0);
+}
+
+/* internal support function */
+INLINE_IF_POSSIBLE 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.
+ */
+INLINE_IF_POSSIBLE dlist_node *
+dlist_tail_node(dlist_head *head)
+{
+	return dlist_tail_element_off(head, 0);
+}
+#endif   /* defined(USE_INLINE) ||
+								 * defined(ILIST_DEFINE_FUNCTIONS) */
+
+/*
+ * Return the containing struct of 'type' where 'membername' is the dlist_node
+ * pointed at by 'ptr'.
+ *
+ * This is used to convert a dlist_node* returned by some list
+ * navigation/manipulation back to its content.
+ *
+ * Note that assert_compatible_types is a compile time only check, so we don't
+ * have multiple evaluation dangers here.
+ */
+#define dlist_container(type, membername, ptr)								 \
+	(assert_compatible_types_bool(dlist_node *, ptr),						 \
+	 assert_compatible_types_bool(dlist_node, ((type *)NULL)->membername),	 \
+	 ((type *)((char *)(ptr) - offsetof(type, membername)))					 \
+	 )
+/*
+ * Return the value of first element in the list.
+ *
+ * The list may not be empty.
+ *
+ * Note that assert_compatible_types is a compile time only check, so we don't
+ * have multiple evaluation dangers here.
+ */
+#define dlist_head_element(type, membername, ptr)							 \
+	(assert_compatible_types_bool(dlist_node, ((type*)NULL)->membername),	 \
+	 ((type *)dlist_get_head_off(ptr, offsetof(type, membername))))
+
+/*
+ * Return the value of first element in the list.
+ *
+ * The list may not be empty.
+ *
+ * Note that assert_compatible_types is a compile time only check, so we don't
+ * have multiple evaluation dangers here.
+ */
+#define dlist_tail_element(type, membername, ptr)							 \
+	(assert_compatible_types_bool(dlist_node, ((type*)NULL)->membername),	 \
+	 ((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)											 \
+	assert_compatible_types(dlist_iter, iter);								 \
+	assert_compatible_types(dlist_head *, ptr);								 \
+	for (iter.end = &(ptr)->head, iter.cur = iter.end->next;				 \
+		 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)										 \
+	assert_compatible_types(dlist_mutable_iter, iter);						 \
+	assert_compatible_types(dlist_head *, ptr);								 \
+	for (iter.end = &(ptr)->head, iter.cur = iter.end->next,				 \
+			 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)									 \
+	assert_compatible_types(dlist_iter, iter);								 \
+	assert_compatible_types(dlist_head *, ptr);								 \
+	for (iter.end = &(ptr)->head, iter.cur = iter.end->prev;				 \
+		 iter.cur != iter.end;												 \
+		 iter.cur = iter.cur->prev)
+
+#if defined(USE_INLINE) || defined(ILIST_DEFINE_FUNCTIONS)
+
+/*
+ * Initialize a singly linked list.
+ */
+INLINE_IF_POSSIBLE void
+slist_init(slist_head *head)
+{
+	head->head.next = NULL;
+
+	slist_check(head);
+}
+
+/*
+ * Is the list empty?
+ */
+INLINE_IF_POSSIBLE bool
+slist_is_empty(slist_head *head)
+{
+	slist_check(head);
+
+	return head->head.next == NULL;
+}
+
+/* internal support function */
+INLINE_IF_POSSIBLE 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.
+ */
+INLINE_IF_POSSIBLE 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.
+ */
+INLINE_IF_POSSIBLE 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.
+ */
+INLINE_IF_POSSIBLE 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
+ */
+INLINE_IF_POSSIBLE bool
+slist_has_next(slist_head *head,
+			   slist_node *node)
+{
+	slist_check(head);
+
+	return node->next != NULL;
+}
+#endif   /*-- defined(USE_INLINE || ILIST_DEFINE_FUNCTIONS) --*/
+
+/*
+ * Return the containing struct of 'type' where 'membername' is the slist_node
+ * pointed at by 'ptr'.
+ *
+ * This is used to convert a slist_node* returned by some list
+ * navigation/manipulation back to its content.
+ *
+ * Note that assert_compatible_types is a compile time only check, so we don't
+ * have multiple evaluation dangers here.
+ */
+#define slist_container(type, membername, ptr)								 \
+	(assert_compatible_types_bool(slist_node *, ptr),						 \
+	 assert_compatible_types_bool(slist_node, ((type*)NULL)->membername),	 \
+	 ((type *)((char *)(ptr) - offsetof(type, membername)))					 \
+	 )
+/*
+ * Return the value of first element in the list.
+ */
+#define slist_head_element(type, membername, ptr)							 \
+	(assert_compatible_types_bool(slist_node, ((type*)NULL)->membername),	 \
+	 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)											 \
+	assert_compatible_types(slist_iter, iter);								 \
+	assert_compatible_types(slist_head *, ptr);								 \
+	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. Every other manipulation can lead to
+ * corruption.
+ */
+#define slist_foreach_modify(iter, ptr)										 \
+	assert_compatible_types(slist_mutable_iter, iter);						 \
+	assert_compatible_types(slist_head *, ptr);								 \
+	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 */
-- 
1.7.12.289.g0ce9864.dirty

