summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Withnall <withnall@endlessm.com>2018-04-19 14:54:41 +0100
committerPhilip Withnall <withnall@endlessm.com>2018-05-09 13:52:05 +0100
commitd0a48f26c765b7f5a3aa26773b7d1475a1643f1c (patch)
tree2befd8733faa59eb42b8a26c0158ca78e86cc6da
parente6200eaea2b97380162f59555f35d45a1b626ed2 (diff)
downloadglib-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.c51
-rw-r--r--glib/garray.h6
-rw-r--r--glib/tests/array-test.c54
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);