diff options
author | Philip Withnall <withnall@endlessm.com> | 2018-04-19 14:54:41 +0100 |
---|---|---|
committer | Philip Withnall <withnall@endlessm.com> | 2018-05-09 13:52:05 +0100 |
commit | d0a48f26c765b7f5a3aa26773b7d1475a1643f1c (patch) | |
tree | 2befd8733faa59eb42b8a26c0158ca78e86cc6da | |
parent | e6200eaea2b97380162f59555f35d45a1b626ed2 (diff) | |
download | glib-d0a48f26c765b7f5a3aa26773b7d1475a1643f1c.tar.gz |
garray: Add g_ptr_array_steal_index*() functions
These make it easy to steal elements from pointer arrays without having
the array’s GDestroyNotify called on them, similarly to what’s possible
with g_hash_table_steal().
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=795376
-rw-r--r-- | glib/garray.c | 51 | ||||
-rw-r--r-- | glib/garray.h | 6 | ||||
-rw-r--r-- | glib/tests/array-test.c | 54 |
3 files changed, 107 insertions, 4 deletions
diff --git a/glib/garray.c b/glib/garray.c index d8f96db90..914eaee34 100644 --- a/glib/garray.c +++ b/glib/garray.c @@ -1194,7 +1194,8 @@ g_ptr_array_set_size (GPtrArray *array, static gpointer ptr_array_remove_index (GPtrArray *array, guint index_, - gboolean fast) + gboolean fast, + gboolean free_element) { GRealPtrArray *rarray = (GRealPtrArray *) array; gpointer result; @@ -1206,7 +1207,7 @@ ptr_array_remove_index (GPtrArray *array, result = rarray->pdata[index_]; - if (rarray->element_free_func != NULL) + if (rarray->element_free_func != NULL && free_element) rarray->element_free_func (rarray->pdata[index_]); if (index_ != rarray->len - 1 && !fast) @@ -1240,7 +1241,7 @@ gpointer g_ptr_array_remove_index (GPtrArray *array, guint index_) { - return ptr_array_remove_index (array, index_, FALSE); + return ptr_array_remove_index (array, index_, FALSE, TRUE); } /** @@ -1262,7 +1263,49 @@ gpointer g_ptr_array_remove_index_fast (GPtrArray *array, guint index_) { - return ptr_array_remove_index (array, index_, TRUE); + return ptr_array_remove_index (array, index_, TRUE, TRUE); +} + +/** + * g_ptr_array_steal_index: + * @array: a #GPtrArray + * @index_: the index of the pointer to steal + * + * Removes the pointer at the given index from the pointer array. + * The following elements are moved down one place. The #GDestroyNotify for + * @array is *not* called on the removed element; ownership is transferred to + * the caller of this function. + * + * Returns: (transfer full) (nullable): the pointer which was removed + * Since: 2.58 + */ +gpointer +g_ptr_array_steal_index (GPtrArray *array, + guint index_) +{ + return ptr_array_remove_index (array, index_, FALSE, FALSE); +} + +/** + * g_ptr_array_steal_index_fast: + * @array: a #GPtrArray + * @index_: the index of the pointer to steal + * + * Removes the pointer at the given index from the pointer array. + * The last element in the array is used to fill in the space, so + * this function does not preserve the order of the array. But it + * is faster than g_ptr_array_steal_index(). The #GDestroyNotify for @array is + * *not* called on the removed element; ownership is transferred to the caller + * of this function. + * + * Returns: (transfer full) (nullable): the pointer which was removed + * Since: 2.58 + */ +gpointer +g_ptr_array_steal_index_fast (GPtrArray *array, + guint index_) +{ + return ptr_array_remove_index (array, index_, TRUE, FALSE); } /** diff --git a/glib/garray.h b/glib/garray.h index 3490f14f0..6c8c2c363 100644 --- a/glib/garray.h +++ b/glib/garray.h @@ -154,6 +154,12 @@ gpointer g_ptr_array_remove_index (GPtrArray *array, GLIB_AVAILABLE_IN_ALL gpointer g_ptr_array_remove_index_fast (GPtrArray *array, guint index_); +GLIB_AVAILABLE_IN_2_58 +gpointer g_ptr_array_steal_index (GPtrArray *array, + guint index_); +GLIB_AVAILABLE_IN_2_58 +gpointer g_ptr_array_steal_index_fast (GPtrArray *array, + guint index_); GLIB_AVAILABLE_IN_ALL gboolean g_ptr_array_remove (GPtrArray *array, gpointer data); diff --git a/glib/tests/array-test.c b/glib/tests/array-test.c index 64b996fb8..8c0872aef 100644 --- a/glib/tests/array-test.c +++ b/glib/tests/array-test.c @@ -659,6 +659,59 @@ pointer_array_find_non_empty (void) } static void +steal_destroy_notify (gpointer data) +{ + guint *counter = data; + *counter = *counter + 1; +} + +/* 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) +{ + guint i1 = 0, i2 = 0, i3 = 0, i4 = 0; + gpointer out1, out2; + GPtrArray *array = g_ptr_array_new_with_free_func (steal_destroy_notify); + + g_ptr_array_add (array, &i1); + g_ptr_array_add (array, &i2); + g_ptr_array_add (array, &i3); + g_ptr_array_add (array, &i4); + + g_assert_cmpuint (array->len, ==, 4); + + /* Remove a single element. */ + out1 = g_ptr_array_steal_index (array, 0); + g_assert_true (out1 == &i1); + g_assert_cmpuint (i1, ==, 0); /* should not have been destroyed */ + + /* Following elements should have been moved down. */ + g_assert_cmpuint (array->len, ==, 3); + g_assert_true (g_ptr_array_index (array, 0) == &i2); + g_assert_true (g_ptr_array_index (array, 1) == &i3); + g_assert_true (g_ptr_array_index (array, 2) == &i4); + + /* Remove another element, quickly. */ + out2 = g_ptr_array_steal_index_fast (array, 0); + g_assert_true (out2 == &i2); + g_assert_cmpuint (i2, ==, 0); /* should not have been destroyed */ + + /* Last element should have been swapped in place. */ + g_assert_cmpuint (array->len, ==, 2); + g_assert_true (g_ptr_array_index (array, 0) == &i4); + g_assert_true (g_ptr_array_index (array, 1) == &i3); + + /* Check that destroying the pointer array doesn’t affect the stolen elements. */ + g_ptr_array_unref (array); + + g_assert_cmpuint (i1, ==, 0); + g_assert_cmpuint (i2, ==, 0); + g_assert_cmpuint (i3, ==, 1); + g_assert_cmpuint (i4, ==, 1); +} + +static void byte_array_append (void) { GByteArray *gbarray; @@ -970,6 +1023,7 @@ main (int argc, char *argv[]) g_test_add_func ("/pointerarray/sort-with-data", pointer_array_sort_with_data); 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); /* byte arrays */ g_test_add_func ("/bytearray/append", byte_array_append); |