diff --git a/src/basic/list.h b/src/basic/list.h index f7f97000e0..b62c374985 100644 --- a/src/basic/list.h +++ b/src/basic/list.h @@ -169,3 +169,18 @@ #define LIST_IS_EMPTY(head) \ (!(head)) + +/* Join two lists tail to head: a->b, c->d to a->b->c->d and de-initialise second list */ +#define LIST_JOIN(name,a,b) \ + do { \ + assert(b); \ + if (!(a)) \ + (a) = (b); \ + else { \ + typeof(*(a)) *_head = (b), *_tail; \ + LIST_FIND_TAIL(name, (a), _tail); \ + _tail->name##_next = _head; \ + _head->name##_prev = _tail; \ + } \ + (b) = NULL; \ + } while (false) diff --git a/src/test/test-list.c b/src/test/test-list.c index 24e0496d46..ca5361adb9 100644 --- a/src/test/test-list.c +++ b/src/test/test-list.c @@ -12,11 +12,14 @@ int main(int argc, const char *argv[]) { LIST_FIELDS(struct list_item, item); } list_item; LIST_HEAD(list_item, head); + LIST_HEAD(list_item, head2); list_item items[4]; list_item *cursor; LIST_HEAD_INIT(head); + LIST_HEAD_INIT(head2); assert_se(head == NULL); + assert_se(head2 == NULL); for (i = 0; i < ELEMENTSOF(items); i++) { LIST_INIT(item, &items[i]); @@ -203,5 +206,49 @@ int main(int argc, const char *argv[]) { assert_se(head == NULL); + for (i = 0; i < ELEMENTSOF(items) / 2; i++) { + LIST_INIT(item, &items[i]); + assert_se(LIST_JUST_US(item, &items[i])); + LIST_PREPEND(item, head, &items[i]); + } + + for (i = ELEMENTSOF(items) / 2; i < ELEMENTSOF(items); i++) { + LIST_INIT(item, &items[i]); + assert_se(LIST_JUST_US(item, &items[i])); + LIST_PREPEND(item, head2, &items[i]); + } + + assert_se(items[0].item_next == NULL); + assert_se(items[1].item_next == &items[0]); + assert_se(items[2].item_next == NULL); + assert_se(items[3].item_next == &items[2]); + + assert_se(items[0].item_prev == &items[1]); + assert_se(items[1].item_prev == NULL); + assert_se(items[2].item_prev == &items[3]); + assert_se(items[3].item_prev == NULL); + + LIST_JOIN(item, head2, head); + assert_se(head == NULL); + + assert_se(items[0].item_next == NULL); + assert_se(items[1].item_next == &items[0]); + assert_se(items[2].item_next == &items[1]); + assert_se(items[3].item_next == &items[2]); + + assert_se(items[0].item_prev == &items[1]); + assert_se(items[1].item_prev == &items[2]); + assert_se(items[2].item_prev == &items[3]); + assert_se(items[3].item_prev == NULL); + + LIST_JOIN(item, head, head2); + assert_se(head2 == NULL); + assert_se(!LIST_IS_EMPTY(head)); + + for (i = 0; i < ELEMENTSOF(items); i++) + LIST_REMOVE(item, head, &items[i]); + + assert_se(head == NULL); + return 0; }