X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Flist%2Flist.h;h=ab3240871773d90ceee149c3cb30931e228326fb;hb=8216fa0be7d9bf39774a192d52fef955f6bd7cd8;hp=faad86f5c736a3a53ed08c79e74f92c39086a810;hpb=f98c408ee4e2f655e009e2499a02aeb2cc2fa905;p=ccan diff --git a/ccan/list/list.h b/ccan/list/list.h index faad86f5..ab324087 100644 --- a/ccan/list/list.h +++ b/ccan/list/list.h @@ -292,6 +292,34 @@ static inline const void *list_top_(const struct list_head *h, size_t off) return (const char *)h->n.next - off; } +/** + * list_pop - remove the first 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 *one; + * one = list_pop(&parent->children, struct child, list); + * if (!one) + * printf("Empty list!\n"); + */ +#define list_pop(h, type, member) \ + ((type *)list_pop_((h), list_off_(type, member))) + +static inline const void *list_pop_(const struct list_head *h, size_t off) +{ + struct list_node *n; + + if (list_empty(h)) + return NULL; + n = h->n.next; + list_del(n); + return (const char *)n - off; +} + /** * list_tail - get the last entry in a list * @h: the list_head @@ -371,6 +399,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