[glib] array: Add a clear function



commit c602a5f887233bdd75544a290023d10029ca4fda
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Wed Jan 4 07:41:47 2012 +0000

    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
 </SECTION>
 
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);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]