Add g_array_steal(), g_ptr_array_steal() and g_byte_array_steal()

Closes issue #285
This commit is contained in:
Paolo Bonzini 2019-07-30 19:22:05 +02:00 committed by Emmanuel Fleury
parent c08e7b9364
commit 7bada8394d
4 changed files with 258 additions and 1 deletions

View File

@ -2805,6 +2805,7 @@ g_string_chunk_free
<FILE>arrays</FILE>
GArray
g_array_new
g_array_steal
g_array_sized_new
g_array_copy
g_array_ref
@ -2833,6 +2834,7 @@ g_array_free
<FILE>arrays_pointer</FILE>
GPtrArray
g_ptr_array_new
g_ptr_array_steal
g_ptr_array_sized_new
g_ptr_array_new_with_free_func
g_ptr_array_copy
@ -2868,6 +2870,7 @@ g_ptr_array_find_with_equal_func
<SUBSECTION>
GByteArray
g_byte_array_new
g_byte_array_steal
g_byte_array_new_take
g_byte_array_sized_new
g_byte_array_ref

View File

@ -165,6 +165,57 @@ g_array_new (gboolean zero_terminated,
return g_array_sized_new (zero_terminated, clear, elt_size, 0);
}
/**
* g_array_steal:
* @array: a #GArray.
* @len: (optional) (out caller-allocates): pointer to retrieve the number of
* elements of the original array
*
* Frees the data in the array and resets the size to zero, while
* the underlying array is preserved for use elsewhere and returned
* to the caller.
*
* If the array was created with the @zero_terminate property
* set to %TRUE, the returned data is zero terminated too.
*
* If array elements contain dynamically-allocated memory,
* the array elements should also be freed by the caller.
*
* A short example of use:
* |[<!-- language="C" -->
* ...
* gpointer data;
* gsize data_len;
* data = g_array_steal (some_array, &data_len);
* ...
* ]|
* Returns: (transfer full): the element data, which should be
* freed using g_free().
*
* Since: 2.64
*/
gpointer
g_array_steal (GArray *array,
gsize *len)
{
GRealArray *rarray;
gpointer segment;
g_return_val_if_fail (array != NULL, NULL);
rarray = (GRealArray *) array;
segment = (gpointer) rarray->data;
if (len != NULL)
*len = rarray->len;
rarray->data = NULL;
rarray->len = 0;
rarray->alloc = 0;
return segment;
}
/**
* g_array_sized_new:
* @zero_terminated: %TRUE if the array should have an extra element at
@ -1013,6 +1064,46 @@ g_ptr_array_new (void)
return g_ptr_array_sized_new (0);
}
/**
* g_ptr_array_steal:
* @array: a #GPtrArray.
* @len: (optional) (out caller-allocates): pointer to retrieve the number of
* elements of the original array
*
* Frees the data in the array and resets the size to zero, while
* the underlying array is preserved for use elsewhere and returned
* to the caller.
*
* 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.
*
* Returns: (transfer full): the element data, which should be
* freed using g_free().
*
* Since: 2.64
*/
gpointer *
g_ptr_array_steal (GPtrArray *array,
gsize *len)
{
GRealPtrArray *rarray;
gpointer *segment;
g_return_val_if_fail (array != NULL, NULL);
rarray = (GRealPtrArray *) array;
segment = (gpointer *) rarray->pdata;
if (len != NULL)
*len = rarray->len;
rarray->pdata = NULL;
rarray->len = 0;
rarray->alloc = 0;
return segment;
}
/**
* g_ptr_array_copy:
* @array: #GPtrArray to duplicate
@ -2002,6 +2093,28 @@ g_byte_array_new (void)
return (GByteArray *)g_array_sized_new (FALSE, FALSE, 1, 0);
}
/**
* g_byte_array_steal:
* @array: a #GByteArray.
* @len: (optional) (out caller-allocates): pointer to retrieve the number of
* elements of the original array
*
* Frees the data in the array and resets the size to zero, while
* the underlying array is preserved for use elsewhere and returned
* to the caller.
*
* Returns: (transfer full): the element data, which should be
* freed using g_free().
*
* Since: 2.64
*/
guint8 *
g_byte_array_steal (GByteArray *array,
gsize *len)
{
return (guint8 *) g_array_steal ((GArray *) array, len);
}
/**
* g_byte_array_new_take:
* @data: (transfer full) (array length=len): byte data for the array

View File

@ -70,6 +70,9 @@ GLIB_AVAILABLE_IN_ALL
GArray* g_array_new (gboolean zero_terminated,
gboolean clear_,
guint element_size);
GLIB_AVAILABLE_IN_2_64
gpointer g_array_steal (GArray *array,
gsize *len);
GLIB_AVAILABLE_IN_ALL
GArray* g_array_sized_new (gboolean zero_terminated,
gboolean clear_,
@ -137,6 +140,9 @@ 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_64
gpointer* g_ptr_array_steal (GPtrArray *array,
gsize *len);
GLIB_AVAILABLE_IN_2_62
GPtrArray *g_ptr_array_copy (GPtrArray *array,
GCopyFunc func,
@ -227,6 +233,9 @@ GByteArray* g_byte_array_new (void);
GLIB_AVAILABLE_IN_ALL
GByteArray* g_byte_array_new_take (guint8 *data,
gsize len);
GLIB_AVAILABLE_IN_2_64
guint8* g_byte_array_steal (GByteArray *array,
gsize *len);
GLIB_AVAILABLE_IN_ALL
GByteArray* g_byte_array_sized_new (guint reserved_size);
GLIB_AVAILABLE_IN_ALL

View File

@ -140,6 +140,57 @@ array_new_zero_terminated (void)
g_free (out_str);
}
/* Check g_array_steal() function */
static void
array_steal (void)
{
const guint array_size = 10000;
GArray *garray;
gint *adata;
guint i;
gsize len, past_len;
garray = g_array_new (FALSE, FALSE, sizeof (gint));
adata = (gint *) g_array_steal (garray, NULL);
g_assert_null (adata);
adata = (gint *) g_array_steal (garray, &len);
g_assert_null (adata);
g_assert_cmpint (len, ==, 0);
for (i = 0; i < array_size; i++)
g_array_append_val (garray, i);
for (i = 0; i < array_size; i++)
g_assert_cmpint (g_array_index (garray, gint, i), ==, i);
past_len = garray->len;
adata = (gint *) g_array_steal (garray, &len);
for (i = 0; i < array_size; i++)
g_assert_cmpint (adata[i], ==, i);
g_assert_cmpint (past_len, ==, len);
g_assert_cmpint (garray->len, ==, 0);
g_array_append_val (garray, i);
g_assert_cmpint (adata[0], ==, 0);
g_assert_cmpint (g_array_index (garray, gint, 0), ==, array_size);
g_assert_cmpint (garray->len, ==, 1);
g_array_remove_index (garray, 0);
for (i = 0; i < array_size; i++)
g_array_append_val (garray, i);
g_assert_cmpint (garray->len, ==, array_size);
g_assert_cmpmem (adata, array_size * sizeof (gint),
garray->data, array_size * sizeof (gint));
g_free (adata);
g_array_free (garray, TRUE);
}
/* Check that g_array_append_val() works correctly for various #GArray
* configurations. */
static void
@ -760,6 +811,49 @@ test_array_binary_search (void)
g_array_free (garray, TRUE);
}
/* Check g_ptr_array_steal() function */
static void
pointer_array_steal (void)
{
const guint array_size = 10000;
GPtrArray *gparray;
gpointer *pdata;
guint i;
gsize len, past_len;
gparray = g_ptr_array_new ();
pdata = g_ptr_array_steal (gparray, NULL);
g_assert_null (pdata);
pdata = g_ptr_array_steal (gparray, &len);
g_assert_null (pdata);
g_assert_cmpint (len, ==, 0);
for (i = 0; i < array_size; i++)
g_ptr_array_add (gparray, GINT_TO_POINTER (i));
past_len = gparray->len;
pdata = g_ptr_array_steal (gparray, &len);
g_assert_cmpint (gparray->len, ==, 0);
g_assert_cmpint (past_len, ==, len);
g_ptr_array_add (gparray, GINT_TO_POINTER (10));
g_assert_cmpint ((gsize) pdata[0], ==, (gsize) GINT_TO_POINTER (0));
g_assert_cmpint ((gsize) g_ptr_array_index (gparray, 0), ==,
(gsize) GINT_TO_POINTER (10));
g_assert_cmpint (gparray->len, ==, 1);
g_ptr_array_remove_index (gparray, 0);
for (i = 0; i < array_size; i++)
g_ptr_array_add (gparray, GINT_TO_POINTER (i));
g_assert_cmpmem (pdata, array_size * sizeof (gpointer),
gparray->pdata, array_size * sizeof (gpointer));
g_free (pdata);
g_ptr_array_free (gparray, TRUE);
}
static void
pointer_array_add (void)
{
@ -1318,7 +1412,7 @@ 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 (void)
pointer_array_steal_index (void)
{
guint i1 = 0, i2 = 0, i3 = 0, i4 = 0;
gpointer out1, out2;
@ -1361,6 +1455,41 @@ pointer_array_steal (void)
g_assert_cmpuint (i4, ==, 1);
}
static void
byte_array_steal (void)
{
const guint array_size = 10000;
GByteArray *gbarray;
guint8 *bdata;
guint i;
gsize len, past_len;
gbarray = g_byte_array_new ();
bdata = g_byte_array_steal (gbarray, NULL);
g_assert_cmpint ((gsize) bdata, ==, (gsize) gbarray->data);
g_free (bdata);
for (i = 0; i < array_size; i++)
g_byte_array_append (gbarray, (guint8 *) "abcd", 4);
past_len = gbarray->len;
bdata = g_byte_array_steal (gbarray, &len);
g_assert_cmpint (len, ==, past_len);
g_assert_cmpint (gbarray->len, ==, 0);
g_byte_array_append (gbarray, (guint8 *) "@", 1);
g_assert_cmpint (bdata[0], ==, 'a');
g_assert_cmpint (gbarray->data[0], ==, '@');
g_assert_cmpint (gbarray->len, ==, 1);
g_byte_array_remove_index (gbarray, 0);
g_free (bdata);
g_byte_array_free (gbarray, TRUE);
}
static void
byte_array_append (void)
{
@ -1679,6 +1808,7 @@ main (int argc, char *argv[])
/* array tests */
g_test_add_func ("/array/new/zero-terminated", array_new_zero_terminated);
g_test_add_func ("/array/ref-count", array_ref_count);
g_test_add_func ("/array/steal", array_steal);
g_test_add_func ("/array/clear-func", array_clear_func);
g_test_add_func ("/array/binary-search", test_array_binary_search);
@ -1711,8 +1841,10 @@ main (int argc, char *argv[])
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/steal", pointer_array_steal);
g_test_add_func ("/pointerarray/steal_index", pointer_array_steal_index);
/* byte arrays */
g_test_add_func ("/bytearray/steal", byte_array_steal);
g_test_add_func ("/bytearray/append", byte_array_append);
g_test_add_func ("/bytearray/prepend", byte_array_prepend);
g_test_add_func ("/bytearray/remove", byte_array_remove);