[glib] Bug 580450 – Reference counting and boxed types for arrays



commit 402847c8878a6bf839facdf7a91f096769ebc609
Author: David Zeuthen <davidz redhat com>
Date:   Wed Apr 29 11:15:20 2009 -0400

    Bug 580450 â?? Reference counting and boxed types for arrays
    
    Add reference counting and boxed types for GArray, GByteArray and GPtrArray.
    
    Signed-off-by: Matthias Clasen <mclasen redhat com>
---
 docs/reference/glib/glib-sections.txt        |    9 +
 docs/reference/glib/tmpl/arrays.sgml         |   41 ++++-
 docs/reference/glib/tmpl/arrays_byte.sgml    |   23 ++-
 docs/reference/glib/tmpl/arrays_pointer.sgml |   64 ++++++-
 glib/garray.c                                |  253 ++++++++++++++++++++++++--
 glib/garray.h                                |   10 +
 glib/glib.symbols                            |    9 +
 glib/tests/array-test.c                      |  172 +++++++++++++++++
 gobject/gboxed.c                             |   33 ++++
 gobject/gboxed.h                             |   27 +++
 gobject/gobject.symbols                      |    3 +
 11 files changed, 616 insertions(+), 28 deletions(-)

diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 85335af..2f3d954 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -2117,6 +2117,9 @@ g_string_chunk_free
 GArray
 g_array_new
 g_array_sized_new
+g_array_ref
+g_array_unref
+g_array_get_element_size
 g_array_append_val
 g_array_append_vals
 g_array_prepend_val
@@ -2139,6 +2142,10 @@ g_array_free
 GPtrArray
 g_ptr_array_new
 g_ptr_array_sized_new
+g_ptr_array_new_with_free_func
+g_ptr_array_set_free_func
+g_ptr_array_ref
+g_ptr_array_unref
 g_ptr_array_add
 g_ptr_array_remove
 g_ptr_array_remove_index
@@ -2160,6 +2167,8 @@ g_ptr_array_foreach
 GByteArray
 g_byte_array_new
 g_byte_array_sized_new
+g_byte_array_ref
+g_byte_array_unref
 g_byte_array_append
 g_byte_array_prepend
 g_byte_array_remove_index
diff --git a/docs/reference/glib/tmpl/arrays.sgml b/docs/reference/glib/tmpl/arrays.sgml
index 34c5497..890e15c 100644
--- a/docs/reference/glib/tmpl/arrays.sgml
+++ b/docs/reference/glib/tmpl/arrays.sgml
@@ -69,7 +69,7 @@ added to the #GArray.
 
 <!-- ##### FUNCTION g_array_new ##### -->
 <para>
-Creates a new #GArray.
+Creates a new #GArray with a reference count of 1.
 </para>
 
 @zero_terminated: %TRUE if the array should have an extra element at the end
@@ -83,9 +83,9 @@ when they are allocated.
 <!-- ##### FUNCTION g_array_sized_new ##### -->
 <para>
 Creates a new #GArray with @reserved_size elements
-preallocated. This avoids frequent reallocation, if you are going to
-add many elements to the array. Note however that the size of the
-array is still 0.
+preallocated and a reference count of 1. This avoids frequent reallocation,
+if you are going to add many elements to the array. Note however that the
+size of the array is still 0.
 </para>
 
 @zero_terminated: %TRUE if the array should have an extra element at the end with all bits cleared.
@@ -95,6 +95,32 @@ array is still 0.
 @Returns: the new #GArray.
 
 
+<!-- ##### FUNCTION g_array_ref ##### -->
+<para>
+
+</para>
+
+ array: 
+ Returns: 
+
+
+<!-- ##### FUNCTION g_array_unref ##### -->
+<para>
+
+</para>
+
+ array: 
+
+
+<!-- ##### FUNCTION g_array_get_element_size ##### -->
+<para>
+
+</para>
+
+ array: 
+ Returns: 
+
+
 <!-- ##### MACRO g_array_append_val ##### -->
 <para>
 Adds the value on to the end of the array.
@@ -292,8 +318,11 @@ If the array was created with @clear_ set to %TRUE, the new elements are set to
 <para>
 Frees the memory allocated for the #GArray.
 If @free_segment is %TRUE it frees the memory block holding the elements
-as well. Pass %FALSE if you want to free the #GArray wrapper but preserve
-the underlying array for use elsewhere.
+as well and also each element if @array has a @element_free_func set.
+Pass %FALSE if you want to free the #GArray wrapper but preserve
+the underlying array for use elsewhere. If the reference count of @array
+is greater than one, the #GArray wrapper is preserved but the size of
+ array will be set to zero.
 </para>
 <note>
 <para>
diff --git a/docs/reference/glib/tmpl/arrays_byte.sgml b/docs/reference/glib/tmpl/arrays_byte.sgml
index eb3c400..b1c4e4f 100644
--- a/docs/reference/glib/tmpl/arrays_byte.sgml
+++ b/docs/reference/glib/tmpl/arrays_byte.sgml
@@ -63,7 +63,7 @@ added to the #GByteArray.
 
 <!-- ##### FUNCTION g_byte_array_new ##### -->
 <para>
-Creates a new #GByteArray.
+Creates a new #GByteArray with a reference count of 1.
 </para>
 
 @Returns: the new #GByteArray.
@@ -80,6 +80,23 @@ the array. Note however that the size of the array is still 0.
 @Returns: the new #GByteArray.
 
 
+<!-- ##### FUNCTION g_byte_array_ref ##### -->
+<para>
+
+</para>
+
+ array: 
+ Returns: 
+
+
+<!-- ##### FUNCTION g_byte_array_unref ##### -->
+<para>
+
+</para>
+
+ array: 
+
+
 <!-- ##### FUNCTION g_byte_array_append ##### -->
 <para>
 Adds the given bytes to the end of the #GByteArray.
@@ -181,7 +198,9 @@ Sets the size of the #GByteArray, expanding it if necessary.
 <!-- ##### FUNCTION g_byte_array_free ##### -->
 <para>
 Frees the memory allocated by the #GByteArray.
-If @free_segment is %TRUE it frees the actual byte data.
+If @free_segment is %TRUE it frees the actual byte data. If the reference
+count of @array is greater than one, the #GByteArray wrapper is preserved but
+the size of @array will be set to zero.
 </para>
 
 @array: a #GByteArray.
diff --git a/docs/reference/glib/tmpl/arrays_pointer.sgml b/docs/reference/glib/tmpl/arrays_pointer.sgml
index 15c5792..07c4569 100644
--- a/docs/reference/glib/tmpl/arrays_pointer.sgml
+++ b/docs/reference/glib/tmpl/arrays_pointer.sgml
@@ -73,7 +73,7 @@ Contains the public fields of a pointer array.
 
 <!-- ##### FUNCTION g_ptr_array_new ##### -->
 <para>
-Creates a new #GPtrArray.
+Creates a new #GPtrArray with a reference count of 1.
 </para>
 
 @Returns: the new #GPtrArray.
@@ -82,15 +82,50 @@ Creates a new #GPtrArray.
 <!-- ##### FUNCTION g_ptr_array_sized_new ##### -->
 <para>
 Creates a new #GPtrArray with @reserved_size pointers
-preallocated. This avoids frequent reallocation, if you are going to
-add many pointers to the array. Note however that the size of the
-array is still 0.
+preallocated and a reference count of 1. This avoids frequent reallocation,
+if you are going to add many pointers to the array. Note however that the size
+of the array is still 0.
 </para>
 
 @reserved_size: number of pointers preallocated.
 @Returns: the new #GPtrArray.
 
 
+<!-- ##### FUNCTION g_ptr_array_new_with_free_func ##### -->
+<para>
+
+</para>
+
+ element_free_func: 
+ Returns: 
+
+
+<!-- ##### FUNCTION g_ptr_array_set_free_func ##### -->
+<para>
+
+</para>
+
+ array: 
+ element_free_func: 
+
+
+<!-- ##### FUNCTION g_ptr_array_ref ##### -->
+<para>
+
+</para>
+
+ array: 
+ Returns: 
+
+
+<!-- ##### FUNCTION g_ptr_array_unref ##### -->
+<para>
+
+</para>
+
+ array: 
+
+
 <!-- ##### FUNCTION g_ptr_array_add ##### -->
 <para>
 Adds a pointer to the end of the pointer array.
@@ -105,6 +140,8 @@ The array will grow in size automatically if necessary.
 <para>
 Removes the first occurrence of the given pointer from the pointer array.
 The following elements are moved down one place.
+If @array has a non-%NULL #GDestroyNotify function it is called for
+the removed element.
 </para>
 <para>
 It returns %TRUE if the pointer was removed, or %FALSE if the pointer
@@ -121,6 +158,8 @@ in the array.
 <para>
 Removes the pointer at the given index from the pointer array.
 The following elements are moved down one place.
+If @array has a non-%NULL #GDestroyNotify function it is called for
+the removed element.
 </para>
 
 @array: a #GPtrArray.
@@ -134,6 +173,8 @@ Removes the first occurrence of the given pointer 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_remove().
+If @array has a non-%NULL #GDestroyNotify function it is called for
+the removed element.
 </para>
 <para>
 It returns %TRUE if the pointer was removed, or %FALSE if the pointer
@@ -151,6 +192,8 @@ 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_remove_index().
+If @array has a non-%NULL #GDestroyNotify function it is called for
+the removed element.
 </para>
 
 @array: a #GPtrArray.
@@ -162,6 +205,8 @@ g_ptr_array_remove_index().
 <para>
 Removes the given number of pointers starting at the given index from a
 #GPtrArray.  The following elements are moved to close the gap.
+If @array has a non-%NULL #GDestroyNotify function it is called for
+the removed elements.
 </para>
 
 @array: a @GPtrArray.
@@ -228,14 +273,17 @@ Returns the pointer at the given index of the pointer array.
 <!-- ##### FUNCTION g_ptr_array_free ##### -->
 <para>
 Frees the memory allocated for the #GPtrArray.
-If @free_segment is %TRUE it frees the memory block holding the elements
+If @free_seg is %TRUE it frees the memory block holding the elements
 as well. Pass %FALSE if you want to free the #GPtrArray wrapper but preserve
-the underlying array for use elsewhere.
+the underlying array for use elsewhere. If the reference count of @array
+is greater than one, the #GPtrArray wrapper is preserved but the size of
+ array will be set to zero.
 </para>
 <note>
 <para>
-If array contents point to dynamically-allocated memory, they should be freed
-separately.
+If array contents point to dynamically-allocated memory, they should
+be freed separately if @free_seg is %TRUE and no #GDestroyNotify
+function has been set for @array.
 </para>
 </note>
 
diff --git a/glib/garray.c b/glib/garray.c
index b05ded6..64f70e7 100644
--- a/glib/garray.c
+++ b/glib/garray.c
@@ -55,6 +55,7 @@ struct _GRealArray
   guint   elt_size;
   guint   zero_terminated : 1;
   guint   clear : 1;
+  volatile gint ref_count;
 };
 
 #define g_array_elt_len(array,i) ((array)->elt_size * (i))
@@ -91,6 +92,7 @@ GArray* g_array_sized_new (gboolean zero_terminated,
   array->zero_terminated = (zero_terminated ? 1 : 0);
   array->clear           = (clear ? 1 : 0);
   array->elt_size        = elt_size;
+  array->ref_count       = 1;
 
   if (array->zero_terminated || reserved_size != 0)
     {
@@ -101,14 +103,78 @@ GArray* g_array_sized_new (gboolean zero_terminated,
   return (GArray*) array;
 }
 
+/**
+ * g_array_ref:
+ * @array: A #GArray.
+ *
+ * Atomically increments the reference count of @array by one. This
+ * function is MT-safe and may be called from any thread.
+ *
+ * Returns: The passed in #GArray.
+ *
+ * Since: 2.22
+ **/
+GArray *
+g_array_ref (GArray *array)
+{
+  GRealArray *rarray = (GRealArray*) array;
+  g_return_val_if_fail (g_atomic_int_get (&rarray->ref_count) > 0, array);
+  g_atomic_int_inc (&rarray->ref_count);
+  return array;
+}
+
+/**
+ * g_array_unref:
+ * @array: A #GArray.
+ *
+ * Atomically decrements the reference count of @array by one. If the
+ * reference count drops to 0, all memory allocated by the array is
+ * released. This function is MT-safe and may be called from any
+ * thread.
+ *
+ * Since: 2.22
+ **/
+void
+g_array_unref (GArray *array)
+{
+  GRealArray *rarray = (GRealArray*) array;
+  g_return_if_fail (g_atomic_int_get (&rarray->ref_count) > 0);
+  if (g_atomic_int_dec_and_test (&rarray->ref_count))
+    g_array_free (array, TRUE);
+}
+
+/**
+ * g_array_get_element_size:
+ * @array: A #GArray.
+ *
+ * Gets the size of the elements in @array.
+ *
+ * Returns: Size of each element, in bytes.
+ *
+ * Since: 2.22
+ **/
+guint
+g_array_get_element_size (GArray *array)
+{
+  GRealArray *rarray = (GRealArray*) array;
+  return rarray->elt_size;
+}
+
 gchar*
-g_array_free (GArray   *array,
+g_array_free (GArray   *farray,
 	      gboolean  free_segment)
 {
+  GRealArray *array = (GRealArray*) farray;
   gchar* segment;
+  gboolean preserve_wrapper;
 
   g_return_val_if_fail (array, NULL);
 
+  /* if others are holding a reference, preserve the wrapper but do free/return the data */
+  preserve_wrapper = FALSE;
+  if (g_atomic_int_get (&array->ref_count) > 1)
+    preserve_wrapper = TRUE;
+
   if (free_segment)
     {
       g_free (array->data);
@@ -117,7 +183,16 @@ g_array_free (GArray   *array,
   else
     segment = array->data;
 
-  g_slice_free1 (sizeof (GRealArray), array);
+  if (preserve_wrapper)
+    {
+      array->data            = NULL;
+      array->len             = 0;
+      array->alloc           = 0;
+    }
+  else
+    {
+      g_slice_free1 (sizeof (GRealArray), array);
+    }
 
   return segment;
 }
@@ -352,9 +427,11 @@ typedef struct _GRealPtrArray  GRealPtrArray;
 
 struct _GRealPtrArray
 {
-  gpointer *pdata;
-  guint     len;
-  guint     alloc;
+  gpointer     *pdata;
+  guint         len;
+  guint         alloc;
+  volatile gint ref_count;
+  GDestroyNotify element_free_func;
 };
 
 static void g_ptr_array_maybe_expand (GRealPtrArray *array,
@@ -374,6 +451,8 @@ g_ptr_array_sized_new (guint reserved_size)
   array->pdata = NULL;
   array->len = 0;
   array->alloc = 0;
+  array->ref_count = 1;
+  array->element_free_func = NULL;
 
   if (reserved_size != 0)
     g_ptr_array_maybe_expand (array, reserved_size);
@@ -381,23 +460,123 @@ g_ptr_array_sized_new (guint reserved_size)
   return (GPtrArray*) array;  
 }
 
+/**
+ * g_ptr_array_new_with_free_func:
+ * @element_free_func: A function to free elements with destroy @array or %NULL.
+ *
+ * Creates a new #GPtrArray with a reference count of 1 and use @element_free_func
+ * for freeing each element when the array is destroyed either via
+ * g_ptr_array_unref(), when g_ptr_array_free() is called with @free_segment
+ * set to %TRUE or when removing elements.
+ *
+ * Returns: A new #GPtrArray.
+ *
+ * Since: 2.22
+ **/
+GPtrArray *
+g_ptr_array_new_with_free_func (GDestroyNotify element_free_func)
+{
+  GPtrArray *array;
+
+  array = g_ptr_array_new ();
+  g_ptr_array_set_free_func (array, element_free_func);
+  return array;
+}
+
+/**
+ * g_ptr_array_set_free_func:
+ * @array: A #GPtrArray.
+ * @element_free_func: A function to free elements with destroy @array or %NULL.
+ *
+ * Sets a function for freeing each element when @array is destroyed
+ * either via g_ptr_array_unref(), when g_ptr_array_free() is called
+ * with @free_segment set to %TRUE or when removing elements.
+ *
+ * Since: 2.22
+ **/
+void
+g_ptr_array_set_free_func (GPtrArray        *array,
+                           GDestroyNotify    element_free_func)
+{
+  GRealPtrArray* rarray = (GRealPtrArray*) array;
+  rarray->element_free_func = element_free_func;
+}
+
+/**
+ * g_ptr_array_ref:
+ * @array: A #GArray.
+ *
+ * Atomically increments the reference count of @array by one. This
+ * function is MT-safe and may be called from any thread.
+ *
+ * Returns: The passed in #GPtrArray.
+ *
+ * Since: 2.22
+ **/
+GPtrArray *
+g_ptr_array_ref (GPtrArray *array)
+{
+  GRealPtrArray *rarray = (GRealPtrArray*) array;
+  g_return_val_if_fail (g_atomic_int_get (&rarray->ref_count) > 0, array);
+  g_atomic_int_inc (&rarray->ref_count);
+  return array;
+}
+
+/**
+ * g_ptr_array_unref:
+ * @array: A #GPtrArray.
+ *
+ * Atomically decrements the reference count of @array by one. If the
+ * reference count drops to 0, the effect is the same as calling
+ * g_ptr_array_free() with @free_segment set to %TRUE. This function
+ * is MT-safe and may be called from any thread.
+ *
+ * Since: 2.22
+ **/
+void
+g_ptr_array_unref (GPtrArray *array)
+{
+  GRealPtrArray *rarray = (GRealPtrArray*) array;
+  g_return_if_fail (g_atomic_int_get (&rarray->ref_count) > 0);
+  if (g_atomic_int_dec_and_test (&rarray->ref_count))
+    g_ptr_array_free (array, TRUE);
+}
+
 gpointer*
-g_ptr_array_free (GPtrArray *array,
+g_ptr_array_free (GPtrArray *farray,
 		  gboolean   free_segment)
 {
+  GRealPtrArray *array = (GRealPtrArray*) farray;
   gpointer* segment;
+  gboolean preserve_wrapper;
 
   g_return_val_if_fail (array, NULL);
 
+  /* if others are holding a reference, preserve the wrapper but do free/return the data */
+  preserve_wrapper = FALSE;
+  if (g_atomic_int_get (&array->ref_count) > 1)
+    preserve_wrapper = TRUE;
+
   if (free_segment)
     {
+      if (array->element_free_func != NULL)
+        g_ptr_array_foreach (farray, (GFunc) array->element_free_func, NULL);
       g_free (array->pdata);
       segment = NULL;
     }
   else
     segment = array->pdata;
 
-  g_slice_free1 (sizeof (GRealPtrArray), array);
+  if (preserve_wrapper)
+    {
+      array->pdata = NULL;
+      array->len = 0;
+      array->alloc = 0;
+    }
+  else
+    {
+      g_slice_free1 (sizeof (GRealPtrArray), array);
+    }
 
   return segment;
 }
@@ -462,9 +641,12 @@ g_ptr_array_remove_index (GPtrArray *farray,
 
   result = array->pdata[index_];
   
+  if (array->element_free_func != NULL)
+    array->element_free_func (array->pdata[index_]);
+
   if (index_ != array->len - 1)
     g_memmove (array->pdata + index_, array->pdata + index_ + 1, 
-	       sizeof (gpointer) * (array->len - index_ - 1));
+               sizeof (gpointer) * (array->len - index_ - 1));
   
   array->len -= 1;
 
@@ -488,7 +670,11 @@ g_ptr_array_remove_index_fast (GPtrArray *farray,
   result = array->pdata[index_];
   
   if (index_ != array->len - 1)
-    array->pdata[index_] = array->pdata[array->len - 1];
+    {
+      if (array->element_free_func != NULL)
+        array->element_free_func (array->pdata[index_]);
+      array->pdata[index_] = array->pdata[array->len - 1];
+    }
 
   array->len -= 1;
 
@@ -504,15 +690,24 @@ g_ptr_array_remove_range (GPtrArray *farray,
                           guint      length)
 {
   GRealPtrArray* array = (GRealPtrArray*) farray;
+  guint n;
 
   g_return_if_fail (array);
   g_return_if_fail (index_ < array->len);
   g_return_if_fail (index_ + length <= array->len);
 
+  if (array->element_free_func != NULL)
+    {
+      for (n = index_; n < index_ + length; n++)
+        array->element_free_func (array->pdata[n]);
+    }
+
   if (index_ + length != array->len)
-    g_memmove (&array->pdata[index_],
-               &array->pdata[index_ + length], 
-               (array->len - (index_ + length)) * sizeof (gpointer));
+    {
+      g_memmove (&array->pdata[index_],
+                 &array->pdata[index_ + length], 
+                 (array->len - (index_ + length)) * sizeof (gpointer));
+    }
 
   array->len -= length;
   if (G_UNLIKELY (g_mem_gc_friendly))
@@ -646,6 +841,40 @@ guint8*	    g_byte_array_free     (GByteArray *array,
   return (guint8*) g_array_free ((GArray*) array, free_segment);
 }
 
+/**
+ * g_byte_array_ref:
+ * @array: A #GByteArray.
+ *
+ * Atomically increments the reference count of @array by one. This
+ * function is MT-safe and may be called from any thread.
+ *
+ * Returns: The passed in #GByteArray.
+ *
+ * Since: 2.22
+ **/
+GByteArray *
+g_byte_array_ref (GByteArray *array)
+{
+  return (GByteArray *) g_array_ref ((GArray *) array);
+}
+
+/**
+ * g_byte_array_unref:
+ * @array: A #GByteArray.
+ *
+ * Atomically decrements the reference count of @array by one. If the
+ * reference count drops to 0, all memory allocated by the array is
+ * released. This function is MT-safe and may be called from any
+ * thread.
+ *
+ * Since: 2.22
+ **/
+void
+g_byte_array_unref (GByteArray *array)
+{
+  g_array_unref ((GArray *) array);
+}
+
 GByteArray* g_byte_array_append   (GByteArray   *array,
 				   const guint8 *data,
 				   guint         len)
diff --git a/glib/garray.h b/glib/garray.h
index db00137..6bc51f7 100644
--- a/glib/garray.h
+++ b/glib/garray.h
@@ -76,6 +76,9 @@ GArray* g_array_sized_new         (gboolean          zero_terminated,
 				   guint             reserved_size);
 gchar*  g_array_free              (GArray           *array,
 				   gboolean          free_segment);
+GArray *g_array_ref               (GArray           *array);
+void    g_array_unref             (GArray           *array);
+guint   g_array_get_element_size  (GArray           *array);
 GArray* g_array_append_vals       (GArray           *array,
 				   gconstpointer     data,
 				   guint             len);
@@ -107,9 +110,14 @@ void    g_array_sort_with_data    (GArray           *array,
  */
 #define    g_ptr_array_index(array,index_) ((array)->pdata)[index_]
 GPtrArray* g_ptr_array_new                (void);
+GPtrArray* g_ptr_array_new_with_free_func (GDestroyNotify    element_free_func);
 GPtrArray* g_ptr_array_sized_new          (guint             reserved_size);
 gpointer*  g_ptr_array_free               (GPtrArray        *array,
 					   gboolean          free_seg);
+GPtrArray* g_ptr_array_ref                (GPtrArray        *array);
+void       g_ptr_array_unref              (GPtrArray        *array);
+void       g_ptr_array_set_free_func      (GPtrArray        *array,
+                                           GDestroyNotify    element_free_func);
 void       g_ptr_array_set_size           (GPtrArray        *array,
 					   gint              length);
 gpointer   g_ptr_array_remove_index       (GPtrArray        *array,
@@ -143,6 +151,8 @@ GByteArray* g_byte_array_new               (void);
 GByteArray* g_byte_array_sized_new         (guint             reserved_size);
 guint8*     g_byte_array_free              (GByteArray       *array,
 					    gboolean          free_segment);
+GByteArray *g_byte_array_ref               (GByteArray       *array);
+void        g_byte_array_unref             (GByteArray       *array);
 GByteArray* g_byte_array_append            (GByteArray       *array,
 					    const guint8     *data,
 					    guint             len);
diff --git a/glib/glib.symbols b/glib/glib.symbols
index ce6a148..f8410ca 100644
--- a/glib/glib.symbols
+++ b/glib/glib.symbols
@@ -17,6 +17,9 @@ g_array_append_vals
 g_array_free
 g_array_insert_vals
 g_array_new
+g_array_ref
+g_array_unref
+g_array_get_element_size
 g_array_prepend_vals
 g_array_remove_index
 g_array_remove_index_fast
@@ -27,6 +30,8 @@ g_array_sort
 g_array_sort_with_data
 g_byte_array_append
 g_byte_array_free
+g_byte_array_unref
+g_byte_array_ref
 g_byte_array_new
 g_byte_array_prepend
 g_byte_array_remove_index
@@ -39,7 +44,11 @@ g_byte_array_sort_with_data
 g_ptr_array_add
 g_ptr_array_foreach
 g_ptr_array_free
+g_ptr_array_unref
+g_ptr_array_ref
 g_ptr_array_new
+g_ptr_array_new_with_free_func
+g_ptr_array_set_free_func
 g_ptr_array_remove
 g_ptr_array_remove_fast
 g_ptr_array_remove_index
diff --git a/glib/tests/array-test.c b/glib/tests/array-test.c
index 6f83a27..3572ba3 100644
--- a/glib/tests/array-test.c
+++ b/glib/tests/array-test.c
@@ -73,6 +73,33 @@ array_prepend (void)
 }
 
 static void
+array_ref_count (void)
+{
+  GArray *garray;
+  GArray *garray2;
+  gint i;
+
+  garray = g_array_new (FALSE, FALSE, sizeof (gint));
+  g_assert_cmpint (g_array_get_element_size (garray), ==, sizeof (gint));
+  for (i = 0; i < 100; i++)
+    g_array_prepend_val (garray, i);
+
+  /* check we can ref, unref and still access the array */
+  garray2 = g_array_ref (garray);
+  g_assert (garray == garray2);
+  g_array_unref (garray2);
+  for (i = 0; i < 100; i++)
+    g_assert_cmpint (g_array_index (garray, gint, i), ==, (100 - i - 1));
+
+  /* garray2 should be an empty valid GArray wrapper */
+  garray2 = g_array_ref (garray);
+  g_array_free (garray, TRUE);
+
+  g_assert_cmpint (garray2->len, ==, 0);
+  g_array_unref (garray2);
+}
+
+static void
 pointer_array_add (void)
 {
   GPtrArray *gparray;
@@ -93,6 +120,118 @@ pointer_array_add (void)
 }
 
 static void
+pointer_array_ref_count (void)
+{
+  GPtrArray *gparray;
+  GPtrArray *gparray2;
+  gint i;
+  gint sum = 0;
+
+  gparray = g_ptr_array_new ();
+  for (i = 0; i < 10000; i++)
+    g_ptr_array_add (gparray, GINT_TO_POINTER (i));
+
+  /* check we can ref, unref and still access the array */
+  gparray2 = g_ptr_array_ref (gparray);
+  g_assert (gparray == gparray2);
+  g_ptr_array_unref (gparray2);
+  for (i = 0; i < 10000; i++)
+    g_assert (g_ptr_array_index (gparray, i) == GINT_TO_POINTER (i));
+
+  g_ptr_array_foreach (gparray, sum_up, &sum);
+  g_assert (sum == 49995000);
+
+  /* gparray2 should be an empty valid GPtrArray wrapper */
+  gparray2 = g_ptr_array_ref (gparray);
+  g_ptr_array_free (gparray, TRUE);
+
+  g_assert_cmpint (gparray2->len, ==, 0);
+  g_ptr_array_unref (gparray2);
+}
+
+static gint num_free_func_invocations = 0;
+
+static void
+my_free_func (gpointer data)
+{
+  num_free_func_invocations++;
+  g_free (data);
+}
+
+static void
+pointer_array_free_func (void)
+{
+  GPtrArray *gparray;
+  GPtrArray *gparray2;
+  gchar **strv;
+  gchar *s;
+
+  num_free_func_invocations = 0;
+  gparray = g_ptr_array_new_with_free_func (my_free_func);
+  g_ptr_array_unref (gparray);
+  g_assert_cmpint (num_free_func_invocations, ==, 0);
+
+  gparray = g_ptr_array_new_with_free_func (my_free_func);
+  g_ptr_array_free (gparray, TRUE);
+  g_assert_cmpint (num_free_func_invocations, ==, 0);
+
+  num_free_func_invocations = 0;
+  gparray = g_ptr_array_new_with_free_func (my_free_func);
+  g_ptr_array_add (gparray, g_strdup ("foo"));
+  g_ptr_array_add (gparray, g_strdup ("bar"));
+  g_ptr_array_add (gparray, g_strdup ("baz"));
+  g_ptr_array_remove_index (gparray, 0);
+  g_assert_cmpint (num_free_func_invocations, ==, 1);
+  s = g_strdup ("frob");
+  g_ptr_array_add (gparray, s);
+  g_assert (g_ptr_array_remove (gparray, s));
+  g_assert_cmpint (num_free_func_invocations, ==, 2);
+  g_ptr_array_ref (gparray);
+  g_ptr_array_unref (gparray);
+  g_assert_cmpint (num_free_func_invocations, ==, 2);
+  g_ptr_array_unref (gparray);
+  g_assert_cmpint (num_free_func_invocations, ==, 4);
+
+  num_free_func_invocations = 0;
+  gparray = g_ptr_array_new_with_free_func (my_free_func);
+  g_ptr_array_add (gparray, g_strdup ("foo"));
+  g_ptr_array_add (gparray, g_strdup ("bar"));
+  g_ptr_array_add (gparray, g_strdup ("baz"));
+  g_ptr_array_add (gparray, NULL);
+  gparray2 = g_ptr_array_ref (gparray);
+  strv = (gchar **) g_ptr_array_free (gparray, FALSE);
+  g_assert_cmpint (num_free_func_invocations, ==, 0);
+  g_strfreev (strv);
+  g_ptr_array_unref (gparray2);
+  g_assert_cmpint (num_free_func_invocations, ==, 0);
+
+  num_free_func_invocations = 0;
+  gparray = g_ptr_array_new_with_free_func (my_free_func);
+  g_ptr_array_add (gparray, g_strdup ("foo"));
+  g_ptr_array_add (gparray, g_strdup ("bar"));
+  g_ptr_array_add (gparray, g_strdup ("baz"));
+  g_ptr_array_unref (gparray);
+  g_assert_cmpint (num_free_func_invocations, ==, 3);
+
+  num_free_func_invocations = 0;
+  gparray = g_ptr_array_new_with_free_func (my_free_func);
+  g_ptr_array_add (gparray, g_strdup ("foo"));
+  g_ptr_array_add (gparray, g_strdup ("bar"));
+  g_ptr_array_add (gparray, g_strdup ("baz"));
+  g_ptr_array_free (gparray, TRUE);
+  g_assert_cmpint (num_free_func_invocations, ==, 3);
+
+  num_free_func_invocations = 0;
+  gparray = g_ptr_array_new_with_free_func (my_free_func);
+  g_ptr_array_add (gparray, "foo");
+  g_ptr_array_add (gparray, "bar");
+  g_ptr_array_add (gparray, "baz");
+  g_ptr_array_set_free_func (gparray, NULL);
+  g_ptr_array_free (gparray, TRUE);
+  g_assert_cmpint (num_free_func_invocations, ==, 0);
+}
+
+static void
 byte_array_append (void)
 {
   GByteArray *gbarray;
@@ -113,6 +252,35 @@ byte_array_append (void)
   g_byte_array_free (gbarray, TRUE);
 }
 
+static void
+byte_array_ref_count (void)
+{
+  GByteArray *gbarray;
+  GByteArray *gbarray2;
+  gint i;
+
+  gbarray = g_byte_array_new ();
+  for (i = 0; i < 10000; i++)
+    g_byte_array_append (gbarray, (guint8*) "abcd", 4);
+
+  gbarray2 = g_byte_array_ref (gbarray);
+  g_assert (gbarray2 == gbarray);
+  g_byte_array_unref (gbarray2);
+  for (i = 0; i < 10000; i++)
+    {
+      g_assert (gbarray->data[4*i] == 'a');
+      g_assert (gbarray->data[4*i+1] == 'b');
+      g_assert (gbarray->data[4*i+2] == 'c');
+      g_assert (gbarray->data[4*i+3] == 'd');
+    }
+
+  gbarray2 = g_byte_array_ref (gbarray);
+  g_assert (gbarray2 == gbarray);
+  g_byte_array_free (gbarray, TRUE);
+  g_assert_cmpint (gbarray2->len, ==, 0);
+  g_byte_array_unref (gbarray2);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -121,12 +289,16 @@ main (int argc, char *argv[])
   /* array tests */
   g_test_add_func ("/array/append", array_append);
   g_test_add_func ("/array/prepend", array_prepend);
+  g_test_add_func ("/array/ref-count", array_ref_count);
 
   /* pointer arrays */
   g_test_add_func ("/pointerarray/add", pointer_array_add);
+  g_test_add_func ("/pointerarray/ref-count", pointer_array_ref_count);
+  g_test_add_func ("/pointerarray/free-func", pointer_array_free_func);
 
   /* byte arrays */
   g_test_add_func ("/bytearray/append", byte_array_append);
+  g_test_add_func ("/bytearray/ref-count", byte_array_ref_count);
 
   return g_test_run ();
 }
diff --git a/gobject/gboxed.c b/gobject/gboxed.c
index 8cdcd1e..e3a6170 100644
--- a/gobject/gboxed.c
+++ b/gobject/gboxed.c
@@ -274,6 +274,39 @@ g_regex_get_type (void)
   return type_id;
 }
 
+GType
+g_array_get_type (void)
+{
+  static GType type_id = 0;
+  if (!type_id)
+    type_id = g_boxed_type_register_static (g_intern_static_string ("GArray"),
+					    (GBoxedCopyFunc) g_array_ref,
+                                            (GBoxedFreeFunc) g_array_unref);
+  return type_id;
+}
+
+GType
+g_ptr_array_get_type (void)
+{
+  static GType type_id = 0;
+  if (!type_id)
+    type_id = g_boxed_type_register_static (g_intern_static_string ("GPtrArray"),
+					    (GBoxedCopyFunc) g_ptr_array_ref,
+                                            (GBoxedFreeFunc) g_ptr_array_unref);
+  return type_id;
+}
+
+GType
+g_byte_array_get_type (void)
+{
+  static GType type_id = 0;
+  if (!type_id)
+    type_id = g_boxed_type_register_static (g_intern_static_string ("GByteArray"),
+					    (GBoxedCopyFunc) g_byte_array_ref,
+                                            (GBoxedFreeFunc) g_byte_array_unref);
+  return type_id;
+}
+
 static void
 boxed_proxy_value_init (GValue *value)
 {
diff --git a/gobject/gboxed.h b/gobject/gboxed.h
index 75a5193..82e2722 100644
--- a/gobject/gboxed.h
+++ b/gobject/gboxed.h
@@ -162,6 +162,30 @@ GType	g_boxed_type_register_static		(const gchar	*name,
  * Since: 2.14
  */
 #define	G_TYPE_REGEX (g_regex_get_type ())
+/**
+ * G_TYPE_ARRAY:
+ *
+ * The #GType for a boxed type holding a #GArray reference.
+ *
+ * Since: 2.22
+ */
+#define	G_TYPE_ARRAY (g_array_get_type ())
+/**
+ * G_TYPE_BYTE_ARRAY:
+ *
+ * The #GType for a boxed type holding a #GByteArray reference.
+ *
+ * Since: 2.22
+ */
+#define	G_TYPE_BYTE_ARRAY (g_byte_array_get_type ())
+/**
+ * G_TYPE_PTR_ARRAY:
+ *
+ * The #GType for a boxed type holding a #GPtrArray reference.
+ *
+ * Since: 2.22
+ */
+#define	G_TYPE_PTR_ARRAY (g_ptr_array_get_type ())
 
 
 void    g_value_take_boxed      (GValue		*value,
@@ -177,6 +201,9 @@ GType	g_date_get_type	        (void)	G_GNUC_CONST;
 GType	g_strv_get_type	        (void)	G_GNUC_CONST;
 GType	g_gstring_get_type      (void)	G_GNUC_CONST;
 GType   g_hash_table_get_type   (void)  G_GNUC_CONST;
+GType   g_array_get_type        (void)  G_GNUC_CONST;
+GType   g_byte_array_get_type   (void)  G_GNUC_CONST;
+GType   g_ptr_array_get_type    (void)  G_GNUC_CONST;
 GType   g_regex_get_type        (void)  G_GNUC_CONST;
 
 /**
diff --git a/gobject/gobject.symbols b/gobject/gobject.symbols
index 7a98dc3..a43dd08 100644
--- a/gobject/gobject.symbols
+++ b/gobject/gobject.symbols
@@ -20,6 +20,9 @@ g_date_get_type G_GNUC_CONST
 g_gstring_get_type G_GNUC_CONST
 g_strv_get_type G_GNUC_CONST
 g_hash_table_get_type G_GNUC_CONST
+g_array_get_type G_GNUC_CONST
+g_byte_array_get_type G_GNUC_CONST
+g_ptr_array_get_type G_GNUC_CONST
 g_regex_get_type G_GNUC_CONST
 g_closure_get_type G_GNUC_CONST
 g_value_get_type G_GNUC_CONST



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