Merge branch 'th/g-ptr-array-set-null-terminated' into 'main'

array: add support for g_ptr_array_null_terminated()

See merge request GNOME/glib!1485
This commit is contained in:
Philip Withnall 2022-05-27 15:08:50 +00:00
commit a922f2f2c7
4 changed files with 312 additions and 57 deletions

View File

@ -3028,7 +3028,9 @@ g_ptr_array_sized_new
g_ptr_array_new_with_free_func
g_ptr_array_copy
g_ptr_array_new_full
g_ptr_array_new_null_terminated
g_ptr_array_set_free_func
g_ptr_array_is_null_terminated
g_ptr_array_ref
g_ptr_array_unref
g_ptr_array_add

View File

@ -1071,6 +1071,7 @@ struct _GRealPtrArray
guint len;
guint alloc;
gatomicrefcount ref_count;
guint8 null_terminated; /* always either 0 or 1, so it can be added to array lengths */
GDestroyNotify element_free_func;
};
@ -1090,9 +1091,17 @@ struct _GRealPtrArray
static void g_ptr_array_maybe_expand (GRealPtrArray *array,
guint len);
static void
ptr_array_null_terminate (GRealPtrArray *rarray)
{
if (G_UNLIKELY (rarray->null_terminated))
rarray->pdata[rarray->len] = NULL;
}
static GPtrArray *
ptr_array_new (guint reserved_size,
GDestroyNotify element_free_func)
GDestroyNotify element_free_func,
gboolean null_terminated)
{
GRealPtrArray *array;
@ -1101,12 +1110,25 @@ ptr_array_new (guint reserved_size,
array->pdata = NULL;
array->len = 0;
array->alloc = 0;
array->null_terminated = null_terminated ? 1 : 0;
array->element_free_func = element_free_func;
g_atomic_ref_count_init (&array->ref_count);
if (reserved_size != 0)
{
if (G_LIKELY (reserved_size < G_MAXUINT) &&
null_terminated)
reserved_size++;
g_ptr_array_maybe_expand (array, reserved_size);
if (null_terminated)
{
/* don't use ptr_array_null_terminate(). It helps the compiler
* to see when @null_terminated is false and thereby inline
* ptr_array_new() and possibly remove the code entirely. */
array->pdata[0] = NULL;
}
}
return (GPtrArray *) array;
}
@ -1121,7 +1143,7 @@ ptr_array_new (guint reserved_size,
GPtrArray*
g_ptr_array_new (void)
{
return ptr_array_new (0, NULL);
return ptr_array_new (0, NULL, FALSE);
}
/**
@ -1134,6 +1156,10 @@ g_ptr_array_new (void)
* the underlying array is preserved for use elsewhere and returned
* to the caller.
*
* Note that if the array is %NULL terminated this may still return
* %NULL if the length of the array was zero and pdata was not yet
* allocated.
*
* Even if set, the #GDestroyNotify function will never be called
* on the current contents of the array and the caller is
* responsible for freeing the array elements.
@ -1171,8 +1197,9 @@ g_ptr_array_new (void)
* g_assert (chunk_buffer->len == 0);
* ]|
*
* Returns: (transfer full): the element data, which should be
* freed using g_free().
* Returns: (transfer full) (nullable): the element data, which should be
* freed using g_free(). This may be %NULL if the array doesnt have any
* elements (i.e. if `*len` is zero).
*
* Since: 2.64
*/
@ -1215,7 +1242,8 @@ g_ptr_array_steal (GPtrArray *array,
* pointing to) are copied to the new #GPtrArray.
*
* The copy of @array will have the same #GDestroyNotify for its elements as
* @array.
* @array. The copy will also be %NULL terminated if (and only if) the source
* array is.
*
* Returns: (transfer full): a deep copy of the initial #GPtrArray.
*
@ -1226,13 +1254,21 @@ g_ptr_array_copy (GPtrArray *array,
GCopyFunc func,
gpointer user_data)
{
GRealPtrArray *rarray = (GRealPtrArray *) array;
GPtrArray *new_array;
g_return_val_if_fail (array != NULL, NULL);
new_array = ptr_array_new (array->len,
((GRealPtrArray *) array)->element_free_func);
new_array = ptr_array_new (0,
rarray->element_free_func,
rarray->null_terminated);
if (rarray->alloc > 0)
{
g_ptr_array_maybe_expand ((GRealPtrArray *) new_array, array->len + rarray->null_terminated);
if (array->len > 0)
{
if (func != NULL)
{
guint i;
@ -1240,13 +1276,17 @@ g_ptr_array_copy (GPtrArray *array,
for (i = 0; i < array->len; i++)
new_array->pdata[i] = func (array->pdata[i], user_data);
}
else if (array->len > 0)
else
{
memcpy (new_array->pdata, array->pdata,
array->len * sizeof (*array->pdata));
}
new_array->len = array->len;
}
ptr_array_null_terminate (rarray);
}
return new_array;
}
@ -1265,7 +1305,7 @@ g_ptr_array_copy (GPtrArray *array,
GPtrArray*
g_ptr_array_sized_new (guint reserved_size)
{
return ptr_array_new (reserved_size, NULL);
return ptr_array_new (reserved_size, NULL, FALSE);
}
/**
@ -1309,14 +1349,14 @@ g_array_copy (GArray *array)
* either via g_ptr_array_unref(), when g_ptr_array_free() is called with
* @free_segment set to %TRUE or when removing elements.
*
* Returns: A new #GPtrArray
* Returns: (transfer full): A new #GPtrArray
*
* Since: 2.22
*/
GPtrArray*
g_ptr_array_new_with_free_func (GDestroyNotify element_free_func)
{
return ptr_array_new (0, element_free_func);
return ptr_array_new (0, element_free_func, FALSE);
}
/**
@ -1333,7 +1373,7 @@ g_ptr_array_new_with_free_func (GDestroyNotify element_free_func)
* g_ptr_array_unref(), when g_ptr_array_free() is called with
* @free_segment set to %TRUE or when removing elements.
*
* Returns: A new #GPtrArray
* Returns: (transfer full): A new #GPtrArray
*
* Since: 2.30
*/
@ -1341,7 +1381,45 @@ GPtrArray*
g_ptr_array_new_full (guint reserved_size,
GDestroyNotify element_free_func)
{
return ptr_array_new (reserved_size, element_free_func);
return ptr_array_new (reserved_size, element_free_func, FALSE);
}
/**
* g_ptr_array_new_null_terminated:
* @reserved_size: number of pointers preallocated.
* If @null_terminated is %TRUE, the actually allocated
* buffer size is @reserved_size plus 1, unless @reserved_size
* is zero, in which case no initial buffer gets allocated.
* @element_free_func: (nullable): A function to free elements with
* destroy @array or %NULL
* @null_terminated: whether to make the array as %NULL terminated.
*
* Like g_ptr_array_new_full() but also allows to set the array to
* be %NULL terminated. A %NULL terminated pointer array has an
* additional %NULL pointer after the last element, beyond the
* current length.
*
* #GPtrArray created by other constructors are not automatically %NULL
* terminated.
*
* Note that if the @array's length is zero and currently no
* data array is allocated, then pdata will still be %NULL.
* %GPtrArray will only %NULL terminate pdata, if an actual
* array is allocated. It does not guarantee that an array
* is always allocated. In other words, if the length is zero,
* then pdata may either point to a %NULL terminated array of length
* zero or be %NULL.
*
* Returns: (transfer full): A new #GPtrArray
*
* Since: 2.74
*/
GPtrArray *
g_ptr_array_new_null_terminated (guint reserved_size,
GDestroyNotify element_free_func,
gboolean null_terminated)
{
return ptr_array_new (reserved_size, element_free_func, null_terminated);
}
/**
@ -1367,6 +1445,29 @@ g_ptr_array_set_free_func (GPtrArray *array,
rarray->element_free_func = element_free_func;
}
/**
* g_ptr_array_is_null_terminated:
* @array: the #GPtrArray
*
* Gets whether the @array was constructed as %NULL-terminated.
*
* This will only return %TRUE for arrays constructed by passing %TRUE to the
* `null_terminated` argument of g_ptr_array_new_null_terminated(). It will not
* return %TRUE for normal arrays which have had a %NULL element appended to
* them.
*
* Returns: %TRUE if the array is made to be %NULL terminated.
*
* Since: 2.74
*/
gboolean
g_ptr_array_is_null_terminated (GPtrArray *array)
{
g_return_val_if_fail (array, FALSE);
return ((GRealPtrArray *) array)->null_terminated;
}
/**
* g_ptr_array_ref:
* @array: a #GPtrArray
@ -1430,6 +1531,10 @@ g_ptr_array_unref (GPtrArray *array)
* be freed separately if @free_seg is %TRUE and no #GDestroyNotify
* function has been set for @array.
*
* Note that if the array is %NULL terminated and @free_seg is %FALSE
* then this will always return an allocated %NULL terminated buffer.
* If pdata is previously %NULL, a new buffer will be allocated.
*
* This function is not thread-safe. If using a #GPtrArray from multiple
* threads, use only the atomic g_ptr_array_ref() and g_ptr_array_unref()
* functions.
@ -1485,7 +1590,11 @@ ptr_array_free (GPtrArray *array,
segment = NULL;
}
else
{
segment = rarray->pdata;
if (!segment && rarray->null_terminated)
segment = (gpointer *) g_new0 (char *, 1);
}
if (flags & PRESERVE_WRAPPER)
{
@ -1556,7 +1665,13 @@ g_ptr_array_set_size (GPtrArray *array,
if (length_unsigned > rarray->len)
{
guint i;
g_ptr_array_maybe_expand (rarray, (length_unsigned - rarray->len));
if (G_UNLIKELY (rarray->null_terminated) &&
length_unsigned - rarray->len > G_MAXUINT - 1)
g_error ("array would overflow");
g_ptr_array_maybe_expand (rarray, (length_unsigned - rarray->len) + rarray->null_terminated);
/* This is not
* memset (array->pdata + array->len, 0,
* sizeof (gpointer) * (length_unsigned - array->len));
@ -1565,11 +1680,13 @@ g_ptr_array_set_size (GPtrArray *array,
*/
for (i = rarray->len; i < length_unsigned; i++)
rarray->pdata[i] = NULL;
rarray->len = length_unsigned;
ptr_array_null_terminate (rarray);
}
else if (length_unsigned < rarray->len)
g_ptr_array_remove_range (array, length_unsigned, rarray->len - length_unsigned);
rarray->len = length_unsigned;
}
static gpointer
@ -1599,7 +1716,7 @@ ptr_array_remove_index (GPtrArray *array,
rarray->len -= 1;
if (G_UNLIKELY (g_mem_gc_friendly))
if (rarray->null_terminated || G_UNLIKELY (g_mem_gc_friendly))
rarray->pdata[rarray->len] = NULL;
return result;
@ -1715,7 +1832,10 @@ g_ptr_array_remove_range (GPtrArray *array,
g_return_val_if_fail (rarray != NULL, NULL);
g_return_val_if_fail (rarray->len == 0 || (rarray->len != 0 && rarray->pdata != NULL), NULL);
g_return_val_if_fail (index_ <= rarray->len, NULL);
g_return_val_if_fail (index_ + length <= rarray->len, NULL);
g_return_val_if_fail (length == 0 || index_ + length <= rarray->len, NULL);
if (length == 0)
return array;
if (rarray->element_free_func != NULL)
{
@ -1736,6 +1856,8 @@ g_ptr_array_remove_range (GPtrArray *array,
for (i = 0; i < length; i++)
rarray->pdata[rarray->len + i] = NULL;
}
else
ptr_array_null_terminate (rarray);
return array;
}
@ -1832,9 +1954,11 @@ g_ptr_array_add (GPtrArray *array,
g_return_if_fail (rarray);
g_return_if_fail (rarray->len == 0 || (rarray->len != 0 && rarray->pdata != NULL));
g_ptr_array_maybe_expand (rarray, 1);
g_ptr_array_maybe_expand (rarray, 1u + rarray->null_terminated);
rarray->pdata[rarray->len++] = data;
ptr_array_null_terminate (rarray);
}
/**
@ -1857,6 +1981,8 @@ g_ptr_array_add (GPtrArray *array,
* If @func is %NULL, then only the pointers (and not what they are
* pointing to) are copied to the new #GPtrArray.
*
* Whether @array_to_extend is %NULL terminated stays unchanged by this function.
*
* Since: 2.62
**/
void
@ -1870,7 +1996,14 @@ g_ptr_array_extend (GPtrArray *array_to_extend,
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 (array->len == 0u)
return;
if (G_UNLIKELY (array->len == G_MAXUINT) &&
rarray_to_extend->null_terminated)
g_error ("adding %u to array would overflow", array->len);
g_ptr_array_maybe_expand (rarray_to_extend, array->len + rarray_to_extend->null_terminated);
if (func != NULL)
{
@ -1887,6 +2020,8 @@ g_ptr_array_extend (GPtrArray *array_to_extend,
}
rarray_to_extend->len += array->len;
ptr_array_null_terminate (rarray_to_extend);
}
/**
@ -1944,7 +2079,7 @@ g_ptr_array_insert (GPtrArray *array,
g_return_if_fail (index_ >= -1);
g_return_if_fail (index_ <= (gint)rarray->len);
g_ptr_array_maybe_expand (rarray, 1);
g_ptr_array_maybe_expand (rarray, 1u + rarray->null_terminated);
if (index_ < 0)
index_ = rarray->len;
@ -1956,6 +2091,8 @@ g_ptr_array_insert (GPtrArray *array,
rarray->len++;
rarray->pdata[index_] = data;
ptr_array_null_terminate (rarray);
}
/* Please keep this doc-comment in sync with pointer_array_sort_example()

View File

@ -154,6 +154,10 @@ GPtrArray* g_ptr_array_sized_new (guint reserved_size);
GLIB_AVAILABLE_IN_ALL
GPtrArray* g_ptr_array_new_full (guint reserved_size,
GDestroyNotify element_free_func);
GLIB_AVAILABLE_IN_2_74
GPtrArray* g_ptr_array_new_null_terminated (guint reserved_size,
GDestroyNotify element_free_func,
gboolean null_terminated);
GLIB_AVAILABLE_IN_ALL
gpointer* g_ptr_array_free (GPtrArray *array,
gboolean free_seg);
@ -225,6 +229,8 @@ gboolean g_ptr_array_find_with_equal_func (GPtrArray *haystack,
GEqualFunc equal_func,
guint *index_);
GLIB_AVAILABLE_IN_2_74
gboolean g_ptr_array_is_null_terminated (GPtrArray *array);
/* Byte arrays, an array of guint8. Implemented as a GArray,
* but type-safe.

View File

@ -886,6 +886,19 @@ array_overflow_set_size (void)
}
}
static void
assert_ptr_array_null_terminated (GPtrArray *array, gboolean null_terminated)
{
g_assert_cmpint (null_terminated, ==, g_ptr_array_is_null_terminated (array));
if (array->pdata)
{
if (null_terminated)
g_assert_null (array->pdata[array->len]);
}
else
g_assert_cmpint (array->len, ==, 0);
}
/* Check g_ptr_array_steal() function */
static void
pointer_array_steal (void)
@ -927,6 +940,30 @@ pointer_array_steal (void)
g_free (pdata);
g_ptr_array_free (gparray, TRUE);
gparray = g_ptr_array_new_null_terminated (0, NULL, TRUE);
pdata = g_ptr_array_steal (gparray, NULL);
g_assert_null (pdata);
g_ptr_array_unref (gparray);
}
static void
pointer_array_free_null_terminated (void)
{
GPtrArray *parray = NULL;
gpointer *segment;
g_test_summary ("Check that g_ptr_array_free() on an empty array returns a NULL-terminated empty array");
parray = g_ptr_array_new_null_terminated (0, NULL, TRUE);
g_assert_nonnull (parray);
assert_ptr_array_null_terminated (parray, TRUE);
segment = g_ptr_array_free (parray, FALSE);
g_assert_nonnull (segment);
g_assert_null (segment[0]);
g_free (segment);
}
static void
@ -977,16 +1014,26 @@ pointer_array_insert (void)
}
static void
pointer_array_ref_count (void)
pointer_array_ref_count (gconstpointer test_data)
{
const gboolean null_terminated = GPOINTER_TO_INT (test_data);
GPtrArray *gparray;
GPtrArray *gparray2;
gint i;
gint sum = 0;
if (null_terminated)
gparray = g_ptr_array_new_null_terminated (0, NULL, null_terminated);
else
gparray = g_ptr_array_new ();
assert_ptr_array_null_terminated (gparray, null_terminated);
for (i = 0; i < 10000; i++)
{
g_ptr_array_add (gparray, GINT_TO_POINTER (i));
assert_ptr_array_null_terminated (gparray, null_terminated);
}
/* check we can ref, unref and still access the array */
gparray2 = g_ptr_array_ref (gparray);
@ -995,6 +1042,8 @@ pointer_array_ref_count (void)
for (i = 0; i < 10000; i++)
g_assert (g_ptr_array_index (gparray, i) == GINT_TO_POINTER (i));
assert_ptr_array_null_terminated (gparray, null_terminated);
g_ptr_array_foreach (gparray, sum_up, &sum);
g_assert (sum == 49995000);
@ -1003,6 +1052,8 @@ pointer_array_ref_count (void)
g_ptr_array_free (gparray, TRUE);
g_assert_cmpint (gparray2->len, ==, 0);
assert_ptr_array_null_terminated (gparray, null_terminated);
g_ptr_array_unref (gparray2);
}
@ -1108,8 +1159,9 @@ ptr_array_copy_func (gconstpointer src, gpointer userdata)
/* Test the g_ptr_array_copy() function */
static void
pointer_array_copy (void)
pointer_array_copy (gconstpointer test_data)
{
const gboolean null_terminated = GPOINTER_TO_INT (test_data);
GPtrArray *ptr_array, *ptr_array2;
gsize i;
const gsize array_size = 100;
@ -1134,16 +1186,18 @@ pointer_array_copy (void)
array_test[i] = i;
/* Test copy an empty array */
ptr_array = g_ptr_array_sized_new (0);
ptr_array = g_ptr_array_new_null_terminated (0, NULL, null_terminated);
ptr_array2 = g_ptr_array_copy (ptr_array, NULL, NULL);
g_assert_cmpuint (ptr_array2->len, ==, ptr_array->len);
assert_ptr_array_null_terminated (ptr_array, null_terminated);
assert_ptr_array_null_terminated (ptr_array2, null_terminated);
g_ptr_array_unref (ptr_array);
g_ptr_array_unref (ptr_array2);
/* Test simple copy */
ptr_array = g_ptr_array_sized_new (array_size);
ptr_array = g_ptr_array_new_null_terminated (array_size, NULL, null_terminated);
for (i = 0; i < array_size; i++)
g_ptr_array_add (ptr_array, &array_test[i]);
@ -1158,6 +1212,9 @@ pointer_array_copy (void)
g_assert_cmpuint ((gsize) g_ptr_array_index (ptr_array, i), ==,
(gsize) g_ptr_array_index (ptr_array2, i));
assert_ptr_array_null_terminated (ptr_array, null_terminated);
assert_ptr_array_null_terminated (ptr_array2, null_terminated);
g_ptr_array_free (ptr_array2, TRUE);
/* Test copy through GCopyFunc */
@ -1172,6 +1229,9 @@ pointer_array_copy (void)
g_assert_cmpuint ((gsize) g_ptr_array_index (ptr_array, i), !=,
(gsize) g_ptr_array_index (ptr_array2, i));
assert_ptr_array_null_terminated (ptr_array, null_terminated);
assert_ptr_array_null_terminated (ptr_array2, null_terminated);
g_ptr_array_free (ptr_array2, TRUE);
/* Final cleanup */
@ -1181,8 +1241,9 @@ pointer_array_copy (void)
/* Test the g_ptr_array_extend() function */
static void
pointer_array_extend (void)
pointer_array_extend (gconstpointer test_data)
{
gboolean null_terminated = GPOINTER_TO_INT (test_data);
GPtrArray *ptr_array, *ptr_array2;
gsize i;
const gsize array_size = 100;
@ -1210,20 +1271,23 @@ pointer_array_extend (void)
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);
ptr_array = g_ptr_array_new_null_terminated (0, NULL, null_terminated);
ptr_array2 = g_ptr_array_new_null_terminated (0, NULL, null_terminated);
g_ptr_array_extend (ptr_array, ptr_array2, NULL, NULL);
g_assert_cmpuint (ptr_array->len, ==, 0);
g_assert_cmpuint (ptr_array2->len, ==, 0);
assert_ptr_array_null_terminated (ptr_array, null_terminated);
assert_ptr_array_null_terminated (ptr_array2, null_terminated);
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);
ptr_array = g_ptr_array_new_null_terminated (array_size, NULL, null_terminated);
ptr_array2 = g_ptr_array_new_null_terminated (0, NULL, null_terminated);
for (i = 0; i < array_size; i++)
{
@ -1235,12 +1299,15 @@ pointer_array_extend (void)
for (i = 0; i < array_size; i++)
g_assert_cmpuint (*((gsize *) g_ptr_array_index (ptr_array, i)), ==, i);
assert_ptr_array_null_terminated (ptr_array, null_terminated);
assert_ptr_array_null_terminated (ptr_array2, null_terminated);
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);
ptr_array = g_ptr_array_new_null_terminated (0, NULL, null_terminated);
ptr_array2 = g_ptr_array_new_null_terminated (array_size, NULL, null_terminated);
for (i = 0; i < array_size; i++)
{
@ -1252,12 +1319,15 @@ pointer_array_extend (void)
for (i = 0; i < array_size; i++)
g_assert_cmpuint (*((gsize *) g_ptr_array_index (ptr_array, i)), ==, i);
assert_ptr_array_null_terminated (ptr_array, null_terminated);
assert_ptr_array_null_terminated (ptr_array2, null_terminated);
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);
ptr_array = g_ptr_array_new_null_terminated (array_size / 2, NULL, null_terminated);
ptr_array2 = g_ptr_array_new_null_terminated (array_size / 2, NULL, null_terminated);
for (i = 0; i < array_size / 2; i++)
{
@ -1270,12 +1340,15 @@ pointer_array_extend (void)
for (i = 0; i < array_size; i++)
g_assert_cmpuint (*((gsize *) g_ptr_array_index (ptr_array, i)), ==, i);
assert_ptr_array_null_terminated (ptr_array, null_terminated);
assert_ptr_array_null_terminated (ptr_array2, null_terminated);
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);
ptr_array = g_ptr_array_new_null_terminated (array_size / 2, NULL, null_terminated);
ptr_array2 = g_ptr_array_new_null_terminated (array_size / 2, NULL, null_terminated);
for (i = 0; i < array_size / 2; i++)
{
@ -1288,6 +1361,9 @@ pointer_array_extend (void)
for (i = 0; i < array_size; i++)
g_assert_cmpuint (*((gsize *) g_ptr_array_index (ptr_array, i)), ==, i);
assert_ptr_array_null_terminated (ptr_array, null_terminated);
assert_ptr_array_null_terminated (ptr_array2, null_terminated);
/* Clean-up memory */
for (i = array_size / 2; i < array_size; i++)
g_free (g_ptr_array_index (ptr_array, i));
@ -1631,6 +1707,17 @@ pointer_array_find_non_empty (void)
g_ptr_array_free (array, TRUE);
}
static void
pointer_array_remove_range (void)
{
GPtrArray *parray = NULL;
/* Try removing an empty range. */
parray = g_ptr_array_new ();
g_ptr_array_remove_range (parray, 0, 0);
g_ptr_array_unref (parray);
}
static void
steal_destroy_notify (gpointer data)
{
@ -1641,19 +1728,32 @@ steal_destroy_notify (gpointer data)
/* Test that g_ptr_array_steal_index() and g_ptr_array_steal_index_fast() can
* remove elements from a pointer array without the #GDestroyNotify being called. */
static void
pointer_array_steal_index (void)
pointer_array_steal_index (gconstpointer test_data)
{
const gboolean null_terminated = GPOINTER_TO_INT (test_data);
guint i1 = 0, i2 = 0, i3 = 0, i4 = 0;
gpointer out1, out2;
GPtrArray *array = g_ptr_array_new_with_free_func (steal_destroy_notify);
GPtrArray *array;
if (null_terminated)
array = g_ptr_array_new_null_terminated (0, steal_destroy_notify, null_terminated);
else
array = g_ptr_array_new_with_free_func (steal_destroy_notify);
assert_ptr_array_null_terminated (array, null_terminated);
g_ptr_array_add (array, &i1);
g_ptr_array_add (array, &i2);
assert_ptr_array_null_terminated (array, null_terminated);
g_ptr_array_add (array, &i3);
g_ptr_array_add (array, &i4);
g_assert_cmpuint (array->len, ==, 4);
assert_ptr_array_null_terminated (array, null_terminated);
/* Remove a single element. */
out1 = g_ptr_array_steal_index (array, 0);
g_assert_true (out1 == &i1);
@ -1665,6 +1765,8 @@ pointer_array_steal_index (void)
g_assert_true (g_ptr_array_index (array, 1) == &i3);
g_assert_true (g_ptr_array_index (array, 2) == &i4);
assert_ptr_array_null_terminated (array, null_terminated);
/* Remove another element, quickly. */
out2 = g_ptr_array_steal_index_fast (array, 0);
g_assert_true (out2 == &i2);
@ -1675,6 +1777,8 @@ pointer_array_steal_index (void)
g_assert_true (g_ptr_array_index (array, 0) == &i4);
g_assert_true (g_ptr_array_index (array, 1) == &i3);
assert_ptr_array_null_terminated (array, null_terminated);
/* Check that destroying the pointer array doesnt affect the stolen elements. */
g_ptr_array_unref (array);
@ -2079,12 +2183,16 @@ main (int argc, char *argv[])
}
/* pointer arrays */
g_test_add_func ("/pointerarray/free/null-terminated", pointer_array_free_null_terminated);
g_test_add_func ("/pointerarray/add", pointer_array_add);
g_test_add_func ("/pointerarray/insert", pointer_array_insert);
g_test_add_func ("/pointerarray/ref-count", 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_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_data_func ("/pointerarray/array_copy/not-null-terminated", GINT_TO_POINTER (0), pointer_array_copy);
g_test_add_data_func ("/pointerarray/array_copy/null-terminated", GINT_TO_POINTER (1), pointer_array_copy);
g_test_add_data_func ("/pointerarray/array_extend/not-null-terminated", GINT_TO_POINTER (0), pointer_array_extend);
g_test_add_data_func ("/pointerarray/array_extend/null-terminated", GINT_TO_POINTER (1), 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/example", pointer_array_sort_example);
@ -2092,8 +2200,10 @@ main (int argc, char *argv[])
g_test_add_func ("/pointerarray/sort-with-data/example", pointer_array_sort_with_data_example);
g_test_add_func ("/pointerarray/find/empty", pointer_array_find_empty);
g_test_add_func ("/pointerarray/find/non-empty", pointer_array_find_non_empty);
g_test_add_func ("/pointerarray/remove-range", pointer_array_remove_range);
g_test_add_func ("/pointerarray/steal", pointer_array_steal);
g_test_add_func ("/pointerarray/steal_index", pointer_array_steal_index);
g_test_add_data_func ("/pointerarray/steal_index/not-null-terminated", GINT_TO_POINTER (0), pointer_array_steal_index);
g_test_add_data_func ("/pointerarray/steal_index/null-terminated", GINT_TO_POINTER (1), pointer_array_steal_index);
/* byte arrays */
g_test_add_func ("/bytearray/steal", byte_array_steal);