]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add fr_{lst, heap}_foreach() and tests thereof. (#4237)
authorJames Jones <jejones3141@gmail.com>
Thu, 7 Oct 2021 01:39:58 +0000 (20:39 -0500)
committerGitHub <noreply@github.com>
Thu, 7 Oct 2021 01:39:58 +0000 (20:39 -0500)
Note that because we have to declare an fr_{lst, heap}_iter as well
as a variable of type pointer to the element type of the {lst, heap},
we must take the approach of fr_dlist_foreach_safe(). Correct uses
will thus look like they have unbalanced braces.

src/lib/util/heap.h
src/lib/util/heap_tests.c
src/lib/util/lst.h
src/lib/util/lst_tests.c

index 7d36113f70422ad847fe281ccaa138e423c32a7f..6ae651ccc7bb91bf6bab4f3ed73dc6aa5dc28fa2 100644 (file)
@@ -103,6 +103,26 @@ uint32_t   fr_heap_num_elements(fr_heap_t *hp) CC_HINT(nonnull);
 void           *fr_heap_iter_init(fr_heap_t *hp, fr_heap_iter_t *iter) CC_HINT(nonnull);
 void           *fr_heap_iter_next(fr_heap_t *hp, fr_heap_iter_t *iter) CC_HINT(nonnull);
 
+/** Iterate over the contents of a heap
+ *
+ * @note The initializer section of a for loop can't declare variables with distinct
+ *      base types, so we require a containing block, and can't follow the standard
+ *      do {...} while(0) dodge. The code to be run for each item in the heap should
+ *      thus start with one open brace and end with two close braces, and shouldn't
+ *      be followed with a semicolon.
+ *      This may fake out code formatting programs and code-aware editors.
+ *
+ * @param[in] _heap            to iterate over.
+ * @param[in] _type            of item the heap contains.
+ * @param[in] _data            Name of variable holding a pointer to the heap element.
+ *                             Will be declared in the scope of the loop.
+ */
+#define fr_heap_foreach(_heap, _type, _data) \
+{ \
+       fr_heap_iter_t _iter; \
+       for (_type *_data = fr_heap_iter_init(_heap, &_iter); _data; _data = fr_heap_iter_next(_heap, &_iter))
+
+
 #ifdef __cplusplus
 }
 #endif
index dec118bdcd7f9a498fa32236964bb166f659334b..06d6d6db16239959213d3e8220cd8de47de28872 100644 (file)
@@ -189,6 +189,35 @@ static void heap_test_order(void)
        free(array);
 }
 
+#define        HEAP_ITER_SIZE  20
+
+static void heap_iter(void)
+{
+       fr_heap_t       *hp;
+       heap_thing      *array;
+       unsigned int    data_set;
+
+       hp = fr_heap_alloc(NULL, heap_cmp, heap_thing, heap, 0);
+       TEST_CHECK(hp != NULL);
+
+       array = calloc(HEAP_ITER_SIZE, sizeof(heap_thing));
+
+       for (size_t i = 0; i < HEAP_ITER_SIZE; i++) {
+               array[i].data = i;
+               TEST_CHECK(fr_heap_insert(hp, &array[i])  >= 0);
+       }
+
+       data_set = 0;
+       fr_heap_foreach(hp, heap_thing, item) {
+               TEST_CHECK((data_set & (1U << item->data)) == 0);
+               data_set |= (1U << item->data);
+       }}
+       TEST_CHECK(data_set == ((1U << HEAP_ITER_SIZE) - 1U));
+
+       talloc_free(hp);
+       free(array);
+}
+
 static void heap_cycle(void)
 {
        fr_heap_t       *hp;
@@ -287,6 +316,7 @@ TEST_LIST = {
        { "heap_test_skip_2",           heap_test_skip_2        },
        { "heap_test_skip_10",          heap_test_skip_10       },
        { "heap_test_order",            heap_test_order         },
+       { "heap_iter",                  heap_iter               },
        { "heap_cycle",                 heap_cycle              },
        { NULL }
 };
index 465bf838c79d101db888d718e3b7a613dab2cd3c..1ce5f8de3944c407225d0c22b20f3823e8f4dc5b 100644 (file)
@@ -114,6 +114,26 @@ void               *fr_lst_iter_init(fr_lst_t *lst, fr_lst_iter_t *iter) CC_HINT(nonnull);
 
 void           *fr_lst_iter_next(fr_lst_t *lst, fr_lst_iter_t *iter) CC_HINT(nonnull);
 
+/** Iterate over the contents of an LST
+ *
+ * @note The initializer section of a for loop can't declare variables with distinct
+ *      base types, so we require a containing block, and can't follow the standard
+ *      do {...} while(0) dodge. The code to be run for each item in the LST should
+ *      thus start with one open brace and end with two close braces, and shouldn't
+ *      be followed with a semicolon.
+ *      This may fake out code formatting programs and code-aware editors.
+ *
+ * @param[in] _lst             to iterate over.
+ * @param[in] _type            of item the heap contains.
+ * @param[in] _data            Name of variable holding a pointer to the LST element.
+ *                             Will be declared in the scope of the loop.
+ */
+#define fr_lst_foreach(_lst, _type, _data) \
+{ \
+       fr_lst_iter_t _iter; \
+       for (_type *_data = fr_lst_iter_init(_lst, &_iter); _data; _data = fr_lst_iter_next(_lst, &_iter))
+
+
 #ifdef __cplusplus
 }
 #endif
index aa2eff8db86ad654d9a4558929cbb456a8df1bab..3cc0e58ab8f4d6ce304e0d338d9f233f952687c3 100644 (file)
@@ -388,7 +388,7 @@ static void lst_iter(void)
        fr_lst_t        *lst;
        fr_lst_iter_t   iter;
        lst_thing       values[NVALUES], *data;
-
+       unsigned int    total;
 
        lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 0);
        TEST_CHECK(lst != NULL);
@@ -407,6 +407,13 @@ static void lst_iter(void)
        }
 
        TEST_CHECK(data == NULL);
+
+       total = 0;
+       fr_lst_foreach(lst, lst_thing, item) {
+               total += item->data;
+       }}
+       TEST_CHECK(total = 190);
+
        talloc_free(lst);
 }