X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Flist%2Flist.h;h=8e2f6df0273998764bb89cb69fb4c25d6e5b1070;hp=0091ea4b655216754a347cb4ccb655aa8823177e;hb=c35fcafc261eb9c0f5aff1a608568b38ddc01f66;hpb=e59b7388d8b2b56dc759be7c2dbf63100d2e131f diff --git a/ccan/list/list.h b/ccan/list/list.h index 0091ea4b..8e2f6df0 100644 --- a/ccan/list/list.h +++ b/ccan/list/list.h @@ -1,4 +1,4 @@ -/* Licensed under LGPLv2.1+ - see LICENSE file for details */ +/* Licensed under BSD-MIT - see LICENSE file for details */ #ifndef CCAN_LIST_H #define CCAN_LIST_H #include @@ -279,6 +279,8 @@ static inline void list_del_from(struct list_head *h, struct list_node *n) * Example: * struct child *first; * first = list_top(&parent->children, struct child, list); + * if (!first) + * printf("Empty list!\n"); */ #define list_top(h, type, member) \ ((type *)list_top_((h), list_off_(type, member))) @@ -301,6 +303,8 @@ static inline const void *list_top_(const struct list_head *h, size_t off) * Example: * struct child *last; * last = list_tail(&parent->children, struct child, list); + * if (!last) + * printf("Empty list!\n"); */ #define list_tail(h, type, member) \ ((type *)list_tail_((h), list_off_(type, member))) @@ -367,6 +371,68 @@ 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_append_list - empty one list onto the end of another. + * @to: the list to append into + * @from: the list to empty. + * + * This takes the entire contents of @from and moves it to the end of + * @to. After this @from will be empty. + * + * Example: + * struct list_head adopter; + * + * list_append_list(&adopter, &parent->children); + * assert(list_empty(&parent->children)); + * parent->num_children = 0; + */ +static inline void list_append_list(struct list_head *to, + struct list_head *from) +{ + struct list_node *from_tail = list_debug(from)->n.prev; + struct list_node *to_tail = list_debug(to)->n.prev; + + /* Sew in head and entire list. */ + to->n.prev = from_tail; + from_tail->next = &to->n; + to_tail->next = &from->n; + from->n.prev = to_tail; + + /* Now remove head. */ + list_del(&from->n); + list_head_init(from); +} + +/** + * list_prepend_list - empty one list into the start of another. + * @to: the list to prepend into + * @from: the list to empty. + * + * This takes the entire contents of @from and moves it to the start + * of @to. After this @from will be empty. + * + * Example: + * list_prepend_list(&adopter, &parent->children); + * assert(list_empty(&parent->children)); + * parent->num_children = 0; + */ +static inline void list_prepend_list(struct list_head *to, + struct list_head *from) +{ + struct list_node *from_tail = list_debug(from)->n.prev; + struct list_node *to_head = list_debug(to)->n.next; + + /* Sew in head and entire list. */ + to->n.next = &from->n; + from->n.prev = &to->n; + to_head->prev = from_tail; + from_tail->next = to_head; + + /* Now remove head. */ + list_del(&from->n); + list_head_init(from); +} + /** * list_for_each_off - iterate through a list of memory regions. * @h: the list_head