From 974df9b5ce2925be67f1678e14eb287007afdbb5 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 22 Jul 2021 09:14:12 +1000 Subject: [PATCH] util: add a list_nth_entry() macro Returns the nth element for a given list. Note that unlike the other macros, this takes a type, not a variable as first argument. Signed-off-by:Peter Hutterer --- src/util-list.c | 35 +++++++++++++++++++++++++++++++++++ src/util-list.h | 21 +++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/util-list.c b/src/util-list.c index 1d01373..9a79e3b 100644 --- a/src/util-list.c +++ b/src/util-list.c @@ -154,4 +154,39 @@ MUNIT_TEST(test_list_append) return MUNIT_OK; } +MUNIT_TEST(test_list_nth) +{ + 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); + } + + int idx = 0; + ARRAY_FOR_EACH(tests, t) { + struct list_test *nth = list_nth_entry(struct list_test, + &head, node, idx); + munit_assert_int(nth->val, ==, tests[idx].val); + idx++; + } + + munit_assert(list_nth_entry(struct list_test, &head, node, 10) == NULL); + list_init(&head); + munit_assert(list_nth_entry(struct list_test, &head, node, 0) == NULL); + munit_assert(list_nth_entry(struct list_test, &head, node, 1) == NULL); + + return MUNIT_OK; +} + #endif diff --git a/src/util-list.h b/src/util-list.h index c943ce5..cbfa814 100644 --- a/src/util-list.h +++ b/src/util-list.h @@ -195,3 +195,24 @@ bool list_empty(const struct list *list); &pos->member != (head); \ pos = tmp, \ tmp = list_first_entry(&pos->member, tmp, member)) + +/** + * Return the nth element of the list, starting at 0. This is the equivalent + * to `listname[index]` if the list was an array. If the index is outside the + * list size, NULL is returned. + * + * @code + * struct foo *f = get_a_foo(); + * struct bar *element = list_nth_entry(struct bar, &f->list_of_bars, link, 2); + * @endcode + */ + +#define list_nth_entry(type, head, member, index) \ + ({ type *nth_ = NULL, *pos_; \ + __typeof__(index) idx_ = 0; \ + list_for_each(pos_, head, member) { \ + if (idx_ == index) { nth_ = pos_; break; } \ + idx_++; \ + } \ + nth_; \ + })