From c602a5f887233bdd75544a290023d10029ca4fda Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 4 Jan 2012 07:41:47 +0000 Subject: [PATCH] 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 --- docs/reference/glib/glib-sections.txt | 1 + glib/garray.c | 71 ++++++++++++++++++++++++++++++----- glib/garray.h | 2 + glib/glib.symbols | 1 + glib/tests/array-test.c | 38 +++++++++++++++++++ 5 files changed, 103 insertions(+), 10 deletions(-) diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index b59ca76..45b2e91 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -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 diff --git a/glib/garray.c b/glib/garray.c index 5a5f9fa..5cd002a 100644 --- a/glib/garray.c +++ b/glib/garray.c @@ -110,6 +110,7 @@ struct _GRealArray guint zero_terminated : 1; guint clear : 1; gint ref_count; + GDestroyNotify clear_func; }; /** @@ -211,6 +212,34 @@ GArray* g_array_sized_new (gboolean zero_terminated, } /** + * 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; diff --git a/glib/garray.h b/glib/garray.h index d96aade..eb37b92 100644 --- a/glib/garray.h +++ b/glib/garray.h @@ -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 diff --git a/glib/glib.symbols b/glib/glib.symbols index 1b01bb4..d13420f 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -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 diff --git a/glib/tests/array-test.c b/glib/tests/array-test.c index 7caab87..5f9ccd5 100644 --- a/glib/tests/array-test.c +++ b/glib/tests/array-test.c @@ -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); -- 2.7.4