#ifndef CCAN_LIST_H
#define CCAN_LIST_H
#include <stdbool.h>
+#include <assert.h>
#include <ccan/container_of/container_of.h>
/**
};
/**
- * list_check - check a list for consistency
+ * list_check - check head of a list for consistency
* @h: the list_head
* @abortstr: the location to print on aborting, or NULL.
*
* Returns the list head if the list is consistent, NULL if not (it
* can never return NULL if @abortstr is set).
*
+ * See also: list_check_node()
+ *
* Example:
* static void dump_parent(struct parent *p)
* {
* struct child *c;
*
- * printf("%s (%u children):\n", p->name, parent->num_children);
+ * printf("%s (%u children):\n", p->name, p->num_children);
* list_check(&p->children, "bad child list");
* list_for_each(&p->children, c, list)
* printf(" -> %s\n", c->name);
* }
*/
-struct list_head *list_check(struct list_head *h, const char *abortstr);
+struct list_head *list_check(const struct list_head *h, const char *abortstr);
+
+/**
+ * list_check_node - check node of a list for consistency
+ * @n: the list_node
+ * @abortstr: the location to print on aborting, or NULL.
+ *
+ * Check consistency of the list node is in (it must be in one).
+ *
+ * See also: list_check()
+ *
+ * Example:
+ * static void dump_child(const struct child *c)
+ * {
+ * list_check_node(&c->list, "bad child list");
+ * printf("%s\n", c->name);
+ * }
+ */
+struct list_node *list_check_node(const struct list_node *n,
+ 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_init - initialize a list_head
- * @h: the list_head to set to the empty list
+ * 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:
- * list_head_init(&parent->children);
- * parent->num_children = 0;
+ * static struct list_head my_list = LIST_HEAD_INIT(my_list);
*/
-static inline void list_head_init(struct list_head *h)
-{
- h->n.next = h->n.prev = &h->n;
-}
+#define LIST_HEAD_INIT(name) { { &name.n, &name.n } }
/**
- * LIST_HEAD - define and initalized empty list_head
+ * 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.
*
- * Example:
- * // Header:
- * extern struct list_head my_list;
+ * See also:
+ * LIST_HEAD_INIT, list_head_init()
*
- * // C file:
- * LIST_HEAD(my_list);
+ * 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
+ * @h: the list_head to set to the empty list
+ *
+ * Example:
+ * ...
+ * struct parent *parent = malloc(sizeof(*parent));
+ *
+ * list_head_init(&parent->children);
+ * parent->num_children = 0;
+ */
+static inline void list_head_init(struct list_head *h)
+{
+ h->n.next = h->n.prev = &h->n;
+}
/**
* list_add - add an entry at the start of a linked list.
*
* The list_node does not need to be initialized; it will be overwritten.
* Example:
+ * struct child *child = malloc(sizeof(*child));
+ *
+ * child->name = "marvin";
* list_add(&parent->children, &child->list);
* parent->num_children++;
*/
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_del - delete an entry from a linked list.
+ * 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 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(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);
}
/**
* @member: the list_node member of the type
*
* Example:
- * struct child *c;
* // First list entry is children.next; convert back to child.
- * c = list_entry(parent->children.next, struct child, list);
+ * child = list_entry(parent->children.n.next, struct child, list);
+ *
+ * See Also:
+ * list_top(), list_for_each()
*/
#define list_entry(n, type, member) container_of(n, type, member)
* a for loop, so you can break and continue as normal.
*
* Example:
- * struct child *c;
- * list_for_each(&parent->children, c, list)
- * printf("Name: %s\n", c->name);
+ * list_for_each(&parent->children, child, list)
+ * 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))
* @nxt is used to hold the next element, so you can delete @i from the list.
*
* Example:
- * struct child *c, *n;
- * list_for_each_safe(&parent->children, c, n, list) {
- * list_del(&c->list);
+ * struct child *next;
+ * list_for_each_safe(&parent->children, child, next, list) {
+ * list_del(&child->list);
* parent->num_children--;
* }
*/
#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))