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.
This commit is contained in:
Lennart Poettering 2020-04-14 18:52:24 +02:00
parent 428d32afea
commit 1146b664e6
2 changed files with 86 additions and 0 deletions

View file

@ -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

View file

@ -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;
}