#ifndef CCAN_LIST_H
#define CCAN_LIST_H
#include <stdbool.h>
+#include <assert.h>
#include <ccan/container_of/container_of.h>
/**
const char *abortstr);
#ifdef CCAN_LIST_DEBUG
-#define debug_list(h) list_check((h), __func__)
+#define list_debug(h) list_check((h), __func__)
+#define list_debug_node(n) list_check_node((n), __func__)
#else
-#define debug_list(h) (h)
+#define list_debug(h) (h)
+#define list_debug_node(n) (n)
#endif
/**
- * LIST_HEAD - define and initalize an empty list_head
+ * LIST_HEAD_INIT - initializer for an empty list_head
+ * @name: the name of the list.
+ *
+ * Explicit initializer for an empty list.
+ *
+ * See also:
+ * LIST_HEAD, list_head_init()
+ *
+ * Example:
+ * static struct list_head my_list = LIST_HEAD_INIT(my_list);
+ */
+#define LIST_HEAD_INIT(name) { { &name.n, &name.n } }
+
+/**
+ * LIST_HEAD - define and initialize an empty list_head
* @name: the name of the list.
*
* The LIST_HEAD macro defines a list_head and initializes it to an empty
* list. It can be prepended by "static" to define a static list_head.
*
+ * See also:
+ * LIST_HEAD_INIT, list_head_init()
+ *
* Example:
* static LIST_HEAD(my_global_list);
*/
#define LIST_HEAD(name) \
- struct list_head name = { { &name.n, &name.n } }
+ struct list_head name = LIST_HEAD_INIT(name)
/**
* list_head_init - initialize a list_head
n->prev = &h->n;
h->n.next->prev = n;
h->n.next = n;
- (void)debug_list(h);
+ (void)list_debug(h);
}
/**
n->prev = h->n.prev;
h->n.prev->next = n;
h->n.prev = n;
- (void)debug_list(h);
+ (void)list_debug(h);
+}
+
+/**
+ * list_empty - is a list empty?
+ * @h: the list_head
+ *
+ * If the list is empty, returns true.
+ *
+ * Example:
+ * assert(list_empty(&parent->children) == (parent->num_children == 0));
+ */
+static inline bool list_empty(const struct list_head *h)
+{
+ (void)list_debug(h);
+ return h->n.next == &h->n;
}
/**
- * list_del - delete an entry from a linked list.
+ * list_del - delete an entry from an (unknown) linked list.
* @n: the list_node to delete from the list.
*
+ * Note that this leaves @n in an undefined state; it can be added to
+ * another list, but not deleted again.
+ *
+ * See also:
+ * list_del_from()
+ *
* Example:
* list_del(&child->list);
* parent->num_children--;
*/
static inline void list_del(struct list_node *n)
{
+ (void)list_debug_node(n);
n->next->prev = n->prev;
n->prev->next = n->next;
- (void)debug_list(n->next);
#ifdef CCAN_LIST_DEBUG
/* Catch use-after-del. */
n->next = n->prev = NULL;
}
/**
- * list_empty - is a list empty?
- * @h: the list_head
+ * list_del_from - delete an entry from a known linked list.
+ * @h: the list_head the node is in.
+ * @n: the list_node to delete from the list.
*
- * If the list is empty, returns true.
+ * This explicitly indicates which list a node is expected to be in,
+ * which is better documentation and can catch more bugs.
+ *
+ * See also: list_del()
*
* Example:
- * assert(list_empty(&parent->children) == (parent->num_children == 0));
+ * list_del_from(&parent->children, &child->list);
+ * parent->num_children--;
*/
-static inline bool list_empty(const struct list_head *h)
+static inline void list_del_from(struct list_head *h, struct list_node *n)
{
- (void)debug_list(h);
- return h->n.next == &h->n;
+#ifdef CCAN_LIST_DEBUG
+ {
+ /* Thorough check: make sure it was in list! */
+ struct list_node *i;
+ for (i = h->n.next; i != n; i = i->next)
+ assert(i != &h->n);
+ }
+#endif /* CCAN_LIST_DEBUG */
+
+ /* Quick test that catches a surprising number of bugs. */
+ assert(!list_empty(h));
+ list_del(n);
}
/**
* printf("Name: %s\n", child->name);
*/
#define list_for_each(h, i, member) \
- for (i = container_of_var(debug_list(h)->n.next, i, member); \
+ for (i = container_of_var(list_debug(h)->n.next, i, member); \
&i->member != &(h)->n; \
i = container_of_var(i->member.next, i, member))
* }
*/
#define list_for_each_safe(h, i, nxt, member) \
- for (i = container_of_var(debug_list(h)->n.next, i, member), \
+ for (i = container_of_var(list_debug(h)->n.next, i, member), \
nxt = container_of_var(i->member.next, i, member); \
&i->member != &(h)->n; \
i = nxt, nxt = container_of_var(i->member.next, i, member))