Browse Source

New list_tail() function and test for list_top() on empty list reveals a
bug!

Rusty Russell 17 years ago
parent
commit
0c492447b9
2 changed files with 23 additions and 9 deletions
  1. 15 8
      ccan/list/list.h
  2. 8 1
      ccan/list/test/run.c

+ 15 - 8
ccan/list/list.h

@@ -198,15 +198,22 @@ static inline bool list_empty(struct list_head *h)
  *	first = list_top(&parent->children, struct child, list);
  */
 #define list_top(h, type, member) \
-	list_entry(_list_top(h), type, member)	
+	(list_empty(h) ? NULL : list_entry((h)->n.next, type, member))
 
-static inline struct list_node *_list_top(struct list_head *h)
-{
-	(void)debug_list(h);
-	if (list_empty(h))
-		return NULL;
-	return h->n.next;
-}
+/**
+ * list_tail - get the last entry in a list
+ * @h: the list_head
+ * @type: the type of the entry
+ * @member: the list_node member of the type
+ *
+ * If the list is empty, returns NULL.
+ *
+ * Example:
+ *	struct child *last;
+ *	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))
 
 /**
  * list_for_each - iterate through a list.

+ 8 - 1
ccan/list/test/run.c

@@ -21,7 +21,7 @@ int main(int argc, char *argv[])
 	struct child c1, c2, c3, *c, *n;
 	unsigned int i;
 
-	plan_tests(41);
+	plan_tests(44);
 	/* Test LIST_HEAD, list_empty and check_list */
 	ok1(list_empty(&static_list));
 	ok1(list_check(&static_list, NULL));
@@ -74,6 +74,9 @@ int main(int argc, char *argv[])
 	/* Test list_top */
 	ok1(list_top(&parent.children, struct child, list) == &c1);
 
+	/* Test list_tail */
+	ok1(list_tail(&parent.children, struct child, list) == &c3);
+
 	/* Test list_for_each. */
 	i = 0;
 	list_for_each(&parent.children, c, list) {
@@ -114,5 +117,9 @@ int main(int argc, char *argv[])
 	}
 	ok1(i == 3);
 	ok1(list_empty(&parent.children));
+
+	/* Test list_top/list_tail on empty list. */
+	ok1(list_top(&parent.children, struct child, list) == NULL);
+	ok1(list_tail(&parent.children, struct child, list) == NULL);
 	return exit_status();
 }