[glib] Bug 580450 – Reference counting and boxed types for arrays
- From: David Zeuthen <davidz src gnome org>
- To: svn-commits-list gnome org
- Subject: [glib] Bug 580450 – Reference counting and boxed types for arrays
- Date: Wed, 29 Apr 2009 11:19:51 -0400 (EDT)
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]