+/* Licensed under LGPLv2.1+ - see LICENSE file for details */
#ifndef CCAN_LIST_H
#define CCAN_LIST_H
#include <stdbool.h>
+#include <assert.h>
#include <ccan/container_of/container_of.h>
+#include <ccan/check_type/check_type.h>
/**
* struct list_node - an entry in a doubly-linked list
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_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(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);
}
/**
* struct child *first;
* first = list_top(&parent->children, struct child, list);
*/
-#define list_top(h, type, member) \
- (list_empty(h) ? NULL : list_entry((h)->n.next, type, member))
+#define list_top(h, type, member) \
+ ((type *)list_top_((h), list_off_(type, member)))
+
+static inline const void *list_top_(const struct list_head *h, size_t off)
+{
+ if (list_empty(h))
+ return NULL;
+ return (const char *)h->n.next - off;
+}
/**
* list_tail - get the last entry in a list
* last = list_tail(&parent->children, struct child, list);
*/
#define list_tail(h, type, member) \
- (list_empty(h) ? NULL : list_entry((h)->n.prev, type, member))
+ ((type *)list_tail_((h), list_off_(type, member)))
+
+static inline const void *list_tail_(const struct list_head *h, size_t off)
+{
+ if (list_empty(h))
+ return NULL;
+ return (const char *)h->n.prev - off;
+}
/**
* list_for_each - iterate through a list.
- * @h: the list_head
+ * @h: the list_head (warning: evaluated multiple times!)
* @i: the structure containing the list_node
* @member: the list_node member of the structure
*
* 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))
+/**
+ * list_for_each_rev - iterate through a list backwards.
+ * @h: the list_head
+ * @i: the structure containing the list_node
+ * @member: the list_node member of the structure
+ *
+ * This is a convenient wrapper to iterate @i over the entire list. It's
+ * a for loop, so you can break and continue as normal.
+ *
+ * Example:
+ * list_for_each_rev(&parent->children, child, list)
+ * printf("Name: %s\n", child->name);
+ */
+#define list_for_each_rev(h, i, member) \
+ for (i = container_of_var(list_debug(h)->n.prev, i, member); \
+ &i->member != &(h)->n; \
+ i = container_of_var(i->member.prev, i, member))
+
/**
* list_for_each_safe - iterate through a list, maybe during deletion
* @h: the list_head
* }
*/
#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))
+
+/* Get the offset of the member, but make sure it's a list_node. */
+#define list_off_(type, member) \
+ (container_off(type, member) + \
+ check_type(((type *)0)->member, struct list_node))
+
#endif /* CCAN_LIST_H */