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 <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer 2021-07-22 09:14:12 +10:00
parent 036f9fe7ee
commit 974df9b5ce
2 changed files with 56 additions and 0 deletions

View file

@ -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

View file

@ -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_; \
})