From 2fd6eb7e1cfc878d011ec0b7e58c5e696186516e Mon Sep 17 00:00:00 2001 From: Jonh Wendell Date: Thu, 21 Jun 2012 12:23:23 -0300 Subject: [PATCH] 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 g_list_length g_list_copy +g_list_copy_deep g_list_reverse g_list_sort GCompareFunc @@ -2101,6 +2102,7 @@ g_slist_free1 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 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. * * * 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 +#include 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 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. * * * 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 +#include 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); -- 2.7.4