Commit c2fbfe52 authored by Eric Wong's avatar Eric Wong Committed by Rusty Russell

list: add list_for_each_rev_safe{,_off} macros

Deleting while iterating backwards will be needed in the
Ruby st_foreach_reverse_check implementation if we decide
to port Ruby's st.c to use ccan/list.

ref: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/65408Signed-off-by: default avatarEric Wong <normalperson@yhbt.net>
Reviewed-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 79a88af5
......@@ -524,6 +524,28 @@ static inline const void *list_tail_(const struct list_head *h, size_t off)
#define list_for_each_rev(h, i, member) \
list_for_each_rev_off(h, i, list_off_var_(i, member))
/**
* list_for_each_rev_safe - iterate through a list backwards,
* maybe during deletion
* @h: the list_head
* @i: the structure containing the list_node
* @nxt: 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 backwards.
* It's a for loop, so you can break and continue as normal. The extra
* variable * @nxt is used to hold the next element, so you can delete @i
* from the list.
*
* Example:
* struct child *next;
* list_for_each_rev_safe(&parent->children, child, next, list) {
* printf("Name: %s\n", child->name);
* }
*/
#define list_for_each_rev_safe(h, i, nxt, member) \
list_for_each_rev_safe_off(h, i, nxt, list_off_var_(i, member))
/**
* list_for_each_safe - iterate through a list, maybe during deletion
* @h: the list_head
......@@ -536,7 +558,6 @@ static inline const void *list_tail_(const struct list_head *h, size_t off)
* @nxt is used to hold the next element, so you can delete @i from the list.
*
* Example:
* struct child *next;
* list_for_each_safe(&parent->children, child, next, list) {
* list_del(&child->list);
* parent->num_children--;
......@@ -731,6 +752,25 @@ static inline void list_prepend_list_(struct list_head *to,
#define list_for_each_safe_off(h, i, nxt, off) \
list_for_each_safe_off_dir_((h),(i),(nxt),(off),next)
/**
* list_for_each_rev_safe_off - iterate backwards through a list of
* memory regions, maybe during deletion
* @h: the list_head
* @i: the pointer to a memory region wich contains list node data.
* @nxt: the structure containing the list_node
* @off: offset(relative to @i) at which list node data resides.
*
* For details see `list_for_each_rev_off' and `list_for_each_rev_safe'
* descriptions.
*
* Example:
* list_for_each_rev_safe_off(&parent->children, child,
* next, offsetof(struct child, list))
* printf("Name: %s\n", child->name);
*/
#define list_for_each_rev_safe_off(h, i, nxt, off) \
list_for_each_safe_off_dir_((h),(i),(nxt),(off),prev)
/* Other -off variants. */
#define list_entry_off(n, type, off) \
((type *)list_node_from_off_((n), (off)))
......
......@@ -24,8 +24,9 @@ int main(int argc, char *argv[])
struct list_head list = LIST_HEAD_INIT(list);
opaque_t *q, *nq;
struct list_head opaque_list = LIST_HEAD_INIT(opaque_list);
LIST_HEAD(rev);
plan_tests(84);
plan_tests(92);
/* Test LIST_HEAD, LIST_HEAD_INIT, list_empty and check_list */
ok1(list_empty(&static_list));
ok1(list_check(&static_list, NULL));
......@@ -148,6 +149,10 @@ int main(int argc, char *argv[])
list_del_from(&parent.children, &c->list);
break;
}
/* prepare for list_for_each_rev_safe test */
list_add(&rev, &c->list);
ok1(list_check(&parent.children, NULL));
if (i > 2)
break;
......@@ -155,6 +160,30 @@ int main(int argc, char *argv[])
ok1(i == 3);
ok1(list_empty(&parent.children));
/* Test list_for_each_rev_safe, list_del and list_del_from. */
i = 0;
list_for_each_rev_safe(&rev, c, n, list) {
switch (i++) {
case 0:
ok1(c == &c1);
list_del(&c->list);
break;
case 1:
ok1(c == &c2);
list_del_from(&rev, &c->list);
break;
case 2:
ok1(c == &c3);
list_del_from(&rev, &c->list);
break;
}
ok1(list_check(&rev, NULL));
if (i > 2)
break;
}
ok1(i == 3);
ok1(list_empty(&rev));
/* Test list_node_init: safe to list_del after this. */
list_node_init(&c->list);
list_del(&c->list);
......
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