#pragma once
#include <glib.h>
-#include <gio/gio.h>
-
-#include "libsystem.h"
#ifdef __cplusplus
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.
--- /dev/null
+/*-*- 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;
+}