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
<SUBSECTION>
g_list_length
g_list_copy
+g_list_copy_deep
g_list_reverse
g_list_sort
GCompareFunc
<SUBSECTION>
g_slist_length
g_slist_copy
+g_slist_copy_deep
g_slist_reverse
g_slist_insert_sorted_with_data
g_slist_sort
g_list_append
g_list_concat
g_list_copy
+g_list_copy_deep
g_list_delete_link
g_list_find
g_list_find_custom
g_slist_append
g_slist_concat
g_slist_copy
+g_slist_copy_deep
g_slist_delete_link
g_slist_find
g_slist_find_custom
* <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;
if (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;
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;
#define __G_LIST_H__
#include <glib/gmem.h>
+#include <glib/gnode.h>
G_BEGIN_DECLS
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,
* <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;
if (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;
#define __G_SLIST_H__
#include <glib/gmem.h>
+#include <glib/gnode.h>
G_BEGIN_DECLS
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,
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)
{
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);