mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-26 15:36:14 +01:00
Merge branch 'improve_g_ptr_array_api' into 'master'
Adding g_ptr_array_copy() and g_ptr_array_extend() to garray API Closes #269 See merge request GNOME/glib!918
This commit is contained in:
commit
75614a0972
@ -2638,11 +2638,14 @@ GPtrArray
|
||||
g_ptr_array_new
|
||||
g_ptr_array_sized_new
|
||||
g_ptr_array_new_with_free_func
|
||||
g_ptr_array_copy
|
||||
g_ptr_array_new_full
|
||||
g_ptr_array_set_free_func
|
||||
g_ptr_array_ref
|
||||
g_ptr_array_unref
|
||||
g_ptr_array_add
|
||||
g_ptr_array_extend
|
||||
g_ptr_array_extend_and_steal
|
||||
g_ptr_array_insert
|
||||
g_ptr_array_remove
|
||||
g_ptr_array_remove_index
|
||||
|
129
glib/garray.c
129
glib/garray.c
@ -922,6 +922,52 @@ g_ptr_array_new (void)
|
||||
return g_ptr_array_sized_new (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_ptr_array_copy:
|
||||
* @array: #GPtrArray to duplicate
|
||||
* @func: (nullable): a copy function used to copy every element in the array
|
||||
* @user_data: user data passed to the copy function @func, or %NULL
|
||||
*
|
||||
* Makes a full (deep) copy of a #GPtrArray.
|
||||
*
|
||||
* @func, as a #GCopyFunc, takes two arguments, the data to be copied
|
||||
* and a @user_data pointer. On common processor architectures, it's safe to
|
||||
* pass %NULL as @user_data if the copy function takes only one argument. You
|
||||
* may get compiler warnings from this though if compiling with GCC’s
|
||||
* `-Wcast-function-type` warning.
|
||||
*
|
||||
* If @func is %NULL, then only the pointers (and not what they are
|
||||
* pointing to) are copied to the new #GPtrArray.
|
||||
*
|
||||
* Returns: (transfer full): a deep copy of the initial #GPtrArray.
|
||||
*
|
||||
* Since: 2.62
|
||||
**/
|
||||
GPtrArray *
|
||||
g_ptr_array_copy (GPtrArray *array,
|
||||
GCopyFunc func,
|
||||
gpointer user_data)
|
||||
{
|
||||
gsize i;
|
||||
GPtrArray *new_array;
|
||||
|
||||
g_return_val_if_fail (array != NULL, NULL);
|
||||
|
||||
new_array = g_ptr_array_sized_new (array->len);
|
||||
if (func != NULL)
|
||||
{
|
||||
for (i = 0; i < array->len; i++)
|
||||
new_array->pdata[i] = func (array->pdata[i], user_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (new_array->pdata, array->pdata,
|
||||
array->len * sizeof (*array->pdata));
|
||||
}
|
||||
|
||||
return new_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_ptr_array_sized_new:
|
||||
* @reserved_size: number of pointers preallocated
|
||||
@ -1492,6 +1538,89 @@ g_ptr_array_add (GPtrArray *array,
|
||||
rarray->pdata[rarray->len++] = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_ptr_array_extend:
|
||||
* @array_to_extend: a #GPtrArray.
|
||||
* @array: (transfer none): a #GPtrArray to add to the end of @array_to_extend.
|
||||
* @func: (nullable): a copy function used to copy every element in the array
|
||||
* @user_data: user data passed to the copy function @func, or %NULL
|
||||
*
|
||||
* Adds all pointers of @array to the end of the array @array_to_extend.
|
||||
* The array will grow in size automatically if needed. @array_to_extend is
|
||||
* modified in-place.
|
||||
*
|
||||
* @func, as a #GCopyFunc, takes two arguments, the data to be copied
|
||||
* and a @user_data pointer. On common processor architectures, it's safe to
|
||||
* pass %NULL as @user_data if the copy function takes only one argument. You
|
||||
* may get compiler warnings from this though if compiling with GCC’s
|
||||
* `-Wcast-function-type` warning.
|
||||
*
|
||||
* If @func is %NULL, then only the pointers (and not what they are
|
||||
* pointing to) are copied to the new #GPtrArray.
|
||||
*
|
||||
* Since: 2.62
|
||||
**/
|
||||
void
|
||||
g_ptr_array_extend (GPtrArray *array_to_extend,
|
||||
GPtrArray *array,
|
||||
GCopyFunc func,
|
||||
gpointer user_data)
|
||||
{
|
||||
GRealPtrArray *rarray_to_extend = (GRealPtrArray *) array_to_extend;
|
||||
gsize i;
|
||||
|
||||
g_return_if_fail (array_to_extend != NULL);
|
||||
g_return_if_fail (array != NULL);
|
||||
|
||||
g_ptr_array_maybe_expand (rarray_to_extend, array->len);
|
||||
|
||||
if (func != NULL)
|
||||
{
|
||||
for (i = 0; i < array->len; i++)
|
||||
rarray_to_extend->pdata[i + rarray_to_extend->len] =
|
||||
func (array->pdata[i], user_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (rarray_to_extend->pdata + rarray_to_extend->len, array->pdata,
|
||||
array->len * sizeof (*array->pdata));
|
||||
}
|
||||
|
||||
rarray_to_extend->len += array->len;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_ptr_array_extend_and_steal:
|
||||
* @array_to_extend: (transfer none): a #GPtrArray.
|
||||
* @array: (transfer container): a #GPtrArray to add to the end of
|
||||
* @array_to_extend.
|
||||
*
|
||||
* Adds all the pointers in @array to the end of @array_to_extend, transferring
|
||||
* ownership of each element from @array to @array_to_extend and modifying
|
||||
* @array_to_extend in-place. @array is then freed.
|
||||
*
|
||||
* As with g_ptr_array_free(), @array will be destroyed if its reference count
|
||||
* is 1. If its reference count is higher, it will be decremented and the
|
||||
* length of @array set to zero.
|
||||
*
|
||||
* Since: 2.62
|
||||
**/
|
||||
void
|
||||
g_ptr_array_extend_and_steal (GPtrArray *array_to_extend,
|
||||
GPtrArray *array)
|
||||
{
|
||||
gpointer *pdata;
|
||||
|
||||
g_ptr_array_extend (array_to_extend, array, NULL, NULL);
|
||||
|
||||
/* Get rid of @array without triggering the GDestroyNotify attached
|
||||
* to the elements moved from @array to @array_to_extend. */
|
||||
pdata = g_steal_pointer (&array->pdata);
|
||||
array->len = 0;
|
||||
g_ptr_array_unref (array);
|
||||
g_free (pdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_ptr_array_insert:
|
||||
* @array: a #GPtrArray
|
||||
|
@ -130,6 +130,10 @@ GLIB_AVAILABLE_IN_ALL
|
||||
GPtrArray* g_ptr_array_new (void);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
GPtrArray* g_ptr_array_new_with_free_func (GDestroyNotify element_free_func);
|
||||
GLIB_AVAILABLE_IN_2_62
|
||||
GPtrArray *g_ptr_array_copy (GPtrArray *array,
|
||||
GCopyFunc func,
|
||||
gpointer user_data);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
GPtrArray* g_ptr_array_sized_new (guint reserved_size);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
@ -173,6 +177,14 @@ GPtrArray *g_ptr_array_remove_range (GPtrArray *array,
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_ptr_array_add (GPtrArray *array,
|
||||
gpointer data);
|
||||
GLIB_AVAILABLE_IN_2_62
|
||||
void g_ptr_array_extend (GPtrArray *array_to_extend,
|
||||
GPtrArray *array,
|
||||
GCopyFunc func,
|
||||
gpointer user_data);
|
||||
GLIB_AVAILABLE_IN_2_62
|
||||
void g_ptr_array_extend_and_steal (GPtrArray *array_to_extend,
|
||||
GPtrArray *array);
|
||||
GLIB_AVAILABLE_IN_2_40
|
||||
void g_ptr_array_insert (GPtrArray *array,
|
||||
gint index_,
|
||||
|
15
glib/gnode.h
15
glib/gnode.h
@ -60,21 +60,6 @@ typedef gboolean (*GNodeTraverseFunc) (GNode *node,
|
||||
typedef void (*GNodeForeachFunc) (GNode *node,
|
||||
gpointer data);
|
||||
|
||||
/**
|
||||
* GCopyFunc:
|
||||
* @src: (not nullable): A pointer to the data which should be copied
|
||||
* @data: Additional data
|
||||
*
|
||||
* A function of this signature is used to copy the node data
|
||||
* when doing a deep-copy of a tree.
|
||||
*
|
||||
* Returns: (not nullable): A pointer to the copy
|
||||
*
|
||||
* Since: 2.4
|
||||
*/
|
||||
typedef gpointer (*GCopyFunc) (gconstpointer src,
|
||||
gpointer data);
|
||||
|
||||
/* N-way tree implementation
|
||||
*/
|
||||
struct _GNode
|
||||
|
@ -118,6 +118,20 @@ typedef void (*GHFunc) (gpointer key,
|
||||
gpointer value,
|
||||
gpointer user_data);
|
||||
|
||||
/**
|
||||
* GCopyFunc:
|
||||
* @src: (not nullable): A pointer to the data which should be copied
|
||||
* @data: Additional data
|
||||
*
|
||||
* A function of this signature is used to copy the node data
|
||||
* when doing a deep-copy of a tree.
|
||||
*
|
||||
* Returns: (not nullable): A pointer to the copy
|
||||
*
|
||||
* Since: 2.4
|
||||
*/
|
||||
typedef gpointer (*GCopyFunc) (gconstpointer src,
|
||||
gpointer data);
|
||||
/**
|
||||
* GFreeFunc:
|
||||
* @data: a data pointer
|
||||
|
@ -23,7 +23,6 @@
|
||||
*/
|
||||
|
||||
#undef G_DISABLE_ASSERT
|
||||
#undef G_LOG_DOMAIN
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -746,6 +745,260 @@ pointer_array_free_func (void)
|
||||
g_assert_cmpint (num_free_func_invocations, ==, 0);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
ptr_array_copy_func (gconstpointer src, gpointer userdata)
|
||||
{
|
||||
gsize *dst = g_malloc (sizeof (gsize));
|
||||
*dst = *((gsize *) src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
/* Test the g_ptr_array_copy() function */
|
||||
static void
|
||||
pointer_array_copy (void)
|
||||
{
|
||||
GPtrArray *ptr_array, *ptr_array2;
|
||||
gsize i;
|
||||
const gsize array_size = 100;
|
||||
gsize *array_test = g_malloc (array_size * sizeof (gsize));
|
||||
|
||||
g_test_summary ("Check all normal behaviour of stealing elements from one "
|
||||
"array to append to another, covering different array sizes "
|
||||
"and element copy functions");
|
||||
|
||||
if (g_test_undefined ())
|
||||
{
|
||||
/* Testing degenerated cases */
|
||||
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
|
||||
"*assertion*!= NULL*");
|
||||
ptr_array = g_ptr_array_copy (NULL, NULL, NULL);
|
||||
g_test_assert_expected_messages ();
|
||||
g_assert_cmpuint ((gsize) ptr_array, ==, (gsize) NULL);
|
||||
}
|
||||
|
||||
/* Initializing array_test */
|
||||
for (i = 0; i < array_size; i++)
|
||||
array_test[i] = i;
|
||||
|
||||
/* Test copy an empty array */
|
||||
ptr_array = g_ptr_array_sized_new (0);
|
||||
ptr_array2 = g_ptr_array_copy (ptr_array, NULL, NULL);
|
||||
|
||||
g_ptr_array_unref (ptr_array);
|
||||
g_ptr_array_unref (ptr_array2);
|
||||
|
||||
/* Test simple copy */
|
||||
ptr_array = g_ptr_array_sized_new (array_size);
|
||||
|
||||
for (i = 0; i < array_size; i++)
|
||||
g_ptr_array_add (ptr_array, &array_test[i]);
|
||||
|
||||
ptr_array2 = g_ptr_array_copy (ptr_array, NULL, NULL);
|
||||
|
||||
for (i = 0; i < array_size; i++)
|
||||
g_assert_cmpuint (*((gsize *) g_ptr_array_index (ptr_array2, i)), ==, i);
|
||||
|
||||
for (i = 0; i < array_size; i++)
|
||||
g_assert_cmpuint ((gsize) g_ptr_array_index (ptr_array, i), ==,
|
||||
(gsize) g_ptr_array_index (ptr_array2, i));
|
||||
|
||||
g_ptr_array_free (ptr_array2, TRUE);
|
||||
|
||||
/* Test copy through GCopyFunc */
|
||||
ptr_array2 = g_ptr_array_copy (ptr_array, ptr_array_copy_func, NULL);
|
||||
|
||||
for (i = 0; i < array_size; i++)
|
||||
g_assert_cmpuint (*((gsize *) g_ptr_array_index (ptr_array2, i)), ==, i);
|
||||
|
||||
for (i = 0; i < array_size; i++)
|
||||
g_assert_cmpuint ((gsize) g_ptr_array_index (ptr_array, i), !=,
|
||||
(gsize) g_ptr_array_index (ptr_array2, i));
|
||||
|
||||
for (i = 0; i < array_size; i++)
|
||||
free(ptr_array2->pdata[i]);
|
||||
|
||||
g_ptr_array_free (ptr_array2, TRUE);
|
||||
|
||||
/* Final cleanup */
|
||||
g_ptr_array_free (ptr_array, TRUE);
|
||||
g_free (array_test);
|
||||
}
|
||||
|
||||
/* Test the g_ptr_array_extend() function */
|
||||
static void
|
||||
pointer_array_extend (void)
|
||||
{
|
||||
GPtrArray *ptr_array, *ptr_array2;
|
||||
gsize i;
|
||||
const gsize array_size = 100;
|
||||
gsize *array_test = g_malloc (array_size * sizeof (gsize));
|
||||
|
||||
if (g_test_undefined ())
|
||||
{
|
||||
/* Testing degenerated cases */
|
||||
ptr_array = g_ptr_array_sized_new (0);
|
||||
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
|
||||
"*assertion*!= NULL*");
|
||||
g_ptr_array_extend (NULL, ptr_array, NULL, NULL);
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
|
||||
"*assertion*!= NULL*");
|
||||
g_ptr_array_extend (ptr_array, NULL, NULL, NULL);
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
g_ptr_array_unref (ptr_array);
|
||||
}
|
||||
|
||||
/* Initializing array_test */
|
||||
for (i = 0; i < array_size; i++)
|
||||
array_test[i] = i;
|
||||
|
||||
/* Testing extend with array of size zero */
|
||||
ptr_array = g_ptr_array_sized_new (0);
|
||||
ptr_array2 = g_ptr_array_sized_new (0);
|
||||
|
||||
g_ptr_array_extend (ptr_array, ptr_array2, NULL, NULL);
|
||||
|
||||
g_assert_cmpuint (ptr_array->len, ==, 0);
|
||||
g_assert_cmpuint (ptr_array2->len, ==, 0);
|
||||
|
||||
g_ptr_array_unref (ptr_array);
|
||||
g_ptr_array_unref (ptr_array2);
|
||||
|
||||
/* Testing extend an array of size zero */
|
||||
ptr_array = g_ptr_array_sized_new (array_size);
|
||||
ptr_array2 = g_ptr_array_sized_new (0);
|
||||
|
||||
for (i = 0; i < array_size; i++)
|
||||
{
|
||||
g_ptr_array_add (ptr_array, &array_test[i]);
|
||||
}
|
||||
|
||||
g_ptr_array_extend (ptr_array, ptr_array2, NULL, NULL);
|
||||
|
||||
for (i = 0; i < array_size; i++)
|
||||
g_assert_cmpuint (*((gsize *) g_ptr_array_index (ptr_array, i)), ==, i);
|
||||
|
||||
g_ptr_array_unref (ptr_array);
|
||||
g_ptr_array_unref (ptr_array2);
|
||||
|
||||
/* Testing extend an array of size zero */
|
||||
ptr_array = g_ptr_array_sized_new (0);
|
||||
ptr_array2 = g_ptr_array_sized_new (array_size);
|
||||
|
||||
for (i = 0; i < array_size; i++)
|
||||
{
|
||||
g_ptr_array_add (ptr_array2, &array_test[i]);
|
||||
}
|
||||
|
||||
g_ptr_array_extend (ptr_array, ptr_array2, NULL, NULL);
|
||||
|
||||
for (i = 0; i < array_size; i++)
|
||||
g_assert_cmpuint (*((gsize *) g_ptr_array_index (ptr_array, i)), ==, i);
|
||||
|
||||
g_ptr_array_unref (ptr_array);
|
||||
g_ptr_array_unref (ptr_array2);
|
||||
|
||||
/* Testing simple extend */
|
||||
ptr_array = g_ptr_array_sized_new (array_size / 2);
|
||||
ptr_array2 = g_ptr_array_sized_new (array_size / 2);
|
||||
|
||||
for (i = 0; i < array_size / 2; i++)
|
||||
{
|
||||
g_ptr_array_add (ptr_array, &array_test[i]);
|
||||
g_ptr_array_add (ptr_array2, &array_test[i + (array_size / 2)]);
|
||||
}
|
||||
|
||||
g_ptr_array_extend (ptr_array, ptr_array2, NULL, NULL);
|
||||
|
||||
for (i = 0; i < array_size; i++)
|
||||
g_assert_cmpuint (*((gsize *) g_ptr_array_index (ptr_array, i)), ==, i);
|
||||
|
||||
g_ptr_array_unref (ptr_array);
|
||||
g_ptr_array_unref (ptr_array2);
|
||||
|
||||
/* Testing extend with GCopyFunc */
|
||||
ptr_array = g_ptr_array_sized_new (array_size / 2);
|
||||
ptr_array2 = g_ptr_array_sized_new (array_size / 2);
|
||||
|
||||
for (i = 0; i < array_size / 2; i++)
|
||||
{
|
||||
g_ptr_array_add (ptr_array, &array_test[i]);
|
||||
g_ptr_array_add (ptr_array2, &array_test[i + (array_size / 2)]);
|
||||
}
|
||||
|
||||
g_ptr_array_extend (ptr_array, ptr_array2, ptr_array_copy_func, NULL);
|
||||
|
||||
for (i = 0; i < array_size; i++)
|
||||
g_assert_cmpuint (*((gsize *) g_ptr_array_index (ptr_array, i)), ==, i);
|
||||
|
||||
/* Clean-up memory */
|
||||
for (i = array_size / 2; i < array_size; i++)
|
||||
g_free (g_ptr_array_index (ptr_array, i));
|
||||
|
||||
g_ptr_array_unref (ptr_array);
|
||||
g_ptr_array_unref (ptr_array2);
|
||||
g_free (array_test);
|
||||
}
|
||||
|
||||
/* Test the g_ptr_array_extend_and_steal() function */
|
||||
static void
|
||||
pointer_array_extend_and_steal (void)
|
||||
{
|
||||
GPtrArray *ptr_array, *ptr_array2, *ptr_array3;
|
||||
gsize i;
|
||||
const gsize array_size = 100;
|
||||
gsize *array_test = g_malloc (array_size * sizeof (gsize));
|
||||
|
||||
/* Initializing array_test */
|
||||
for (i = 0; i < array_size; i++)
|
||||
array_test[i] = i;
|
||||
|
||||
/* Testing simple extend_and_steal() */
|
||||
ptr_array = g_ptr_array_sized_new (array_size / 2);
|
||||
ptr_array2 = g_ptr_array_sized_new (array_size / 2);
|
||||
|
||||
for (i = 0; i < array_size / 2; i++)
|
||||
{
|
||||
g_ptr_array_add (ptr_array, &array_test[i]);
|
||||
g_ptr_array_add (ptr_array2, &array_test[i + (array_size / 2)]);
|
||||
}
|
||||
|
||||
g_ptr_array_extend_and_steal (ptr_array, ptr_array2);
|
||||
|
||||
for (i = 0; i < array_size; i++)
|
||||
g_assert_cmpuint (*((gsize *) g_ptr_array_index (ptr_array, i)), ==, i);
|
||||
|
||||
g_ptr_array_free (ptr_array, TRUE);
|
||||
|
||||
/* Testing extend_and_steal() with a pending reference to stolen array */
|
||||
ptr_array = g_ptr_array_sized_new (array_size / 2);
|
||||
ptr_array2 = g_ptr_array_sized_new (array_size / 2);
|
||||
|
||||
for (i = 0; i < array_size / 2; i++)
|
||||
{
|
||||
g_ptr_array_add (ptr_array, &array_test[i]);
|
||||
g_ptr_array_add (ptr_array2, &array_test[i + (array_size / 2)]);
|
||||
}
|
||||
|
||||
ptr_array3 = g_ptr_array_ref (ptr_array2);
|
||||
|
||||
g_ptr_array_extend_and_steal (ptr_array, ptr_array2);
|
||||
|
||||
for (i = 0; i < array_size; i++)
|
||||
g_assert_cmpuint (*((gsize *) g_ptr_array_index (ptr_array, i)), ==, i);
|
||||
|
||||
g_assert_cmpuint (ptr_array3->len, ==, 0);
|
||||
g_assert_null (ptr_array3->pdata);
|
||||
|
||||
g_ptr_array_free (ptr_array, TRUE);
|
||||
g_ptr_array_free (ptr_array3, TRUE);
|
||||
|
||||
/* Final memory clean-up */
|
||||
g_free (array_test);
|
||||
}
|
||||
|
||||
static gint
|
||||
ptr_compare (gconstpointer p1, gconstpointer p2)
|
||||
{
|
||||
@ -1262,6 +1515,9 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/pointerarray/insert", pointer_array_insert);
|
||||
g_test_add_func ("/pointerarray/ref-count", pointer_array_ref_count);
|
||||
g_test_add_func ("/pointerarray/free-func", pointer_array_free_func);
|
||||
g_test_add_func ("/pointerarray/array_copy", pointer_array_copy);
|
||||
g_test_add_func ("/pointerarray/array_extend", pointer_array_extend);
|
||||
g_test_add_func ("/pointerarray/array_extend_and_steal", pointer_array_extend_and_steal);
|
||||
g_test_add_func ("/pointerarray/sort", pointer_array_sort);
|
||||
g_test_add_func ("/pointerarray/sort-with-data", pointer_array_sort_with_data);
|
||||
g_test_add_func ("/pointerarray/find/empty", pointer_array_find_empty);
|
||||
|
Loading…
Reference in New Issue
Block a user