[PATCH 05/34] alist: Add for-loop helpers

Simon Glass sjg at chromium.org
Fri Oct 18 01:23:44 CEST 2024


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

Signed-off-by: Simon Glass <sjg at chromium.org>
---

 include/alist.h  | 50 ++++++++++++++++++++++++++++++++
 lib/alist.c      |  7 +++++
 test/lib/alist.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 131 insertions(+)

diff --git a/include/alist.h b/include/alist.h
index 97523af37a6..0090b9c0eb1 100644
--- a/include/alist.h
+++ b/include/alist.h
@@ -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);
 
+/**
+ * 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
  *
diff --git a/lib/alist.c b/lib/alist.c
index 7730fe0d473..1a4b4fb9c40 100644
--- a/lib/alist.c
+++ b/lib/alist.c
@@ -118,6 +118,13 @@ int alist_calc_index(const struct alist *lst, const void *ptr)
 	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)
 {
 	int index = alist_calc_index(lst, ptr);
diff --git a/test/lib/alist.c b/test/lib/alist.c
index 96092affec9..1715a22584c 100644
--- a/test/lib/alist.c
+++ b/test/lib/alist.c
@@ -292,3 +292,77 @@ static int lib_test_alist_next(struct unit_test_state *uts)
 	return 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);
-- 
2.34.1



More information about the U-Boot mailing list