alist: Add for-loop helpers

Add some macros which permit easy iteration through an alist, similar to
those provided by the 'list' implementation.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2024-10-19 09:21:45 -06:00 committed by Tom Rini
parent 1d49f78c36
commit d785a77d18
3 changed files with 131 additions and 0 deletions

View file

@ -224,6 +224,56 @@ bool alist_expand_by(struct alist *lst, uint inc_by);
*/ */
const void *alist_next_ptrd(const struct alist *lst, const void *ptr); const void *alist_next_ptrd(const struct alist *lst, const void *ptr);
/**
* alist_chk_ptr() - Check whether a pointer is within a list
*
* Checks if the pointer points to an existing element of the list. The pointer
* must point to the start of an element, either in the list, or just outside of
* it. This function is only useful for handling for() loops
*
* Return: true if @ptr is within the list (0..count-1), else false
*/
bool alist_chk_ptr(const struct alist *lst, const void *ptr);
/**
* alist_start() - Get the start of the list (first element)
*
* Note that this will always return ->data even if it is not NULL
*
* Usage:
* const struct my_struct *obj; # 'const' is optional
*
* alist_start(&lst, struct my_struct)
*/
#define alist_start(_lst, _struct) \
((_struct *)(_lst)->data)
/**
* alist_end() - Get the end of the list (just after last element)
*
* Usage:
* const struct my_struct *obj; # 'const' is optional
*
* alist_end(&lst, struct my_struct)
*/
#define alist_end(_lst, _struct) \
((_struct *)(_lst)->data + (_lst)->count)
/**
* alist_for_each() - Iterate over an alist (with constant pointer)
*
* Use as:
* const struct my_struct *obj; # 'const' is optional
*
* alist_for_each(obj, &lst) {
* obj->...
* }
*/
#define alist_for_each(_pos, _lst) \
for (_pos = alist_start(_lst, typeof(*(_pos))); \
_pos < alist_end(_lst, typeof(*(_pos))); \
_pos++)
/** /**
* alist_init() - Set up a new object list * alist_init() - Set up a new object list
* *

View file

@ -118,6 +118,13 @@ int alist_calc_index(const struct alist *lst, const void *ptr)
return index; return index;
} }
bool alist_chk_ptr(const struct alist *lst, const void *ptr)
{
int index = alist_calc_index(lst, ptr);
return index >= 0 && index < lst->count;
}
const void *alist_next_ptrd(const struct alist *lst, const void *ptr) const void *alist_next_ptrd(const struct alist *lst, const void *ptr)
{ {
int index = alist_calc_index(lst, ptr); int index = alist_calc_index(lst, ptr);

View file

@ -292,3 +292,77 @@ static int lib_test_alist_next(struct unit_test_state *uts)
return 0; return 0;
} }
LIB_TEST(lib_test_alist_next, 0); LIB_TEST(lib_test_alist_next, 0);
/* Test alist_for_each() */
static int lib_test_alist_for_each(struct unit_test_state *uts)
{
const struct my_struct *ptr;
struct my_struct data, *ptr2;
struct alist lst;
ulong start;
int sum;
start = ut_check_free();
ut_assert(alist_init_struct(&lst, struct my_struct));
ut_asserteq_ptr(NULL, alist_end(&lst, struct my_struct));
sum = 0;
alist_for_each(ptr, &lst)
sum++;
ut_asserteq(0, sum);
alist_for_each(ptr, &lst)
sum++;
ut_asserteq(0, sum);
/* add three items */
data.val = 1;
data.other_val = 0;
alist_add(&lst, data);
ptr = lst.data;
ut_asserteq_ptr(ptr + 1, alist_end(&lst, struct my_struct));
data.val = 2;
alist_add(&lst, data);
ut_asserteq_ptr(ptr + 2, alist_end(&lst, struct my_struct));
data.val = 3;
alist_add(&lst, data);
ut_asserteq_ptr(ptr + 3, alist_end(&lst, struct my_struct));
/* check alist_chk_ptr() */
ut_asserteq(true, alist_chk_ptr(&lst, ptr + 2));
ut_asserteq(false, alist_chk_ptr(&lst, ptr + 3));
ut_asserteq(false, alist_chk_ptr(&lst, ptr + 4));
ut_asserteq(true, alist_chk_ptr(&lst, ptr));
ut_asserteq(false, alist_chk_ptr(&lst, ptr - 1));
/* sum all items */
sum = 0;
alist_for_each(ptr, &lst)
sum += ptr->val;
ut_asserteq(6, sum);
/* increment all items */
alist_for_each(ptr2, &lst)
ptr2->val += 1;
/* sum all items again */
sum = 0;
alist_for_each(ptr, &lst)
sum += ptr->val;
ut_asserteq(9, sum);
ptr = lst.data;
ut_asserteq_ptr(ptr + 3, alist_end(&lst, struct my_struct));
alist_uninit(&lst);
/* Check for memory leaks */
ut_assertok(ut_check_delta(start));
return 0;
}
LIB_TEST(lib_test_alist_for_each, 0);