list: list_add_after and list_add_before functions
authorEric Wong <normalperson@yhbt.net>
Fri, 24 Oct 2014 22:02:28 +0000 (22:02 +0000)
committerRusty Russell <rusty@rustcorp.com.au>
Mon, 30 Mar 2015 06:46:32 +0000 (17:16 +1030)
These make it easy to add a new element before or after an
existing element in the middle of the list.

The existing list_add and list_add_tail functions are trivially
reimplemented on top of these new functions.

Signed-off-by: Eric Wong <normalperson@yhbt.net>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ccan/list/list.h
ccan/list/test/run.c

index cdd5eeb7e6e8523a85e348c7f775a65ca1185260..5c1159f48159987994341266616620f6f1c915c1 100644 (file)
@@ -157,6 +157,36 @@ static inline void list_node_init(struct list_node *n)
        n->next = n->prev = n;
 }
 
+/**
+ * list_add_after - add an entry after an existing node in a linked list
+ * @h: the list_head to add the node to (for debugging)
+ * @p: the existing list_node to add the node after
+ * @n: the new list_node to add to the list.
+ *
+ * The existing list_node must already be a member of the list.
+ * The new list_node does not need to be initialized; it will be overwritten.
+ *
+ * Example:
+ *     struct child c1, c2, c3;
+ *     LIST_HEAD(h);
+ *
+ *     list_add_tail(&h, &c1.list);
+ *     list_add_tail(&h, &c3.list);
+ *     list_add_after(&h, &c1.list, &c2.list);
+ */
+#define list_add_after(h, p, n) list_add_after_(h, p, n, LIST_LOC)
+static inline void list_add_after_(struct list_head *h,
+                                  struct list_node *p,
+                                  struct list_node *n,
+                                  const char *abortstr)
+{
+       n->next = p->next;
+       n->prev = p;
+       p->next->prev = n;
+       p->next = n;
+       (void)list_debug(h, abortstr);
+}
+
 /**
  * list_add - add an entry at the start of a linked list.
  * @h: the list_head to add the node to
@@ -175,10 +205,34 @@ static inline void list_add_(struct list_head *h,
                             struct list_node *n,
                             const char *abortstr)
 {
-       n->next = h->n.next;
-       n->prev = &h->n;
-       h->n.next->prev = n;
-       h->n.next = n;
+       list_add_after_(h, &h->n, n, abortstr);
+}
+
+/**
+ * list_add_before - add an entry before an existing node in a linked list
+ * @h: the list_head to add the node to (for debugging)
+ * @p: the existing list_node to add the node before
+ * @n: the new list_node to add to the list.
+ *
+ * The existing list_node must already be a member of the list.
+ * The new list_node does not need to be initialized; it will be overwritten.
+ *
+ * Example:
+ *     list_head_init(&h);
+ *     list_add_tail(&h, &c1.list);
+ *     list_add_tail(&h, &c3.list);
+ *     list_add_before(&h, &c3.list, &c2.list);
+ */
+#define list_add_before(h, p, n) list_add_before_(h, p, n, LIST_LOC)
+static inline void list_add_before_(struct list_head *h,
+                                   struct list_node *p,
+                                   struct list_node *n,
+                                   const char *abortstr)
+{
+       n->next = p;
+       n->prev = p->prev;
+       p->prev->next = n;
+       p->prev = n;
        (void)list_debug(h, abortstr);
 }
 
@@ -197,11 +251,7 @@ static inline void list_add_tail_(struct list_head *h,
                                  struct list_node *n,
                                  const char *abortstr)
 {
-       n->next = &h->n;
-       n->prev = h->n.prev;
-       h->n.prev->next = n;
-       h->n.prev = n;
-       (void)list_debug(h, abortstr);
+       list_add_before_(h, &h->n, n, abortstr);
 }
 
 /**
index 88c3835b4070b63949f002c44a4416bdef9cada0..2f1acc78a0605e959fbc94a21cd7eae2a5595018 100644 (file)
@@ -25,7 +25,7 @@ int main(int argc, char *argv[])
        opaque_t *q, *nq;
        struct list_head opaque_list = LIST_HEAD_INIT(opaque_list);
 
-       plan_tests(70);
+       plan_tests(79);
        /* Test LIST_HEAD, LIST_HEAD_INIT, list_empty and check_list */
        ok1(list_empty(&static_list));
        ok1(list_check(&static_list, NULL));
@@ -215,5 +215,43 @@ int main(int argc, char *argv[])
        ok1(list_top(&parent.children, struct child, list) == NULL);
        ok1(list_tail(&parent.children, struct child, list) == NULL);
        ok1(list_pop(&parent.children, struct child, list) == NULL);
+
+       /* Test list_add_before and list_add_after */
+       list_add(&parent.children, &c1.list);
+       list_add_after(&parent.children, &c1.list, &c2.list);
+       ok1(list_check(&parent.children, "list_add_after"));
+
+       i = 0;
+       list_for_each(&parent.children, c, list) {
+               switch (i++) {
+               case 0:
+                       ok1(c == &c1);
+                       break;
+               case 1:
+                       ok1(c == &c2);
+                       break;
+               }
+       }
+       ok1(i == 2);
+
+       list_add_before(&parent.children, &c2.list, &c3.list);
+       ok1(list_check(&parent.children, "list_add_before"));
+
+       i = 0;
+       list_for_each(&parent.children, c, list) {
+               switch (i++) {
+               case 0:
+                       ok1(c == &c1);
+                       break;
+               case 1:
+                       ok1(c == &c3);
+                       break;
+               case 2:
+                       ok1(c == &c2);
+                       break;
+               }
+       }
+       ok1(i == 3);
+
        return exit_status();
 }