Commit b160cdd0 authored by Rusty Russell's avatar Rusty Russell

list: add list_next and list_prev helpers.

Some way towards iterating in the middle of the list.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 5628cd2c
......@@ -399,6 +399,43 @@ static inline const void *list_tail_(const struct list_head *h, size_t off)
#define list_for_each_safe(h, i, nxt, member) \
list_for_each_safe_off(h, i, nxt, list_off_var_(i, member))
/**
* list_next - get the next entry in a list
* @h: the list_head
* @i: a pointer to an entry in the list.
* @member: the list_node member of the structure
*
* If @i was the last entry in the list, returns NULL.
*
* Example:
* struct child *second;
* second = list_next(&parent->children, first, list);
* if (!second)
* printf("No second child!\n");
*/
#define list_next(h, i, member) \
((list_typeof(i))list_entry_or_null(list_debug(h), \
(i)->member.next, \
list_off_var_((i), member)))
/**
* list_prev - get the previous entry in a list
* @h: the list_head
* @i: a pointer to an entry in the list.
* @member: the list_node member of the structure
*
* If @i was the first entry in the list, returns NULL.
*
* Example:
* first = list_prev(&parent->children, second, list);
* if (!first)
* printf("Can't go back to first child?!\n");
*/
#define list_prev(h, i, member) \
((list_typeof(i))list_entry_or_null(list_debug(h), \
(i)->member.prev, \
list_off_var_((i), member)))
/**
* list_append_list - empty one list onto the end of another.
* @to: the list to append into
......@@ -560,4 +597,19 @@ static inline struct list_node *list_node_from_off_(void *ptr, size_t off)
(container_off_var(var, member) + \
check_type(var->member, struct list_node))
#if HAVE_TYPEOF
#define list_typeof(var) typeof(var)
#else
#define list_typeof(var) void *
#endif
/* Returns member, or NULL if at end of list. */
static inline void *list_entry_or_null(struct list_head *h,
struct list_node *n,
size_t off)
{
if (n == &h->n)
return NULL;
return (char *)n - off;
}
#endif /* CCAN_LIST_H */
#include <ccan/list/list.h>
#include <ccan/tap/tap.h>
#include <ccan/list/list.c>
#include "helper.h"
struct parent {
const char *name;
unsigned int num_children;
struct list_head children;
};
struct child {
const char *name;
struct list_node list;
};
int main(int argc, char *argv[])
{
struct parent parent;
struct child c1, c2, c3;
plan_tests(12);
parent.num_children = 0;
list_head_init(&parent.children);
c1.name = "c1";
list_add(&parent.children, &c1.list);
ok1(list_next(&parent.children, &c1, list) == NULL);
ok1(list_prev(&parent.children, &c1, list) == NULL);
c2.name = "c2";
list_add_tail(&parent.children, &c2.list);
ok1(list_next(&parent.children, &c1, list) == &c2);
ok1(list_prev(&parent.children, &c1, list) == NULL);
ok1(list_next(&parent.children, &c2, list) == NULL);
ok1(list_prev(&parent.children, &c2, list) == &c1);
c3.name = "c3";
list_add_tail(&parent.children, &c3.list);
ok1(list_next(&parent.children, &c1, list) == &c2);
ok1(list_prev(&parent.children, &c1, list) == NULL);
ok1(list_next(&parent.children, &c2, list) == &c3);
ok1(list_prev(&parent.children, &c2, list) == &c1);
ok1(list_next(&parent.children, &c3, list) == NULL);
ok1(list_prev(&parent.children, &c3, list) == &c2);
return exit_status();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment