array: Add a clear function

Like GPtrArray has a "free function" that can be used to free memory
associated to each pointer in the array, GArray would benefit from
having a "clear function" that can be used to clear the content of
each element of the array when it's removed, or when the entire array
is freed.

https://bugzilla.gnome.org/show_bug.cgi?id=667243
This commit is contained in:
Emmanuele Bassi 2012-01-04 07:41:47 +00:00 committed by Matthias Clasen
parent 030b3f25e3
commit c602a5f887
5 changed files with 103 additions and 10 deletions

View File

@ -2354,6 +2354,7 @@ g_array_sort
g_array_sort_with_data
g_array_index
g_array_set_size
g_array_set_clear_func
g_array_free
</SECTION>

View File

@ -110,6 +110,7 @@ struct _GRealArray
guint zero_terminated : 1;
guint clear : 1;
gint ref_count;
GDestroyNotify clear_func;
};
/**
@ -210,6 +211,34 @@ GArray* g_array_sized_new (gboolean zero_terminated,
return (GArray*) array;
}
/**
* g_array_set_clear_func:
* @array: A #GArray
* @clear_func: a function to clear an element of @array
*
* Sets a function to clear an element of @array.
*
* The @clear_func will be called when an element in the array
* data segment is removed and when the array is freed and data
* segment is deallocated as well.
*
* Note that in contrast with other uses of #GDestroyNotify
* functions, @clear_func is expected to clear the contents of
* the array element it is given, but not free the element itself.
*
* Since: 2.32
*/
void
g_array_set_clear_func (GArray *array,
GDestroyNotify clear_func)
{
GRealArray *rarray = (GRealArray *) array;
g_return_if_fail (array != NULL);
rarray->clear_func = clear_func;
}
/**
* g_array_ref:
* @array: A #GArray.
@ -325,6 +354,14 @@ array_free (GRealArray *array,
if (flags & FREE_SEGMENT)
{
if (array->clear_func != NULL)
{
guint i;
for (i = 0; i < array->len; i++)
array->clear_func (g_array_elt_pos (array, i));
}
g_free (array->data);
segment = NULL;
}
@ -514,8 +551,8 @@ g_array_set_size (GArray *farray,
if (array->clear)
g_array_elt_zero (array, array->len, length - array->len);
}
else if (G_UNLIKELY (g_mem_gc_friendly) && length < array->len)
g_array_elt_zero (array, length, array->len - length);
else if (length < array->len)
g_array_remove_range (farray, length, array->len - length);
array->len = length;
@ -543,11 +580,14 @@ g_array_remove_index (GArray *farray,
g_return_val_if_fail (index_ < array->len, NULL);
if (array->clear_func != NULL)
array->clear_func (g_array_elt_pos (array, index_));
if (index_ != array->len - 1)
g_memmove (g_array_elt_pos (array, index_),
g_array_elt_pos (array, index_ + 1),
g_array_elt_len (array, array->len - index_ - 1));
g_array_elt_pos (array, index_ + 1),
g_array_elt_len (array, array->len - index_ - 1));
array->len -= 1;
if (G_UNLIKELY (g_mem_gc_friendly))
@ -579,10 +619,13 @@ g_array_remove_index_fast (GArray *farray,
g_return_val_if_fail (index_ < array->len, NULL);
if (array->clear_func != NULL)
array->clear_func (g_array_elt_pos (array, index_));
if (index_ != array->len - 1)
memcpy (g_array_elt_pos (array, index_),
g_array_elt_pos (array, array->len - 1),
g_array_elt_len (array, 1));
memcpy (g_array_elt_pos (array, index_),
g_array_elt_pos (array, array->len - 1),
g_array_elt_len (array, 1));
array->len -= 1;
@ -617,9 +660,17 @@ g_array_remove_range (GArray *farray,
g_return_val_if_fail (index_ < array->len, NULL);
g_return_val_if_fail (index_ + length <= array->len, NULL);
if (array->clear_func != NULL)
{
guint i;
for (i = 0; i < length; i++)
array->clear_func (g_array_elt_pos (array, index_ + i));
}
if (index_ + length != array->len)
g_memmove (g_array_elt_pos (array, index_),
g_array_elt_pos (array, index_ + length),
g_memmove (g_array_elt_pos (array, index_),
g_array_elt_pos (array, index_ + length),
(array->len - (index_ + length)) * array->elt_size);
array->len -= length;

View File

@ -104,6 +104,8 @@ void g_array_sort (GArray *array,
void g_array_sort_with_data (GArray *array,
GCompareDataFunc compare_func,
gpointer user_data);
void g_array_set_clear_func (GArray *array,
GDestroyNotify clear_func);
/* Resizable pointer array. This interface is much less complicated
* than the above. Add appends a pointer. Remove fills any cleared

View File

@ -12,6 +12,7 @@ g_array_prepend_vals
g_array_remove_index
g_array_remove_index_fast
g_array_remove_range
g_array_set_clear_func
g_array_set_size
g_array_sized_new
g_array_sort

View File

@ -304,6 +304,43 @@ array_sort_with_data (void)
g_array_free (garray, TRUE);
}
static gint num_clear_func_invocations = 0;
static void
my_clear_func (gpointer data)
{
num_clear_func_invocations += 1;
}
static void
array_clear_func (void)
{
GArray *garray;
gint i;
gint cur;
garray = g_array_new (FALSE, FALSE, sizeof (gint));
g_array_set_clear_func (garray, my_clear_func);
for (i = 0; i < 10; i++)
{
cur = g_random_int_range (0, 100);
g_array_append_val (garray, cur);
}
g_array_remove_index (garray, 9);
g_assert_cmpint (num_clear_func_invocations, ==, 1);
g_array_remove_range (garray, 5, 3);
g_assert_cmpint (num_clear_func_invocations, ==, 4);
g_array_remove_index_fast (garray, 4);
g_assert_cmpint (num_clear_func_invocations, ==, 5);
g_array_free (garray, TRUE);
g_assert_cmpint (num_clear_func_invocations, ==, 10);
}
static void
pointer_array_add (void)
{
@ -812,6 +849,7 @@ main (int argc, char *argv[])
g_test_add_func ("/array/large-size", array_large_size);
g_test_add_func ("/array/sort", array_sort);
g_test_add_func ("/array/sort-with-data", array_sort_with_data);
g_test_add_func ("/array/clear-func", array_clear_func);
/* pointer arrays */
g_test_add_func ("/pointerarray/add", pointer_array_add);