From: Lennart Poettering Date: Tue, 14 Apr 2020 16:52:24 +0000 (+0200) Subject: macro: add new FOREACH_POINTER() macro magic X-Git-Tag: v246-rc1~45^2~18 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1146b664e60cc16f9c3ab828029956739ae9552d;p=thirdparty%2Fsystemd.git macro: add new FOREACH_POINTER() macro magic This allows us to iterate through a series of specified pointers. It's a bit like FOREACH_STRING(), but for all kinds of pointers. --- diff --git a/src/basic/macro.h b/src/basic/macro.h index fd8772f377f..ceea8176f5b 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -538,6 +538,12 @@ static inline int __coverity_check_and_return__(int condition) { (y) = (_t); \ } while (false) +/* Iterates through a specified list of pointers. Accepts NULL pointers, but uses (void*) -1 as internal marker for EOL. */ +#define FOREACH_POINTER(p, x, ...) \ + for (typeof(p) *_l = (typeof(p)[]) { ({ p = x; }), ##__VA_ARGS__, (void*) -1 }; \ + p != (typeof(p)) (void*) -1; \ + p = *(++_l)) + /* Define C11 thread_local attribute even on older gcc compiler * version */ #ifndef thread_local diff --git a/src/test/test-util.c b/src/test/test-util.c index 76dd72a5980..d4a6c8f5c33 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -410,6 +410,85 @@ static void test_system_tasks_max_scale(void) { assert_se(system_tasks_max_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX); } +static void test_foreach_pointer(void) { + int a, b, c, *i; + size_t k = 0; + + FOREACH_POINTER(i, &a, &b, &c) { + switch (k) { + + case 0: + assert_se(i == &a); + break; + + case 1: + assert_se(i == &b); + break; + + case 2: + assert_se(i == &c); + break; + + default: + assert_not_reached("unexpected index"); + break; + } + + k++; + } + + assert(k == 3); + + FOREACH_POINTER(i, &b) { + assert(k == 3); + assert(i == &b); + k = 4; + } + + assert(k == 4); + + FOREACH_POINTER(i, NULL, &c, NULL, &b, NULL, &a, NULL) { + switch (k) { + + case 4: + assert_se(i == NULL); + break; + + case 5: + assert_se(i == &c); + break; + + case 6: + assert_se(i == NULL); + break; + + case 7: + assert_se(i == &b); + break; + + case 8: + assert_se(i == NULL); + break; + + case 9: + assert_se(i == &a); + break; + + case 10: + assert_se(i == NULL); + break; + + default: + assert_not_reached("unexpected index"); + break; + } + + k++; + } + + assert(k == 11); +} + int main(int argc, char *argv[]) { test_setup_logging(LOG_INFO); @@ -428,6 +507,7 @@ int main(int argc, char *argv[]) { test_physical_memory_scale(); test_system_tasks_max(); test_system_tasks_max_scale(); + test_foreach_pointer(); return 0; }