[glib/wip/ernestask/g_clear_list: 3/3] list, slist: Add g_clear_{s, }list()



commit 58ba7d78fbd7ecb4c0df2dc7e251627ebbffb9d5
Author: Ernestas Kulik <ekulik redhat com>
Date:   Sat Nov 23 17:41:54 2019 +0100

    list, slist: Add g_clear_{s,}list()
    
    Although not quite as often-occurring, this should help with constructs
    like this:
    
      if (list)
        {
          g_list_free_full (list, foo);
          list = NULL;
        }
    
    Closes https://gitlab.gnome.org/GNOME/glib/issues/1943

 docs/reference/glib/glib-sections.txt |  2 ++
 glib/glist.c                          | 29 ++++++++++++++++++++
 glib/glist.h                          | 21 +++++++++++++++
 glib/gslist.c                         | 29 ++++++++++++++++++++
 glib/gslist.h                         | 21 +++++++++++++++
 glib/tests/utils.c                    | 50 +++++++++++++++++++++++++++++++++++
 6 files changed, 152 insertions(+)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index e9dfa73e9..460feecc0 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -2503,6 +2503,7 @@ g_list_delete_link
 g_list_remove_all
 g_list_free
 g_list_free_full
+g_clear_list
 
 <SUBSECTION>
 g_list_alloc
@@ -2559,6 +2560,7 @@ g_slist_free
 g_slist_free_full
 g_slist_free_1
 g_slist_free1
+g_clear_slist
 
 <SUBSECTION>
 g_slist_length
diff --git a/glib/glist.c b/glib/glist.c
index 39143fa7e..7b64ba1d6 100644
--- a/glib/glist.c
+++ b/glib/glist.c
@@ -1313,3 +1313,32 @@ g_list_sort_with_data (GList            *list,
 {
   return g_list_sort_real (list, (GFunc) compare_func, user_data);
 }
+
+/**
+ * g_clear_list: (skip)
+ * @list_ptr: (not nullable): a #GList return location
+ * @destroy: (nullable): the function to pass to g_list_free_full() or %NULL to not free elements
+ *
+ * Clears a pointer to a #GList, freeing it and, optionally, freeing its elements using @destroy.
+ *
+ * @list_ptr must be a valid pointer. If @list_ptr points to a null #GList, this does nothing.
+ *
+ * Since: 2.64
+ */
+void
+(g_clear_list) (GList          **list_ptr,
+                GDestroyNotify   destroy)
+{
+  GList *list;
+
+  list = *list_ptr;
+  if (list)
+    {
+      *list_ptr = NULL;
+
+      if (destroy)
+        g_list_free_full (list, destroy);
+      else
+        g_list_free (list);
+    }
+}
diff --git a/glib/glist.h b/glib/glist.h
index 8b4703e17..ddea3cf35 100644
--- a/glib/glist.h
+++ b/glib/glist.h
@@ -147,6 +147,27 @@ GLIB_AVAILABLE_IN_ALL
 gpointer g_list_nth_data                (GList            *list,
                                         guint             n);
 
+GLIB_AVAILABLE_IN_2_64
+void     g_clear_list                   (GList           **list_ptr,
+                                         GDestroyNotify    destroy);
+
+#define  g_clear_list(list_ptr, destroy)       \
+  G_STMT_START {                               \
+    GList *_list;                              \
+                                               \
+    _list = *(list_ptr);                       \
+    if (_list)                                 \
+      {                                        \
+        *list_ptr = NULL;                      \
+                                               \
+        if ((destroy) != NULL)                 \
+          g_list_free_full (_list, (destroy)); \
+        else                                   \
+          g_list_free (_list);                 \
+      }                                        \
+  } G_STMT_END                                 \
+  GLIB_AVAILABLE_MACRO_IN_2_64
+
 
 #define g_list_previous(list)          ((list) ? (((GList *)(list))->prev) : NULL)
 #define g_list_next(list)              ((list) ? (((GList *)(list))->next) : NULL)
diff --git a/glib/gslist.c b/glib/gslist.c
index 8f616cb47..ef711f634 100644
--- a/glib/gslist.c
+++ b/glib/gslist.c
@@ -1065,3 +1065,32 @@ g_slist_sort_with_data (GSList           *list,
 {
   return g_slist_sort_real (list, (GFunc) compare_func, user_data);
 }
+
+/**
+ * g_clear_slist: (skip)
+ * @slist_ptr: (not nullable): a #GSList return location
+ * @destroy: (nullable): the function to pass to g_slist_free_full() or %NULL to not free elements
+ *
+ * Clears a pointer to a #GSList, freeing it and, optionally, freeing its elements using @destroy.
+ *
+ * @slist_ptr must be a valid pointer. If @slist_ptr points to a null #GSList, this does nothing.
+ *
+ * Since: 2.64
+ */
+void
+(g_clear_slist) (GSList         **slist_ptr,
+                 GDestroyNotify   destroy)
+{
+  GSList *slist;
+
+  slist = *slist_ptr;
+  if (slist)
+    {
+      *slist_ptr = NULL;
+
+      if (destroy)
+        g_slist_free_full (slist, destroy);
+      else
+        g_slist_free (slist);
+    }
+}
diff --git a/glib/gslist.h b/glib/gslist.h
index 2704ef7d3..249417986 100644
--- a/glib/gslist.h
+++ b/glib/gslist.h
@@ -136,6 +136,27 @@ GLIB_AVAILABLE_IN_ALL
 gpointer g_slist_nth_data                (GSList           *list,
                                          guint             n);
 
+GLIB_AVAILABLE_IN_2_64
+void     g_clear_slist                   (GSList          **slist_ptr,
+                                          GDestroyNotify    destroy);
+
+#define  g_clear_slist(slist_ptr, destroy)       \
+  G_STMT_START {                                 \
+    GSList *_slist;                              \
+                                                 \
+    _slist = *(slist_ptr);                       \
+    if (_slist)                                  \
+      {                                          \
+        *slist_ptr = NULL;                       \
+                                                 \
+        if ((destroy) != NULL)                   \
+          g_slist_free_full (_slist, (destroy)); \
+        else                                     \
+          g_slist_free (_slist);                 \
+      }                                          \
+  } G_STMT_END                                   \
+  GLIB_AVAILABLE_MACRO_IN_2_64
+
 #define  g_slist_next(slist)            ((slist) ? (((GSList *)(slist))->next) : NULL)
 
 G_END_DECLS
diff --git a/glib/tests/utils.c b/glib/tests/utils.c
index cf8a5cbc3..ed1d63d57 100644
--- a/glib/tests/utils.c
+++ b/glib/tests/utils.c
@@ -760,6 +760,54 @@ test_int_limits (void)
   g_free (str);
 }
 
+static void
+test_clear_list (void)
+{
+    GList *list = NULL;
+
+    g_clear_list (&list, NULL);
+    g_assert_null (list);
+
+    list = g_list_prepend (list, "test");
+    g_assert_nonnull (list);
+
+    g_clear_list (&list, NULL);
+    g_assert_null (list);
+
+    g_clear_list (&list, g_free);
+    g_assert_null (list);
+
+    list = g_list_prepend (list, g_malloc (16));
+    g_assert_nonnull (list);
+
+    g_clear_list (&list, g_free);
+    g_assert_null (list);
+}
+
+static void
+test_clear_slist (void)
+{
+    GSList *slist = NULL;
+
+    g_clear_slist (&slist, NULL);
+    g_assert_null (slist);
+
+    slist = g_slist_prepend (slist, "test");
+    g_assert_nonnull (slist);
+
+    g_clear_slist (&slist, NULL);
+    g_assert_null (slist);
+
+    g_clear_slist (&slist, g_free);
+    g_assert_null (slist);
+
+    slist = g_slist_prepend (slist, g_malloc (16));
+    g_assert_nonnull (slist);
+
+    g_clear_slist (&slist, g_free);
+    g_assert_null (slist);
+}
+
 int
 main (int   argc,
       char *argv[])
@@ -814,6 +862,8 @@ main (int   argc,
   g_test_add_func ("/utils/atexit", test_atexit);
   g_test_add_func ("/utils/check-setuid", test_check_setuid);
   g_test_add_func ("/utils/int-limits", test_int_limits);
+  g_test_add_func ("/utils/clear-list", test_clear_list);
+  g_test_add_func ("/utils/clear-slist", test_clear_slist);
 
   return g_test_run ();
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]