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

Signed-off-by: Simon Glass <s...@chromium.org>
---

(no changes since v1)

 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

Reply via email to