From: James Jones Date: Thu, 7 Oct 2021 01:39:58 +0000 (-0500) Subject: Add fr_{lst, heap}_foreach() and tests thereof. (#4237) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eca78cf7dd6f627e6c6375e1b791da93c9abe4f2;p=thirdparty%2Ffreeradius-server.git Add fr_{lst, heap}_foreach() and tests thereof. (#4237) 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. --- diff --git a/src/lib/util/heap.h b/src/lib/util/heap.h index 7d36113f70..6ae651ccc7 100644 --- a/src/lib/util/heap.h +++ b/src/lib/util/heap.h @@ -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 diff --git a/src/lib/util/heap_tests.c b/src/lib/util/heap_tests.c index dec118bdcd..06d6d6db16 100644 --- a/src/lib/util/heap_tests.c +++ b/src/lib/util/heap_tests.c @@ -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 } }; diff --git a/src/lib/util/lst.h b/src/lib/util/lst.h index 465bf838c7..1ce5f8de39 100644 --- a/src/lib/util/lst.h +++ b/src/lib/util/lst.h @@ -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 diff --git a/src/lib/util/lst_tests.c b/src/lib/util/lst_tests.c index aa2eff8db8..3cc0e58ab8 100644 --- a/src/lib/util/lst_tests.c +++ b/src/lib/util/lst_tests.c @@ -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); }