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
This commit is contained in:
Jonh Wendell 2012-06-21 12:23:23 -03:00
parent e0f4b2b03b
commit 2fd6eb7e1c
7 changed files with 136 additions and 6 deletions

View File

@ -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

View File

@ -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

View File

@ -566,13 +566,49 @@ 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
*/
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;
@ -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;

View File

@ -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,

View File

@ -554,13 +554,49 @@ 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
*/
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;
@ -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;

View File

@ -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,

View File

@ -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);