[glib: 1/2] Add g_array_steal(), g_ptr_array_steal() and g_byte_array_steal()



commit 7bada8394dae1128558734fb655a5abb529a630c
Author: Paolo Bonzini <pbonzini redhat com>
Date:   Tue Jul 30 19:22:05 2019 +0200

    Add g_array_steal(), g_ptr_array_steal() and g_byte_array_steal()
    
    Closes issue #285

 docs/reference/glib/glib-sections.txt |   3 +
 glib/garray.c                         | 113 ++++++++++++++++++++++++++++
 glib/garray.h                         |   9 +++
 glib/tests/array-test.c               | 134 +++++++++++++++++++++++++++++++++-
 4 files changed, 258 insertions(+), 1 deletion(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index c67af683d..08ff50ac2 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -2805,6 +2805,7 @@ g_string_chunk_free
 <FILE>arrays</FILE>
 GArray
 g_array_new
+g_array_steal
 g_array_sized_new
 g_array_copy
 g_array_ref
@@ -2833,6 +2834,7 @@ g_array_free
 <FILE>arrays_pointer</FILE>
 GPtrArray
 g_ptr_array_new
+g_ptr_array_steal
 g_ptr_array_sized_new
 g_ptr_array_new_with_free_func
 g_ptr_array_copy
@@ -2868,6 +2870,7 @@ g_ptr_array_find_with_equal_func
 <SUBSECTION>
 GByteArray
 g_byte_array_new
+g_byte_array_steal
 g_byte_array_new_take
 g_byte_array_sized_new
 g_byte_array_ref
diff --git a/glib/garray.c b/glib/garray.c
index 38f64b82d..0ffbe3de6 100644
--- a/glib/garray.c
+++ b/glib/garray.c
@@ -165,6 +165,57 @@ g_array_new (gboolean zero_terminated,
   return g_array_sized_new (zero_terminated, clear, elt_size, 0);
 }
 
+/**
+ * g_array_steal:
+ * @array: a #GArray.
+ * @len: (optional) (out caller-allocates): pointer to retrieve the number of
+ *    elements of the original array
+ *
+ * Frees the data in the array and resets the size to zero, while
+ * the underlying array is preserved for use elsewhere and returned
+ * to the caller.
+ *
+ * If the array was created with the @zero_terminate property
+ * set to %TRUE, the returned data is zero terminated too.
+ *
+ * If array elements contain dynamically-allocated memory,
+ * the array elements should also be freed by the caller.
+ *
+ * A short example of use:
+ * |[<!-- language="C" -->
+ * ...
+ * gpointer data;
+ * gsize data_len;
+ * data = g_array_steal (some_array, &data_len);
+ * ...
+ * ]|
+
+ * Returns: (transfer full): the element data, which should be
+ *     freed using g_free().
+ *
+ * Since: 2.64
+ */
+gpointer
+g_array_steal (GArray *array,
+               gsize *len)
+{
+  GRealArray *rarray;
+  gpointer segment;
+
+  g_return_val_if_fail (array != NULL, NULL);
+
+  rarray = (GRealArray *) array;
+  segment = (gpointer) rarray->data;
+
+  if (len != NULL)
+    *len = rarray->len;
+
+  rarray->data  = NULL;
+  rarray->len   = 0;
+  rarray->alloc = 0;
+  return segment;
+}
+
 /**
  * g_array_sized_new:
  * @zero_terminated: %TRUE if the array should have an extra element at
@@ -1013,6 +1064,46 @@ g_ptr_array_new (void)
   return g_ptr_array_sized_new (0);
 }
 
+/**
+ * g_ptr_array_steal:
+ * @array: a #GPtrArray.
+ * @len: (optional) (out caller-allocates): pointer to retrieve the number of
+ *    elements of the original array
+ *
+ * Frees the data in the array and resets the size to zero, while
+ * the underlying array is preserved for use elsewhere and returned
+ * to the caller.
+ *
+ * Even if set, the #GDestroyNotify function will never be called
+ * on the current contents of the array and the caller is
+ * responsible for freeing the array elements.
+ *
+ * Returns: (transfer full): the element data, which should be
+ *     freed using g_free().
+ *
+ * Since: 2.64
+ */
+gpointer *
+g_ptr_array_steal (GPtrArray *array,
+                   gsize *len)
+{
+  GRealPtrArray *rarray;
+  gpointer *segment;
+
+  g_return_val_if_fail (array != NULL, NULL);
+
+  rarray = (GRealPtrArray *) array;
+  segment = (gpointer *) rarray->pdata;
+
+  if (len != NULL)
+    *len = rarray->len;
+
+  rarray->pdata = NULL;
+  rarray->len   = 0;
+  rarray->alloc = 0;
+  return segment;
+}
+
 /**
  * g_ptr_array_copy:
  * @array: #GPtrArray to duplicate
@@ -2002,6 +2093,28 @@ g_byte_array_new (void)
   return (GByteArray *)g_array_sized_new (FALSE, FALSE, 1, 0);
 }
 
+/**
+ * g_byte_array_steal:
+ * @array: a #GByteArray.
+ * @len: (optional) (out caller-allocates): pointer to retrieve the number of
+ *    elements of the original array
+ *
+ * Frees the data in the array and resets the size to zero, while
+ * the underlying array is preserved for use elsewhere and returned
+ * to the caller.
+ *
+ * Returns: (transfer full): the element data, which should be
+ *     freed using g_free().
+ *
+ * Since: 2.64
+ */
+guint8 *
+g_byte_array_steal (GByteArray *array,
+                    gsize *len)
+{
+  return (guint8 *) g_array_steal ((GArray *) array, len);
+}
+
 /**
  * g_byte_array_new_take:
  * @data: (transfer full) (array length=len): byte data for the array
diff --git a/glib/garray.h b/glib/garray.h
index 3e7ce7732..67131b5b3 100644
--- a/glib/garray.h
+++ b/glib/garray.h
@@ -70,6 +70,9 @@ GLIB_AVAILABLE_IN_ALL
 GArray* g_array_new               (gboolean          zero_terminated,
                                   gboolean          clear_,
                                   guint             element_size);
+GLIB_AVAILABLE_IN_2_64
+gpointer g_array_steal            (GArray           *array,
+                                   gsize            *len);
 GLIB_AVAILABLE_IN_ALL
 GArray* g_array_sized_new         (gboolean          zero_terminated,
                                   gboolean          clear_,
@@ -137,6 +140,9 @@ GLIB_AVAILABLE_IN_ALL
 GPtrArray* g_ptr_array_new                (void);
 GLIB_AVAILABLE_IN_ALL
 GPtrArray* g_ptr_array_new_with_free_func (GDestroyNotify    element_free_func);
+GLIB_AVAILABLE_IN_2_64
+gpointer*   g_ptr_array_steal              (GPtrArray        *array,
+                                            gsize            *len);
 GLIB_AVAILABLE_IN_2_62
 GPtrArray *g_ptr_array_copy               (GPtrArray        *array,
                                            GCopyFunc         func,
@@ -227,6 +233,9 @@ GByteArray* g_byte_array_new               (void);
 GLIB_AVAILABLE_IN_ALL
 GByteArray* g_byte_array_new_take          (guint8           *data,
                                             gsize             len);
+GLIB_AVAILABLE_IN_2_64
+guint8*     g_byte_array_steal             (GByteArray       *array,
+                                            gsize            *len);
 GLIB_AVAILABLE_IN_ALL
 GByteArray* g_byte_array_sized_new         (guint             reserved_size);
 GLIB_AVAILABLE_IN_ALL
diff --git a/glib/tests/array-test.c b/glib/tests/array-test.c
index b26704e25..01372a030 100644
--- a/glib/tests/array-test.c
+++ b/glib/tests/array-test.c
@@ -140,6 +140,57 @@ array_new_zero_terminated (void)
   g_free (out_str);
 }
 
+/* Check g_array_steal() function */
+static void
+array_steal (void)
+{
+  const guint array_size = 10000;
+  GArray *garray;
+  gint *adata;
+  guint i;
+  gsize len, past_len;
+
+  garray = g_array_new (FALSE, FALSE, sizeof (gint));
+  adata = (gint *) g_array_steal (garray, NULL);
+  g_assert_null (adata);
+
+  adata = (gint *) g_array_steal (garray, &len);
+  g_assert_null (adata);
+  g_assert_cmpint (len, ==, 0);
+
+  for (i = 0; i < array_size; i++)
+    g_array_append_val (garray, i);
+
+  for (i = 0; i < array_size; i++)
+    g_assert_cmpint (g_array_index (garray, gint, i), ==, i);
+
+
+  past_len = garray->len;
+  adata = (gint *) g_array_steal (garray, &len);
+  for (i = 0; i < array_size; i++)
+    g_assert_cmpint (adata[i], ==, i);
+
+  g_assert_cmpint (past_len, ==, len);
+  g_assert_cmpint (garray->len, ==, 0);
+
+  g_array_append_val (garray, i);
+
+  g_assert_cmpint (adata[0], ==, 0);
+  g_assert_cmpint (g_array_index (garray, gint, 0), ==, array_size);
+  g_assert_cmpint (garray->len, ==, 1);
+
+  g_array_remove_index (garray, 0);
+
+  for (i = 0; i < array_size; i++)
+    g_array_append_val (garray, i);
+
+  g_assert_cmpint (garray->len, ==, array_size);
+  g_assert_cmpmem (adata, array_size * sizeof (gint),
+                   garray->data, array_size * sizeof (gint));
+  g_free (adata);
+  g_array_free (garray, TRUE);
+}
+
 /* Check that g_array_append_val() works correctly for various #GArray
  * configurations. */
 static void
@@ -760,6 +811,49 @@ test_array_binary_search (void)
   g_array_free (garray, TRUE);
 }
 
+/* Check g_ptr_array_steal() function */
+static void
+pointer_array_steal (void)
+{
+  const guint array_size = 10000;
+  GPtrArray *gparray;
+  gpointer *pdata;
+  guint i;
+  gsize len, past_len;
+
+  gparray = g_ptr_array_new ();
+  pdata = g_ptr_array_steal (gparray, NULL);
+  g_assert_null (pdata);
+
+  pdata = g_ptr_array_steal (gparray, &len);
+  g_assert_null (pdata);
+  g_assert_cmpint (len, ==, 0);
+
+  for (i = 0; i < array_size; i++)
+    g_ptr_array_add (gparray, GINT_TO_POINTER (i));
+
+  past_len = gparray->len;
+  pdata = g_ptr_array_steal (gparray, &len);
+  g_assert_cmpint (gparray->len, ==, 0);
+  g_assert_cmpint (past_len, ==, len);
+  g_ptr_array_add (gparray, GINT_TO_POINTER (10));
+
+  g_assert_cmpint ((gsize) pdata[0], ==, (gsize) GINT_TO_POINTER (0));
+  g_assert_cmpint ((gsize) g_ptr_array_index (gparray, 0), ==,
+                   (gsize) GINT_TO_POINTER (10));
+  g_assert_cmpint (gparray->len, ==, 1);
+
+  g_ptr_array_remove_index (gparray, 0);
+
+  for (i = 0; i < array_size; i++)
+    g_ptr_array_add (gparray, GINT_TO_POINTER (i));
+  g_assert_cmpmem (pdata, array_size * sizeof (gpointer),
+                   gparray->pdata, array_size * sizeof (gpointer));
+  g_free (pdata);
+
+  g_ptr_array_free (gparray, TRUE);
+}
+
 static void
 pointer_array_add (void)
 {
@@ -1318,7 +1412,7 @@ steal_destroy_notify (gpointer data)
 /* Test that g_ptr_array_steal_index() and g_ptr_array_steal_index_fast() can
  * remove elements from a pointer array without the #GDestroyNotify being called. */
 static void
-pointer_array_steal (void)
+pointer_array_steal_index (void)
 {
   guint i1 = 0, i2 = 0, i3 = 0, i4 = 0;
   gpointer out1, out2;
@@ -1361,6 +1455,41 @@ pointer_array_steal (void)
   g_assert_cmpuint (i4, ==, 1);
 }
 
+static void
+byte_array_steal (void)
+{
+  const guint array_size = 10000;
+  GByteArray *gbarray;
+  guint8 *bdata;
+  guint i;
+  gsize len, past_len;
+
+  gbarray = g_byte_array_new ();
+  bdata = g_byte_array_steal (gbarray, NULL);
+  g_assert_cmpint ((gsize) bdata, ==, (gsize) gbarray->data);
+  g_free (bdata);
+
+  for (i = 0; i < array_size; i++)
+    g_byte_array_append (gbarray, (guint8 *) "abcd", 4);
+
+  past_len = gbarray->len;
+  bdata = g_byte_array_steal (gbarray, &len);
+
+  g_assert_cmpint (len, ==, past_len);
+  g_assert_cmpint (gbarray->len, ==, 0);
+
+  g_byte_array_append (gbarray, (guint8 *) "@", 1);
+
+  g_assert_cmpint (bdata[0], ==, 'a');
+  g_assert_cmpint (gbarray->data[0], ==, '@');
+  g_assert_cmpint (gbarray->len, ==, 1);
+
+  g_byte_array_remove_index (gbarray, 0);
+
+  g_free (bdata);
+  g_byte_array_free (gbarray, TRUE);
+}
+
 static void
 byte_array_append (void)
 {
@@ -1679,6 +1808,7 @@ main (int argc, char *argv[])
   /* array tests */
   g_test_add_func ("/array/new/zero-terminated", array_new_zero_terminated);
   g_test_add_func ("/array/ref-count", array_ref_count);
+  g_test_add_func ("/array/steal", array_steal);
   g_test_add_func ("/array/clear-func", array_clear_func);
   g_test_add_func ("/array/binary-search", test_array_binary_search);
 
@@ -1711,8 +1841,10 @@ main (int argc, char *argv[])
   g_test_add_func ("/pointerarray/find/empty", pointer_array_find_empty);
   g_test_add_func ("/pointerarray/find/non-empty", pointer_array_find_non_empty);
   g_test_add_func ("/pointerarray/steal", pointer_array_steal);
+  g_test_add_func ("/pointerarray/steal_index", pointer_array_steal_index);
 
   /* byte arrays */
+  g_test_add_func ("/bytearray/steal", byte_array_steal);
   g_test_add_func ("/bytearray/append", byte_array_append);
   g_test_add_func ("/bytearray/prepend", byte_array_prepend);
   g_test_add_func ("/bytearray/remove", byte_array_remove);


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