mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-08-19 15:18:55 +02:00
garray: Add g_ptr_array_new_from_null_terminated_array()
It allows to create a GPtrArray from a null-terminated C array computing its size and in case performing copies of the its values using the provided GCopyFunc.
This commit is contained in:
@@ -2718,6 +2718,7 @@ g_ptr_array_new_null_terminated
|
|||||||
g_ptr_array_new_take
|
g_ptr_array_new_take
|
||||||
g_ptr_array_new_take_null_terminated
|
g_ptr_array_new_take_null_terminated
|
||||||
g_ptr_array_new_from_array
|
g_ptr_array_new_from_array
|
||||||
|
g_ptr_array_new_from_null_terminated_array
|
||||||
g_ptr_array_set_free_func
|
g_ptr_array_set_free_func
|
||||||
g_ptr_array_is_null_terminated
|
g_ptr_array_is_null_terminated
|
||||||
g_ptr_array_ref
|
g_ptr_array_ref
|
||||||
|
@@ -1238,12 +1238,45 @@ g_ptr_array_new_take_null_terminated (gpointer *data,
|
|||||||
len += 1;
|
len += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_return_val_if_fail (len <= G_MAXUINT, NULL);
|
||||||
|
|
||||||
array = g_ptr_array_new_take (g_steal_pointer (&data), len, element_free_func);
|
array = g_ptr_array_new_take (g_steal_pointer (&data), len, element_free_func);
|
||||||
((GRealPtrArray *)array)->null_terminated = TRUE;
|
((GRealPtrArray *)array)->null_terminated = TRUE;
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GPtrArray *
|
||||||
|
ptr_array_new_from_array (gpointer *data,
|
||||||
|
gsize len,
|
||||||
|
GCopyFunc copy_func,
|
||||||
|
gpointer copy_func_user_data,
|
||||||
|
GDestroyNotify element_free_func,
|
||||||
|
gboolean null_terminated)
|
||||||
|
{
|
||||||
|
GPtrArray *array;
|
||||||
|
GRealPtrArray *rarray;
|
||||||
|
|
||||||
|
g_assert (len <= G_MAXUINT);
|
||||||
|
|
||||||
|
array = ptr_array_new (len, element_free_func, null_terminated);
|
||||||
|
rarray = (GRealPtrArray *)array;
|
||||||
|
|
||||||
|
if (copy_func != NULL)
|
||||||
|
{
|
||||||
|
for (gsize i = 0; i < len; i++)
|
||||||
|
rarray->pdata[i] = copy_func (data[i], copy_func_user_data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy (rarray->pdata, data, len * sizeof (gpointer));
|
||||||
|
}
|
||||||
|
|
||||||
|
rarray->len = len;
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* g_ptr_array_new_from_array: (skip)
|
* g_ptr_array_new_from_array: (skip)
|
||||||
* @data: (array length=len) (transfer none) (nullable): an array of pointers,
|
* @data: (array length=len) (transfer none) (nullable): an array of pointers,
|
||||||
@@ -1283,28 +1316,58 @@ g_ptr_array_new_from_array (gpointer *data,
|
|||||||
gpointer copy_func_user_data,
|
gpointer copy_func_user_data,
|
||||||
GDestroyNotify element_free_func)
|
GDestroyNotify element_free_func)
|
||||||
{
|
{
|
||||||
GPtrArray *array;
|
|
||||||
GRealPtrArray *rarray;
|
|
||||||
|
|
||||||
g_return_val_if_fail (data != NULL || len == 0, NULL);
|
g_return_val_if_fail (data != NULL || len == 0, NULL);
|
||||||
g_return_val_if_fail (len <= G_MAXUINT, NULL);
|
g_return_val_if_fail (len <= G_MAXUINT, NULL);
|
||||||
|
|
||||||
array = ptr_array_new (len, element_free_func, FALSE);
|
return ptr_array_new_from_array (
|
||||||
rarray = (GRealPtrArray *)array;
|
data, len, copy_func, copy_func_user_data, element_free_func, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
if (copy_func != NULL)
|
/**
|
||||||
|
* g_ptr_array_new_from_null_terminated_array: (skip)
|
||||||
|
* @data: (array zero-terminated=1) (transfer none) (nullable): an array of
|
||||||
|
* pointers, %NULL terminated; or %NULL for an empty array
|
||||||
|
* @copy_func: (nullable): a copy function used to copy every element in the
|
||||||
|
* array or %NULL.
|
||||||
|
* @copy_func_user_data: user data passed to @copy_func, or %NULL
|
||||||
|
* @element_free_func: (nullable): a function to free elements on @array
|
||||||
|
* destruction or %NULL
|
||||||
|
*
|
||||||
|
* Creates a new #GPtrArray copying the pointers from @data after having
|
||||||
|
* computed the length of it and with a reference count of 1.
|
||||||
|
* This avoids having to manually add each element one by one.
|
||||||
|
* If @copy_func is provided, then it is used to copy the data in the new
|
||||||
|
* array.
|
||||||
|
* It also set @element_free_func for freeing each element when the array is
|
||||||
|
* destroyed either via g_ptr_array_unref(), when g_ptr_array_free() is called
|
||||||
|
* with @free_segment set to %TRUE or when removing elements.
|
||||||
|
*
|
||||||
|
* Do not use it if the @data has more than %G_MAXUINT elements. #GPtrArray
|
||||||
|
* stores the length of its data in #guint, which may be shorter than
|
||||||
|
* #gsize.
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): A new #GPtrArray
|
||||||
|
*
|
||||||
|
* Since: 2.76
|
||||||
|
*/
|
||||||
|
GPtrArray *
|
||||||
|
g_ptr_array_new_from_null_terminated_array (gpointer *data,
|
||||||
|
GCopyFunc copy_func,
|
||||||
|
gpointer copy_func_user_data,
|
||||||
|
GDestroyNotify element_free_func)
|
||||||
|
{
|
||||||
|
gsize len = 0;
|
||||||
|
|
||||||
|
if (data != NULL)
|
||||||
{
|
{
|
||||||
for (gsize i = 0; i < len; i++)
|
for (gsize i = 0; data[i] != NULL; ++i)
|
||||||
rarray->pdata[i] = copy_func (data[i], copy_func_user_data);
|
len += 1;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy (rarray->pdata, data, len * sizeof (gpointer));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rarray->len = len;
|
g_return_val_if_fail (len <= G_MAXUINT, NULL);
|
||||||
|
|
||||||
return array;
|
return ptr_array_new_from_array (
|
||||||
|
data, len, copy_func, copy_func_user_data, element_free_func, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -171,6 +171,11 @@ GPtrArray* g_ptr_array_new_null_terminated (guint reserved_size,
|
|||||||
GLIB_AVAILABLE_IN_2_76
|
GLIB_AVAILABLE_IN_2_76
|
||||||
GPtrArray* g_ptr_array_new_take_null_terminated (gpointer *data,
|
GPtrArray* g_ptr_array_new_take_null_terminated (gpointer *data,
|
||||||
GDestroyNotify element_free_func);
|
GDestroyNotify element_free_func);
|
||||||
|
GLIB_AVAILABLE_IN_2_76
|
||||||
|
GPtrArray* g_ptr_array_new_from_null_terminated_array (gpointer *data,
|
||||||
|
GCopyFunc copy_func,
|
||||||
|
gpointer copy_func_user_data,
|
||||||
|
GDestroyNotify element_free_func);
|
||||||
GLIB_AVAILABLE_IN_ALL
|
GLIB_AVAILABLE_IN_ALL
|
||||||
gpointer* g_ptr_array_free (GPtrArray *array,
|
gpointer* g_ptr_array_free (GPtrArray *array,
|
||||||
gboolean free_seg);
|
gboolean free_seg);
|
||||||
|
@@ -1460,6 +1460,191 @@ pointer_array_new_from_array_with_copy_and_free_func (void)
|
|||||||
g_free (old_pdata_copy);
|
g_free (old_pdata_copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pointer_array_new_from_null_terminated_array (void)
|
||||||
|
{
|
||||||
|
const size_t array_size = 10000;
|
||||||
|
GPtrArray *source_array;
|
||||||
|
GPtrArray *gparray;
|
||||||
|
gpointer *old_pdata_copy;
|
||||||
|
|
||||||
|
source_array = g_ptr_array_new_null_terminated (array_size, NULL, TRUE);
|
||||||
|
g_assert_true (g_ptr_array_is_null_terminated (source_array));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < array_size; i++)
|
||||||
|
g_ptr_array_add (source_array, GUINT_TO_POINTER (i + 1));
|
||||||
|
|
||||||
|
g_assert_cmpuint (array_size, ==, source_array->len);
|
||||||
|
g_assert_nonnull (source_array->pdata);
|
||||||
|
|
||||||
|
old_pdata_copy =
|
||||||
|
g_memdup2 (source_array->pdata, source_array->len * sizeof (gpointer));
|
||||||
|
g_assert_nonnull (old_pdata_copy);
|
||||||
|
|
||||||
|
gparray = g_ptr_array_new_from_null_terminated_array (source_array->pdata,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
g_assert_true (g_ptr_array_is_null_terminated (source_array));
|
||||||
|
assert_ptr_array_null_terminated (gparray, TRUE);
|
||||||
|
|
||||||
|
g_clear_pointer (&source_array, g_ptr_array_unref);
|
||||||
|
|
||||||
|
g_assert_true (g_ptr_array_is_null_terminated (gparray));
|
||||||
|
g_assert_cmpuint (gparray->len, ==, array_size);
|
||||||
|
|
||||||
|
g_assert_cmpuint (GPOINTER_TO_UINT (g_ptr_array_index (gparray, 0)), ==, 1);
|
||||||
|
g_assert_cmpuint (GPOINTER_TO_UINT (g_ptr_array_index (gparray, 10)), ==, 11);
|
||||||
|
|
||||||
|
g_assert_cmpmem (old_pdata_copy, array_size * sizeof (gpointer),
|
||||||
|
gparray->pdata, array_size * sizeof (gpointer));
|
||||||
|
|
||||||
|
g_ptr_array_add (gparray, GUINT_TO_POINTER (55));
|
||||||
|
assert_ptr_array_null_terminated (gparray, TRUE);
|
||||||
|
|
||||||
|
g_ptr_array_insert (gparray, 0, GUINT_TO_POINTER (33));
|
||||||
|
assert_ptr_array_null_terminated (gparray, TRUE);
|
||||||
|
|
||||||
|
g_assert_cmpuint (gparray->len, ==, array_size + 2);
|
||||||
|
g_assert_cmpuint (GPOINTER_TO_UINT (g_ptr_array_index (gparray, 0)), ==, 33);
|
||||||
|
g_assert_cmpuint (
|
||||||
|
GPOINTER_TO_UINT (g_ptr_array_index (gparray, gparray->len - 1)), ==, 55);
|
||||||
|
|
||||||
|
g_ptr_array_remove_index (gparray, 0);
|
||||||
|
g_assert_cmpuint (gparray->len, ==, array_size + 1);
|
||||||
|
assert_ptr_array_null_terminated (gparray, TRUE);
|
||||||
|
|
||||||
|
g_ptr_array_remove_index (gparray, gparray->len - 1);
|
||||||
|
g_assert_cmpuint (gparray->len, ==, array_size);
|
||||||
|
assert_ptr_array_null_terminated (gparray, TRUE);
|
||||||
|
|
||||||
|
g_assert_cmpmem (old_pdata_copy, array_size * sizeof (gpointer),
|
||||||
|
gparray->pdata, array_size * sizeof (gpointer));
|
||||||
|
|
||||||
|
g_ptr_array_unref (gparray);
|
||||||
|
g_free (old_pdata_copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pointer_array_new_from_null_terminated_array_empty (void)
|
||||||
|
{
|
||||||
|
GPtrArray *gparray;
|
||||||
|
|
||||||
|
gparray = g_ptr_array_new_from_null_terminated_array (
|
||||||
|
(gpointer []) { NULL }, NULL, NULL, NULL);
|
||||||
|
g_assert_true (g_ptr_array_is_null_terminated (gparray));
|
||||||
|
assert_ptr_array_null_terminated (gparray, TRUE);
|
||||||
|
g_assert_cmpuint (gparray->len, ==, 0);
|
||||||
|
|
||||||
|
g_clear_pointer (&gparray, g_ptr_array_unref);
|
||||||
|
|
||||||
|
gparray = g_ptr_array_new_from_null_terminated_array (
|
||||||
|
NULL, NULL, NULL, NULL);
|
||||||
|
g_assert_true (g_ptr_array_is_null_terminated (gparray));
|
||||||
|
assert_ptr_array_null_terminated (gparray, TRUE);
|
||||||
|
g_assert_cmpuint (gparray->len, ==, 0);
|
||||||
|
|
||||||
|
g_clear_pointer (&gparray, g_ptr_array_unref);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pointer_array_new_from_null_terminated_array_with_copy_and_free_func (void)
|
||||||
|
{
|
||||||
|
const size_t array_size = 10000;
|
||||||
|
GPtrArray *source_array;
|
||||||
|
GPtrArray *gparray;
|
||||||
|
GStrv old_pdata_copy;
|
||||||
|
|
||||||
|
source_array = g_ptr_array_new_null_terminated (array_size, g_free, TRUE);
|
||||||
|
g_assert_true (g_ptr_array_is_null_terminated (source_array));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < array_size; i++)
|
||||||
|
g_ptr_array_add (source_array, g_strdup_printf ("%" G_GSIZE_FORMAT, i));
|
||||||
|
|
||||||
|
g_assert_cmpuint (array_size, ==, source_array->len);
|
||||||
|
g_assert_nonnull (source_array->pdata);
|
||||||
|
|
||||||
|
old_pdata_copy = g_strdupv ((char **) source_array->pdata);
|
||||||
|
g_assert_cmpuint (g_strv_length (old_pdata_copy), ==, array_size);
|
||||||
|
g_assert_nonnull (old_pdata_copy);
|
||||||
|
g_clear_pointer (&source_array, g_ptr_array_unref);
|
||||||
|
|
||||||
|
gparray = g_ptr_array_new_from_null_terminated_array (
|
||||||
|
(gpointer* ) old_pdata_copy, (GCopyFunc) g_strdup, NULL, g_free);
|
||||||
|
g_assert_true (g_ptr_array_is_null_terminated (gparray));
|
||||||
|
assert_ptr_array_null_terminated (gparray, TRUE);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < gparray->len; i++)
|
||||||
|
{
|
||||||
|
g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, i), ==,
|
||||||
|
(const char *) old_pdata_copy[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, 0), ==, "0");
|
||||||
|
g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, 101), ==, "101");
|
||||||
|
|
||||||
|
g_ptr_array_add (gparray, g_strdup_printf ("%d", 55));
|
||||||
|
assert_ptr_array_null_terminated (gparray, TRUE);
|
||||||
|
|
||||||
|
g_ptr_array_insert (gparray, 0, g_strdup_printf ("%d", 33));
|
||||||
|
assert_ptr_array_null_terminated (gparray, TRUE);
|
||||||
|
|
||||||
|
g_assert_cmpuint (gparray->len, ==, array_size + 2);
|
||||||
|
g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, 0), ==, "33");
|
||||||
|
g_assert_cmpstr (
|
||||||
|
(const char *) g_ptr_array_index (gparray, gparray->len - 1), ==, "55");
|
||||||
|
|
||||||
|
g_ptr_array_remove_index (gparray, 0);
|
||||||
|
assert_ptr_array_null_terminated (gparray, TRUE);
|
||||||
|
g_assert_cmpuint (gparray->len, ==, array_size + 1);
|
||||||
|
|
||||||
|
g_ptr_array_remove_index (gparray, gparray->len - 1);
|
||||||
|
assert_ptr_array_null_terminated (gparray, TRUE);
|
||||||
|
g_assert_cmpuint (gparray->len, ==, array_size);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < gparray->len; i++)
|
||||||
|
{
|
||||||
|
g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, i), ==,
|
||||||
|
(const char *) old_pdata_copy[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_unref (gparray);
|
||||||
|
g_strfreev (old_pdata_copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pointer_array_new_from_null_terminated_array_from_gstrv (void)
|
||||||
|
{
|
||||||
|
GPtrArray *gparray;
|
||||||
|
GStrv strv;
|
||||||
|
char *joined;
|
||||||
|
|
||||||
|
strv = g_strsplit ("A.dot.separated.string", ".", -1);
|
||||||
|
gparray = g_ptr_array_new_from_null_terminated_array (
|
||||||
|
(gpointer) strv, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
g_assert_cmpstr (
|
||||||
|
(const char *) g_ptr_array_index (gparray, 0), ==, "A");
|
||||||
|
g_assert_true (g_ptr_array_index (gparray, 0) == strv[0]);
|
||||||
|
g_assert_cmpstr (
|
||||||
|
(const char *) g_ptr_array_index (gparray, 1), ==, "dot");
|
||||||
|
g_assert_true (g_ptr_array_index (gparray, 1) == strv[1]);
|
||||||
|
g_assert_cmpstr (
|
||||||
|
(const char *) g_ptr_array_index (gparray, 2), ==, "separated");
|
||||||
|
g_assert_true (g_ptr_array_index (gparray, 2) == strv[2]);
|
||||||
|
g_assert_cmpstr (
|
||||||
|
(const char *) g_ptr_array_index (gparray, 3), ==, "string");
|
||||||
|
g_assert_true (g_ptr_array_index (gparray, 3) == strv[3]);
|
||||||
|
|
||||||
|
g_assert_null (strv[4]);
|
||||||
|
g_assert_null (g_ptr_array_index (gparray, 4));
|
||||||
|
|
||||||
|
joined = g_strjoinv (".", (char **) gparray->pdata);
|
||||||
|
g_assert_cmpstr (joined, ==, "A.dot.separated.string");
|
||||||
|
|
||||||
|
g_ptr_array_unref (gparray);
|
||||||
|
g_strfreev (strv);
|
||||||
|
g_free (joined);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pointer_array_ref_count (gconstpointer test_data)
|
pointer_array_ref_count (gconstpointer test_data)
|
||||||
{
|
{
|
||||||
@@ -2645,6 +2830,10 @@ main (int argc, char *argv[])
|
|||||||
g_test_add_func ("/pointerarray/new-from-array/empty", pointer_array_new_from_array_empty);
|
g_test_add_func ("/pointerarray/new-from-array/empty", pointer_array_new_from_array_empty);
|
||||||
g_test_add_func ("/pointerarray/new-from-array/overflow", pointer_array_new_from_array_overflow);
|
g_test_add_func ("/pointerarray/new-from-array/overflow", pointer_array_new_from_array_overflow);
|
||||||
g_test_add_func ("/pointerarray/new-from-array/with-copy-and-free-func", pointer_array_new_from_array_with_copy_and_free_func);
|
g_test_add_func ("/pointerarray/new-from-array/with-copy-and-free-func", pointer_array_new_from_array_with_copy_and_free_func);
|
||||||
|
g_test_add_func ("/pointerarray/new-from-null-terminated-array", pointer_array_new_from_null_terminated_array);
|
||||||
|
g_test_add_func ("/pointerarray/new-from-null-terminated-array/empty", pointer_array_new_from_null_terminated_array_empty);
|
||||||
|
g_test_add_func ("/pointerarray/new-from-null-terminated-array/with-copy-and-free-func", pointer_array_new_from_null_terminated_array_with_copy_and_free_func);
|
||||||
|
g_test_add_func ("/pointerarray/new-from-null-terminated-array/from-gstrv", pointer_array_new_from_null_terminated_array_from_gstrv);
|
||||||
g_test_add_data_func ("/pointerarray/ref-count/not-null-terminated", GINT_TO_POINTER (0), pointer_array_ref_count);
|
g_test_add_data_func ("/pointerarray/ref-count/not-null-terminated", GINT_TO_POINTER (0), pointer_array_ref_count);
|
||||||
g_test_add_data_func ("/pointerarray/ref-count/null-terminated", GINT_TO_POINTER (1), pointer_array_ref_count);
|
g_test_add_data_func ("/pointerarray/ref-count/null-terminated", GINT_TO_POINTER (1), pointer_array_ref_count);
|
||||||
g_test_add_func ("/pointerarray/free-func", pointer_array_free_func);
|
g_test_add_func ("/pointerarray/free-func", pointer_array_free_func);
|
||||||
|
Reference in New Issue
Block a user