libsystem: glib-utils: extend glist iterate macro function
authorWaLyong Cho <walyong.cho@samsung.com>
Wed, 14 Dec 2016 06:17:57 +0000 (15:17 +0900)
committerWaLyong Cho <walyong.cho@samsung.com>
Wed, 14 Dec 2016 11:09:07 +0000 (20:09 +0900)
Some of additional glist iterate macro functions are added:
- FOREACH_G_LIST_DATA()
- FOREACH_G_LIST_REVERSE()
- FOREACH_G_LIST_SAFE()
- FOREACH_G_LIST_SAFE_REVERSE()

Change-Id: Ie37b40aded588a4c8e725f86b2185c12c3a2e868
Signed-off-by: WaLyong Cho <walyong.cho@samsung.com>
src/Makefile.am
src/libsystem/glib-util.h
src/test/test-foreach-glist.c [new file with mode: 0644]

index f6cbb81..0b63ea5 100644 (file)
@@ -122,6 +122,19 @@ test_read_write_LDADD = \
 tests += test-read-write
 
 # ------------------------------------------------------------------------------
+test_foreach_glist_SOURCES = \
+       test/test-foreach-glist.c
+
+test_foreach_glist_CFLAGS = \
+       $(GIO_CFLAGS)
+
+test_foreach_glist_LDADD = \
+       $(GIO_LIBS) \
+       libsystem.la
+
+tests += test-foreach-glist
+
+# ------------------------------------------------------------------------------
 pkgconfiglib_DATA += \
        libsystem-sd/libsystem-sd.pc
 
index 7d3c7ad..560acc4 100644 (file)
@@ -30,9 +30,6 @@
 #pragma once
 
 #include <glib.h>
-#include <gio/gio.h>
-
-#include "libsystem.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -41,11 +38,47 @@ extern "C" {
 /**
  * @brief Iterate for each list nodes.
  *
- * @param n each list nodes
+ * @param c current node
+ * @param l list to iterate
+ */
+#define FOREACH_G_LIST(c, l)                                    \
+        for (c = g_list_first(l); c; c = g_list_next(c))
+
+/**
+ * @brief Reverse iterate for each list nodes.
+ *
+ * @param c current node
+ * @param l list to iterate
+ */
+#define FOREACH_G_LIST_REVERSE(c, l)                            \
+        for (c = g_list_last(l); c; c = g_list_previous(c))
+
+/**
+ * @brief Iterate for each list nodes. #FOREACH_G_LIST_SAFE is similar
+ * with #FOREACH_G_LIST but safe for list remove. When you are
+ * iterating a list to remove some of list nodes, you have to use
+ * #FOREACH_G_LIST_SAFE for safe iteration.
+ *
+ * @param c current node
+ * @param n next node of current iteration, this is used for safe iteration
+ * @param l list to iterate
+ */
+#define FOREACH_G_LIST_SAFE(c, n, l)                                    \
+        for (c = g_list_first(l), n = g_list_next(c); c; c = n, n = g_list_next(c))
+
+/**
+ * @brief Reverse iterate for each list
+ * nodes. #FOREACH_G_LIST_SAFE_REVERSE is similar with
+ * #FOREACH_G_LIST_REVERSE but safe for list remove. When you are
+ * iterating a list to remove some of list nodes, you have to use
+ * #FOREACH_G_LIST_SAFE_REVERSE for safe iteration.
+ *
+ * @param c current node
+ * @param p previous node of current iteration, this is used for safe iteration
  * @param l list to iterate
  */
-#define FOREACH_G_LIST(n, l)                                    \
-        for (n = g_list_first(l); n; n = g_list_next(n))
+#define FOREACH_G_LIST_SAFE_REVERSE(c, p, l)                            \
+        for (c = g_list_last(l), p = g_list_previous(c); c; c = p, p = g_list_previous(c))
 
 /**
  * @brief Convert GError to errno.
diff --git a/src/test/test-foreach-glist.c b/src/test/test-foreach-glist.c
new file mode 100644 (file)
index 0000000..ba952e0
--- /dev/null
@@ -0,0 +1,138 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * libsystem
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <limits.h>
+#include <glib.h>
+
+#include "libsystem/libsystem.h"
+#include "libsystem/glib-util.h"
+
+static void gen_test_list(GList **list) {
+        GList *l = NULL;
+        int i;
+
+        assert(list);
+        assert(!*list);
+
+        for (i = 1; i <= 10; i++)
+                l = g_list_append(l, GINT_TO_POINTER(i));
+
+        *list = l;
+}
+
+static void test_foreach_g_list(void) {
+        GList *list = NULL, *node;
+        char buf[LINE_MAX];
+        int n = 0;
+
+        gen_test_list(&list);
+
+        FOREACH_G_LIST(node, list) {
+                int i = GPOINTER_TO_INT(node->data);
+
+                n += snprintf(buf + n, LINE_MAX - n - 1, "%d ", i);
+        }
+
+        assert(streq(buf, "1 2 3 4 5 6 7 8 9 10 "));
+
+        g_list_free(list);
+}
+
+static void test_foreach_g_list_reverse(void) {
+        GList *list = NULL, *node;
+        char buf[LINE_MAX];
+        int n = 0;
+
+        gen_test_list(&list);
+
+        FOREACH_G_LIST_REVERSE(node, list) {
+                int i = GPOINTER_TO_INT(node->data);
+
+                n += snprintf(buf + n, LINE_MAX - n - 1, "%d ", i);
+        }
+
+        assert(streq(buf, "10 9 8 7 6 5 4 3 2 1 "));
+
+        g_list_free(list);
+}
+
+static void test_foreach_g_list_safe(void) {
+        GList *list = NULL, *node, *next;
+        char buf[LINE_MAX];
+        int n = 0;
+
+        gen_test_list(&list);
+
+        FOREACH_G_LIST_SAFE(node, next, list) {
+                int i = GPOINTER_TO_INT(node->data);
+
+                if (i % 2)
+                        list = g_list_remove_link(list, node);
+        }
+
+        FOREACH_G_LIST(node, list) {
+                int i = GPOINTER_TO_INT(node->data);
+
+                n += snprintf(buf + n, LINE_MAX - n - 1, "%d ", i);
+        }
+
+        assert(streq(buf, "2 4 6 8 10 "));
+
+        g_list_free(list);
+}
+
+static void test_foreach_g_list_safe_reverse(void) {
+        GList *list = NULL, *node, *prev;
+        char buf[LINE_MAX];
+        int n = 0;
+
+        gen_test_list(&list);
+
+        FOREACH_G_LIST_SAFE_REVERSE(node, prev, list) {
+                int i = GPOINTER_TO_INT(node->data);
+
+                if (i % 2)
+                        list = g_list_remove_link(list, node);
+        }
+
+        FOREACH_G_LIST_REVERSE(node, list) {
+                int i = GPOINTER_TO_INT(node->data);
+
+                n += snprintf(buf + n, LINE_MAX - n - 1, "%d ", i);
+        }
+
+        assert(streq(buf, "10 8 6 4 2 "));
+
+        g_list_free(list);
+}
+
+int main(int argc, char *argv[]) {
+
+        test_foreach_g_list();
+        test_foreach_g_list_reverse();
+
+        test_foreach_g_list_safe();
+        test_foreach_g_list_safe_reverse();
+
+        return 0;
+}