]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
macro: add new FOREACH_POINTER() macro magic
authorLennart Poettering <lennart@poettering.net>
Tue, 14 Apr 2020 16:52:24 +0000 (18:52 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 1 Jul 2020 09:17:28 +0000 (11:17 +0200)
This allows us to iterate through a series of specified pointers. It's a
bit like FOREACH_STRING(), but for all kinds of pointers.

src/basic/macro.h
src/test/test-util.c

index fd8772f377f04e36de3e612a274017f1d0f303e8..ceea8176f5b85321e7966b4e747c386f8ed79980 100644 (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
index 76dd72a59807a81abb2ec309a234b3991cadbcf5..d4a6c8f5c339029c3349c3dce31213307668dd9c 100644 (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;
 }