diff --git a/src/util-list.c b/src/util-list.c index 90f5ac0..49b4fe6 100644 --- a/src/util-list.c +++ b/src/util-list.c @@ -190,4 +190,67 @@ MUNIT_TEST(test_list_nth) return MUNIT_OK; } +MUNIT_TEST(list_first_last) +{ + struct list_test { + int val; + struct list node; + } tests[] = { + { .val = 1 }, + { .val = 2 }, + { .val = 3 }, + { .val = 4 }, + }; + struct list_test *t; + struct list head; + + list_init(&head); + ARRAY_FOR_EACH(tests, t) { + list_append(&head, &t->node); + } + + struct list_test *first = list_first_entry(&head, t, node); + munit_assert_int(first->val, ==, 1); + first = list_first_entry_by_type(&head, struct list_test, node); + munit_assert_int(first->val, ==, 1); + + struct list_test *last = list_last_entry(&head, t, node); + munit_assert_int(last->val, ==, 4); + last = list_last_entry_by_type(&head, struct list_test, node); + munit_assert_int(last->val, ==, 4); + + return MUNIT_OK; +} + +MUNIT_TEST(list_foreach) +{ + struct list_test { + int val; + struct list node; + } tests[] = { + { .val = 1 }, + { .val = 2 }, + { .val = 3 }, + { .val = 4 }, + }; + struct list_test *t; + struct list head; + + list_init(&head); + ARRAY_FOR_EACH(tests, t) { + list_append(&head, &t->node); + } + + unsigned int idx = 0; + list_for_each(t, &head, node) { + munit_assert_int(t->val, ==, tests[idx++].val); + } + + list_for_each_backwards(t, &head, node) { + munit_assert_int(t->val, ==, tests[--idx].val); + } + + return MUNIT_OK; +} + #endif diff --git a/src/util-list.h b/src/util-list.h index 283d634..cbc6204 100644 --- a/src/util-list.h +++ b/src/util-list.h @@ -88,6 +88,7 @@ void list_append(struct list *list, struct list *elm); * */ void list_remove(struct list *elm); + /** * Returns true if the given list head is an empty list. */ @@ -139,6 +140,12 @@ bool list_empty(const struct list *list); #define list_first_entry(head, pointer_of_type, member) \ container_of((head)->next, __typeof__(*pointer_of_type), member) +/** + * Return the last entry of the list. See list_first_entry() for details. + */ +#define list_last_entry(head, pointer_of_type, member) \ + container_of((head)->prev, __typeof__(*pointer_of_type), member) + /** * Given a list 'head', return the first entry of type 'container_type' that * has a member 'link'. @@ -159,6 +166,12 @@ bool list_empty(const struct list *list); #define list_first_entry_by_type(head, container_type, member) \ container_of((head)->next, container_type, member) +/** + * Return the last entry of the list. See list_first_entry_by_type() for details. + */ +#define list_last_entry_by_type(head, container_type, member) \ + container_of((head)->prev, container_type, member) + /** * Iterate through the list. * @@ -177,6 +190,14 @@ bool list_empty(const struct list *list); &pos->member != (head); \ pos = list_first_entry_by_type(&pos->member, __typeof__(*pos), member)) +/** + * Iterate through the list backwards. + */ +#define list_for_each_backwards(pos, head, member) \ + for (pos = list_last_entry_by_type(head, __typeof__(*pos), member); \ + &pos->member != (head); \ + pos = list_last_entry_by_type(&pos->member, __typeof__(*pos), member)) + /** * Iterate through the list. Equivalent to list_for_each() but allows * calling list_remove() on the element.