[glib] Adds g_list_copy_deep and g_slist_copy_deep



commit 2fd6eb7e1cfc878d011ec0b7e58c5e696186516e
Author: Jonh Wendell <jwendell gnome org>
Date:   Thu Jun 21 12:23:23 2012 -0300

    Adds g_list_copy_deep and g_slist_copy_deep
    
    They make a full (deep) copy of a list.
    
    In contrast with g_[s]list_copy(), these functions take a function as a argument
    to make a copy of each list element, in addition to copying the list container itself.
    
    The functions g_[s]list_copy() were reimplemented to just call the new functions
    with NULL as the function argument, which will behave like current implementation.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=675024

 docs/reference/glib/glib-sections.txt |    2 +
 glib/glib.symbols                     |    2 +
 glib/glist.c                          |   48 ++++++++++++++++++++++++++++++--
 glib/glist.h                          |    7 +++++
 glib/gslist.c                         |   48 ++++++++++++++++++++++++++++++--
 glib/gslist.h                         |    6 ++++
 glib/tests/list.c                     |   29 ++++++++++++++++++++
 7 files changed, 136 insertions(+), 6 deletions(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 141c7bb..6e2ad35 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -2051,6 +2051,7 @@ g_list_free1
 <SUBSECTION>
 g_list_length
 g_list_copy
+g_list_copy_deep
 g_list_reverse
 g_list_sort
 GCompareFunc
@@ -2101,6 +2102,7 @@ g_slist_free1
 <SUBSECTION>
 g_slist_length
 g_slist_copy
+g_slist_copy_deep
 g_slist_reverse
 g_slist_insert_sorted_with_data
 g_slist_sort
diff --git a/glib/glib.symbols b/glib/glib.symbols
index fdafb3e..5ffbcb9 100644
--- a/glib/glib.symbols
+++ b/glib/glib.symbols
@@ -551,6 +551,7 @@ g_list_alloc
 g_list_append
 g_list_concat
 g_list_copy
+g_list_copy_deep
 g_list_delete_link
 g_list_find
 g_list_find_custom
@@ -942,6 +943,7 @@ g_slist_alloc
 g_slist_append
 g_slist_concat
 g_slist_copy
+g_slist_copy_deep
 g_slist_delete_link
 g_slist_find
 g_slist_find_custom
diff --git a/glib/glist.c b/glib/glist.c
index dac7dc8..1c4f9e4 100644
--- a/glib/glist.c
+++ b/glib/glist.c
@@ -566,7 +566,8 @@ g_list_delete_link (GList *list,
  * <note><para>
  * Note that this is a "shallow" copy. If the list elements 
  * consist of pointers to data, the pointers are copied but 
- * the actual data is not.
+ * the actual data is not. See g_list_copy_deep() if you need
+ * to copy the data as well.
  * </para></note>
  *
  * Returns: a copy of @list
@@ -574,6 +575,41 @@ g_list_delete_link (GList *list,
 GList*
 g_list_copy (GList *list)
 {
+  return g_list_copy_deep (list, NULL, NULL);
+}
+
+/**
+ * g_list_copy_deep:
+ * @list: a #GList
+ * @func: a copy function used to copy every element in the list
+ * @user_data: user data passed to the copy function @func, or #NULL
+ *
+ * Makes a full (deep) copy of a #GList.
+ *
+ * In contrast with g_list_copy(), this function uses @func to make a copy of
+ * each list element, in addition to copying the list container itself.
+ *
+ * @func, as a #GCopyFunc, takes two arguments, the data to be copied and a user
+ * pointer. It's safe to pass #NULL as user_data, if the copy function takes only
+ * one argument.
+ *
+ * For instance, if @list holds a list of GObjects, you can do:
+ * |[
+ * another_list = g_list_copy_deep (list, (GCopyFunc) g_object_ref, NULL);
+ * ]|
+ *
+ * And, to entirely free the new list, you could do:
+ * |[
+ * g_list_free_full (another_list, g_object_unref);
+ * ]|
+ *
+ * Returns: a full copy of @list, use #g_list_free_full to free it
+ *
+ * Since: 2.34
+ */
+GList*
+g_list_copy_deep (GList *list, GCopyFunc func, gpointer user_data)
+{
   GList *new_list = NULL;
 
   if (list)
@@ -581,7 +617,10 @@ g_list_copy (GList *list)
       GList *last;
 
       new_list = _g_list_alloc ();
-      new_list->data = list->data;
+      if (func)
+        new_list->data = func (list->data, user_data);
+      else
+        new_list->data = list->data;
       new_list->prev = NULL;
       last = new_list;
       list = list->next;
@@ -590,7 +629,10 @@ g_list_copy (GList *list)
 	  last->next = _g_list_alloc ();
 	  last->next->prev = last;
 	  last = last->next;
-	  last->data = list->data;
+	  if (func)
+	    last->data = func (list->data, user_data);
+	  else
+	    last->data = list->data;
 	  list = list->next;
 	}
       last->next = NULL;
diff --git a/glib/glist.h b/glib/glist.h
index aaa11f2..44cfcc0 100644
--- a/glib/glist.h
+++ b/glib/glist.h
@@ -32,6 +32,7 @@
 #define __G_LIST_H__
 
 #include <glib/gmem.h>
+#include <glib/gnode.h>
 
 G_BEGIN_DECLS
 
@@ -81,6 +82,12 @@ GList*   g_list_delete_link             (GList            *list,
 					 GList            *link_) G_GNUC_WARN_UNUSED_RESULT;
 GList*   g_list_reverse                 (GList            *list) G_GNUC_WARN_UNUSED_RESULT;
 GList*   g_list_copy                    (GList            *list) G_GNUC_WARN_UNUSED_RESULT;
+
+GLIB_AVAILABLE_IN_2_34
+GList*   g_list_copy_deep               (GList            *list,
+					 GCopyFunc         func,
+					 gpointer          user_data) G_GNUC_WARN_UNUSED_RESULT;
+
 GList*   g_list_nth                     (GList            *list,
 					 guint             n);
 GList*   g_list_nth_prev                (GList            *list,
diff --git a/glib/gslist.c b/glib/gslist.c
index 89e0f2d..8d32d05 100644
--- a/glib/gslist.c
+++ b/glib/gslist.c
@@ -554,7 +554,8 @@ g_slist_delete_link (GSList *list,
  * <note><para>
  * Note that this is a "shallow" copy. If the list elements
  * consist of pointers to data, the pointers are copied but
- * the actual data isn't.
+ * the actual data isn't. See g_slist_copy_deep() if you need
+ * to copy the data as well.
  * </para></note>
  *
  * Returns: a copy of @list
@@ -562,6 +563,41 @@ g_slist_delete_link (GSList *list,
 GSList*
 g_slist_copy (GSList *list)
 {
+  return g_slist_copy_deep (list, NULL, NULL);
+}
+
+/**
+ * g_slist_copy_deep:
+ * @list: a #GSList
+ * @func: a copy function used to copy every element in the list
+ * @user_data: user data passed to the copy function @func, or #NULL
+ *
+ * Makes a full (deep) copy of a #GSList.
+ *
+ * In contrast with g_slist_copy(), this function uses @func to make a copy of
+ * each list element, in addition to copying the list container itself.
+ *
+ * @func, as a #GCopyFunc, takes two arguments, the data to be copied and a user
+ * pointer. It's safe to pass #NULL as user_data, if the copy function takes only
+ * one argument.
+ *
+ * For instance, if @list holds a list of GObjects, you can do:
+ * |[
+ * another_list = g_slist_copy_deep (list, (GCopyFunc) g_object_ref, NULL);
+ * ]|
+ *
+ * And, to entirely free the new list, you could do:
+ * |[
+ * g_slist_free_full (another_list, g_object_unref);
+ * ]|
+ *
+ * Returns: a full copy of @list, use #g_slist_free_full to free it
+ *
+ * Since: 2.34
+ */
+GSList*
+g_slist_copy_deep (GSList *list, GCopyFunc func, gpointer user_data)
+{
   GSList *new_list = NULL;
 
   if (list)
@@ -569,14 +605,20 @@ g_slist_copy (GSList *list)
       GSList *last;
 
       new_list = _g_slist_alloc ();
-      new_list->data = list->data;
+      if (func)
+        new_list->data = func (list->data, user_data);
+      else
+        new_list->data = list->data;
       last = new_list;
       list = list->next;
       while (list)
         {
           last->next = _g_slist_alloc ();
           last = last->next;
-          last->data = list->data;
+          if (func)
+            last->data = func (list->data, user_data);
+          else
+            last->data = list->data;
           list = list->next;
         }
       last->next = NULL;
diff --git a/glib/gslist.h b/glib/gslist.h
index 5652145..c61fd2f 100644
--- a/glib/gslist.h
+++ b/glib/gslist.h
@@ -32,6 +32,7 @@
 #define __G_SLIST_H__
 
 #include <glib/gmem.h>
+#include <glib/gnode.h>
 
 G_BEGIN_DECLS
 
@@ -80,6 +81,11 @@ GSList*  g_slist_delete_link             (GSList           *list,
 					  GSList           *link_) G_GNUC_WARN_UNUSED_RESULT;
 GSList*  g_slist_reverse                 (GSList           *list) G_GNUC_WARN_UNUSED_RESULT;
 GSList*  g_slist_copy                    (GSList           *list) G_GNUC_WARN_UNUSED_RESULT;
+
+GLIB_AVAILABLE_IN_2_34
+GSList*  g_slist_copy_deep               (GSList            *list,
+					  GCopyFunc         func,
+					  gpointer          user_data) G_GNUC_WARN_UNUSED_RESULT;
 GSList*  g_slist_nth                     (GSList           *list,
 					  guint             n);
 GSList*  g_slist_find                    (GSList           *list,
diff --git a/glib/tests/list.c b/glib/tests/list.c
index 648a70e..7241784 100644
--- a/glib/tests/list.c
+++ b/glib/tests/list.c
@@ -388,6 +388,34 @@ test_list_copy (void)
   g_list_free (l2);
 }
 
+static gpointer
+multiply_value (gconstpointer value, gpointer data)
+{
+  return GINT_TO_POINTER (GPOINTER_TO_INT (value) * GPOINTER_TO_INT (data));
+}
+
+static void
+test_list_copy_deep (void)
+{
+  GList *l, *l2;
+  GList *u, *v;
+
+  l = NULL;
+  l = g_list_append (l, GINT_TO_POINTER (1));
+  l = g_list_append (l, GINT_TO_POINTER (2));
+  l = g_list_append (l, GINT_TO_POINTER (3));
+
+  l2 = g_list_copy_deep (l, multiply_value, GINT_TO_POINTER (2));
+
+  for (u = l, v = l2; u && v; u = u->next, v = v->next)
+    {
+      g_assert_cmpint (GPOINTER_TO_INT (u->data) * 2, ==, GPOINTER_TO_INT (v->data));
+    }
+
+  g_list_free (l);
+  g_list_free (l2);
+}
+
 static void
 test_delete_link (void)
 {
@@ -484,6 +512,7 @@ main (int argc, char *argv[])
   g_test_add_func ("/list/insert", test_list_insert);
   g_test_add_func ("/list/free-full", test_free_full);
   g_test_add_func ("/list/copy", test_list_copy);
+  g_test_add_func ("/list/copy-deep", test_list_copy_deep);
   g_test_add_func ("/list/delete-link", test_delete_link);
   g_test_add_func ("/list/prepend", test_prepend);
   g_test_add_func ("/list/position", test_position);



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