summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Withnall <philip@tecnocode.co.uk>2022-12-21 18:34:13 +0000
committerPhilip Withnall <philip@tecnocode.co.uk>2022-12-21 18:34:13 +0000
commit5e378c775a79b61f307f2b780652745b528b4105 (patch)
tree4f598329109cbfd59b1de29f3ce23c5a4b98bea7
parentf64fc323106569349a091a68c9f45b68f9293ba4 (diff)
parent94c45f8fa246dc36a958649e62ce95c58785cde7 (diff)
downloadglib-5e378c775a79b61f307f2b780652745b528b4105.tar.gz
Merge branch 'ptr-array-new-take' into 'main'
garray: Add more G(Ptr)Array constructors to take or copy C arrays See merge request GNOME/glib!3128
-rw-r--r--docs/reference/glib/glib-sections.txt.in6
-rw-r--r--glib/garray.c338
-rw-r--r--glib/garray.h27
-rw-r--r--glib/tests/array-test.c842
4 files changed, 1211 insertions, 2 deletions
diff --git a/docs/reference/glib/glib-sections.txt.in b/docs/reference/glib/glib-sections.txt.in
index ab7453e60..baf62ebfa 100644
--- a/docs/reference/glib/glib-sections.txt.in
+++ b/docs/reference/glib/glib-sections.txt.in
@@ -2684,6 +2684,8 @@ g_string_chunk_free
<FILE>arrays</FILE>
GArray
g_array_new
+g_array_new_take
+g_array_new_take_zero_terminated
g_array_steal
g_array_sized_new
g_array_copy
@@ -2719,6 +2721,10 @@ g_ptr_array_new_with_free_func
g_ptr_array_copy
g_ptr_array_new_full
g_ptr_array_new_null_terminated
+g_ptr_array_new_take
+g_ptr_array_new_take_null_terminated
+g_ptr_array_new_from_array
+g_ptr_array_new_from_null_terminated_array
g_ptr_array_set_free_func
g_ptr_array_is_null_terminated
g_ptr_array_ref
diff --git a/glib/garray.c b/glib/garray.c
index 0db46bf5f..3ba41a483 100644
--- a/glib/garray.c
+++ b/glib/garray.c
@@ -35,6 +35,7 @@
#include "garray.h"
+#include "galloca.h"
#include "gbytes.h"
#include "ghash.h"
#include "gslice.h"
@@ -191,6 +192,119 @@ g_array_new (gboolean zero_terminated,
}
/**
+ * g_array_new_take: (skip)
+ * @data: (array length=len) (transfer full) (nullable): an array of
+ * elements of @element_size, or %NULL for an empty array
+ * @len: the number of elements in @data
+ * @clear: %TRUE if #GArray elements should be automatically cleared
+ * to 0 when they are allocated
+ * @element_size: the size of each element in bytes
+ *
+ * Creates a new #GArray with @data as array data, @len as length and a
+ * reference count of 1.
+ *
+ * This avoids having to copy the data manually, when it can just be
+ * inherited. @data will eventually be freed using g_free(), so must
+ * have been allocated with a suitable allocator.
+ *
+ * In case the elements need to be cleared when the array is freed, use
+ * g_array_set_clear_func() to set a #GDestroyNotify function to perform
+ * such task.
+ *
+ * Do not use it if @len or @element_size are greater than %G_MAXUINT.
+ * #GArray stores the length of its data in #guint, which may be shorter
+ * than #gsize.
+ *
+ * Returns: (transfer full): A new #GArray
+ *
+ * Since: 2.76
+ */
+GArray *
+g_array_new_take (gpointer data,
+ gsize len,
+ gboolean clear,
+ gsize element_size)
+{
+ GRealArray *rarray;
+ GArray *array;
+
+ g_return_val_if_fail (data != NULL || len == 0, NULL);
+ g_return_val_if_fail (len <= G_MAXUINT, NULL);
+ g_return_val_if_fail (element_size <= G_MAXUINT, NULL);
+
+ array = g_array_sized_new (FALSE, clear, element_size, 0);
+ rarray = (GRealArray *) array;
+ rarray->data = (guint8 *) g_steal_pointer (&data);
+ rarray->len = len;
+ rarray->elt_capacity = len;
+
+ return array;
+}
+
+/**
+ * g_array_new_take_zero_terminated: (skip)
+ * @data: (array zero-terminated=1): an array of elements of @element_size
+ * @clear: %TRUE if #GArray elements should be automatically cleared
+ * to 0 when they are allocated
+ * @element_size: the size of each element in bytes
+ *
+ * Creates a new #GArray with @data as array data, computing the length of it
+ * and setting the reference count to 1.
+ *
+ * This avoids having to copy the data manually, when it can just be
+ * inherited. @data will eventually be freed using g_free(), so must
+ * have been allocated with a suitable allocator.
+ *
+ * The length is calculated by iterating through @data until the first %NULL
+ * element is found.
+ *
+ * In case the elements need to be cleared when the array is freed, use
+ * g_array_set_clear_func() to set a #GDestroyNotify function to perform
+ * such task.
+ *
+ * Do not use it if @data length or @element_size are greater than %G_MAXUINT.
+ * #GArray stores the length of its data in #guint, which may be shorter
+ * than #gsize.
+ *
+ * Returns: (transfer full): A new #GArray
+ *
+ * Since: 2.76
+ */
+GArray *
+g_array_new_take_zero_terminated (gpointer data,
+ gboolean clear,
+ gsize element_size)
+{
+ GArray *array;
+ gsize len = 0;
+
+ g_return_val_if_fail (element_size <= G_MAXUINT, NULL);
+
+ if (data != NULL)
+ {
+ guint8 *array_data = data;
+
+ for (gsize i = 0; ; ++i)
+ {
+ const guint8 *element_start = array_data + (i * element_size);
+
+ if (*element_start == 0 &&
+ memcmp (element_start, element_start + 1, element_size - 1) == 0)
+ break;
+
+ len += 1;
+ }
+ }
+
+ g_return_val_if_fail (len <= G_MAXUINT, NULL);
+
+ array = g_array_new_take (data, len, clear, element_size);
+ ((GRealArray *)array)->zero_terminated = TRUE;
+
+ return array;
+}
+
+/**
* g_array_steal:
* @array: a #GArray.
* @len: (optional) (out): pointer to retrieve the number of
@@ -1072,7 +1186,7 @@ struct _GRealPtrArray
guint len;
guint alloc;
gatomicrefcount ref_count;
- guint8 null_terminated; /* always either 0 or 1, so it can be added to array lengths */
+ guint8 null_terminated : 1; /* always either 0 or 1, so it can be added to array lengths */
GDestroyNotify element_free_func;
};
@@ -1151,6 +1265,226 @@ g_ptr_array_new (void)
}
/**
+ * g_ptr_array_new_take: (skip)
+ * @data: (array length=len) (transfer full) (nullable): an array of pointers,
+ * or %NULL for an empty array
+ * @len: the number of pointers in @data
+ * @element_free_func: (nullable): A function to free elements on @array
+ * destruction or %NULL
+ *
+ * Creates a new #GPtrArray with @data as pointers, @len as length and a
+ * reference count of 1.
+ *
+ * This avoids having to copy such data manually. @data will eventually be
+ * freed using g_free(), so must have been allocated with a suitable allocator.
+ *
+ * It also sets @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.
+ *
+ * Do not use it if @len is greater than %G_MAXUINT. #GPtrArray
+ * stores the length of its data in #guint, which may be shorter than
+ * #gsize.
+ *
+ * Returns: (transfer full): A new #GPtrArray
+ *
+ * Since: 2.76
+ */
+GPtrArray *
+g_ptr_array_new_take (gpointer *data,
+ gsize len,
+ GDestroyNotify element_free_func)
+{
+ GPtrArray *array;
+ GRealPtrArray *rarray;
+
+ g_return_val_if_fail (data != NULL || len == 0, NULL);
+ g_return_val_if_fail (len <= G_MAXUINT, NULL);
+
+ array = ptr_array_new (0, element_free_func, FALSE);
+ rarray = (GRealPtrArray *)array;
+
+ rarray->pdata = g_steal_pointer (&data);
+ rarray->len = len;
+ rarray->alloc = len;
+
+ return array;
+}
+
+/**
+ * g_ptr_array_new_take_null_terminated: (skip)
+ * @data: (array zero-terminated=1) (transfer full) (nullable): an array
+ * of pointers, %NULL terminated, or %NULL for an empty array
+ * @element_free_func: (nullable): a function to free elements on @array
+ * destruction or %NULL
+ *
+ * Creates a new #GPtrArray with @data as pointers, computing the length of it
+ * and setting the reference count to 1.
+ *
+ * This avoids having to copy such data manually. @data will eventually be
+ * freed using g_free(), so must have been allocated with a suitable allocator.
+ *
+ * The length is calculated by iterating through @data until the first %NULL
+ * element is found.
+ *
+ * It also sets @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.
+ *
+ * Do not use it if the @data length is greater than %G_MAXUINT. #GPtrArray
+ * stores the length of its data in #guint, which may be shorter than
+ * #gsize.
+ *
+ * Returns: (transfer full): A new #GPtrArray
+ *
+ * Since: 2.76
+ */
+GPtrArray *
+g_ptr_array_new_take_null_terminated (gpointer *data,
+ GDestroyNotify element_free_func)
+{
+ GPtrArray *array;
+ gsize len = 0;
+
+ if (data != NULL)
+ {
+ for (gsize i = 0; data[i] != NULL; ++i)
+ len += 1;
+ }
+
+ g_return_val_if_fail (len <= G_MAXUINT, NULL);
+
+ array = g_ptr_array_new_take (g_steal_pointer (&data), len, element_free_func);
+ ((GRealPtrArray *)array)->null_terminated = TRUE;
+
+ return array;
+}
+
+static GPtrArray *
+ptr_array_new_from_array (gpointer *data,
+ gsize len,
+ GCopyFunc copy_func,
+ gpointer copy_func_user_data,
+ GDestroyNotify element_free_func,
+ gboolean null_terminated)
+{
+ GPtrArray *array;
+ GRealPtrArray *rarray;
+
+ g_assert (len <= G_MAXUINT);
+
+ array = ptr_array_new (len, element_free_func, null_terminated);
+ rarray = (GRealPtrArray *)array;
+
+ if (copy_func != NULL)
+ {
+ for (gsize i = 0; i < len; i++)
+ rarray->pdata[i] = copy_func (data[i], copy_func_user_data);
+ }
+ else
+ {
+ memcpy (rarray->pdata, data, len * sizeof (gpointer));
+ }
+
+ rarray->len = len;
+
+ return array;
+}
+
+/**
+ * g_ptr_array_new_from_array: (skip)
+ * @data: (array length=len) (transfer none) (nullable): an array of pointers,
+ * or %NULL for an empty array
+ * @len: the number of pointers in @data
+ * @copy_func: (nullable): a copy function used to copy every element in the
+ * array or %NULL.
+ * @copy_func_user_data: user data passed to @copy_func, or %NULL
+ * @element_free_func: (nullable): a function to free elements on @array
+ * destruction or %NULL
+ *
+ * Creates a new #GPtrArray, copying @len pointers from @data, and setting
+ * the array’s reference count to 1.
+ *
+ * This avoids having to manually add each element one by one.
+ *
+ * If @copy_func is provided, then it is used to copy each element before
+ * adding them to the new array. If it is %NULL then the pointers are copied
+ * directly.
+ *
+ * It also sets @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.
+ *
+ * Do not use it if @len is greater than %G_MAXUINT. #GPtrArray
+ * stores the length of its data in #guint, which may be shorter than
+ * #gsize.
+ *
+ * Returns: (transfer full): A new #GPtrArray
+ *
+ * Since: 2.76
+ */
+GPtrArray *
+g_ptr_array_new_from_array (gpointer *data,
+ gsize len,
+ GCopyFunc copy_func,
+ gpointer copy_func_user_data,
+ GDestroyNotify element_free_func)
+{
+ g_return_val_if_fail (data != NULL || len == 0, NULL);
+ g_return_val_if_fail (len <= G_MAXUINT, NULL);
+
+ return ptr_array_new_from_array (
+ data, len, copy_func, copy_func_user_data, element_free_func, FALSE);
+}
+
+/**
+ * g_ptr_array_new_from_null_terminated_array: (skip)
+ * @data: (array zero-terminated=1) (transfer none) (nullable): an array of
+ * pointers, %NULL terminated; or %NULL for an empty array
+ * @copy_func: (nullable): a copy function used to copy every element in the
+ * array or %NULL.
+ * @copy_func_user_data: user data passed to @copy_func, or %NULL
+ * @element_free_func: (nullable): a function to free elements on @array
+ * destruction or %NULL
+ *
+ * Creates a new #GPtrArray copying the pointers from @data after having
+ * computed the length of it and with a reference count of 1.
+ * This avoids having to manually add each element one by one.
+ * If @copy_func is provided, then it is used to copy the data in the new
+ * array.
+ * It also set @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.
+ *
+ * Do not use it if the @data has more than %G_MAXUINT elements. #GPtrArray
+ * stores the length of its data in #guint, which may be shorter than
+ * #gsize.
+ *
+ * Returns: (transfer full): A new #GPtrArray
+ *
+ * Since: 2.76
+ */
+GPtrArray *
+g_ptr_array_new_from_null_terminated_array (gpointer *data,
+ GCopyFunc copy_func,
+ gpointer copy_func_user_data,
+ GDestroyNotify element_free_func)
+{
+ gsize len = 0;
+
+ if (data != NULL)
+ {
+ for (gsize i = 0; data[i] != NULL; ++i)
+ len += 1;
+ }
+
+ g_return_val_if_fail (len <= G_MAXUINT, NULL);
+
+ return ptr_array_new_from_array (
+ data, len, copy_func, copy_func_user_data, element_free_func, TRUE);
+}
+
+/**
* g_ptr_array_steal:
* @array: a #GPtrArray.
* @len: (optional) (out): pointer to retrieve the number of
@@ -2113,7 +2447,7 @@ g_ptr_array_insert (GPtrArray *array,
*
* Sorts the array, using @compare_func which should be a qsort()-style
* comparison function (returns less than zero for first arg is less
- * than second arg, zero for equal, greater than zero if irst arg is
+ * than second arg, zero for equal, greater than zero if first arg is
* greater than second arg).
*
* Note that the comparison function for g_ptr_array_sort() doesn't
diff --git a/glib/garray.h b/glib/garray.h
index 2300e5f58..2ec10793b 100644
--- a/glib/garray.h
+++ b/glib/garray.h
@@ -72,6 +72,15 @@ GLIB_AVAILABLE_IN_ALL
GArray* g_array_new (gboolean zero_terminated,
gboolean clear_,
guint element_size);
+GLIB_AVAILABLE_IN_2_76
+GArray* g_array_new_take (gpointer data,
+ gsize len,
+ gboolean clear,
+ gsize element_size);
+GLIB_AVAILABLE_IN_2_76
+GArray* g_array_new_take_zero_terminated (gpointer data,
+ gboolean clear,
+ gsize element_size);
GLIB_AVAILABLE_IN_2_64
gpointer g_array_steal (GArray *array,
gsize *len);
@@ -142,6 +151,16 @@ 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_76
+GPtrArray* g_ptr_array_new_take (gpointer *data,
+ gsize len,
+ GDestroyNotify element_free_func);
+GLIB_AVAILABLE_IN_2_76
+GPtrArray* g_ptr_array_new_from_array (gpointer *data,
+ gsize len,
+ GCopyFunc copy_func,
+ gpointer copy_func_user_data,
+ GDestroyNotify element_free_func);
GLIB_AVAILABLE_IN_2_64
gpointer* g_ptr_array_steal (GPtrArray *array,
gsize *len);
@@ -158,6 +177,14 @@ GLIB_AVAILABLE_IN_2_74
GPtrArray* g_ptr_array_new_null_terminated (guint reserved_size,
GDestroyNotify element_free_func,
gboolean null_terminated);
+GLIB_AVAILABLE_IN_2_76
+GPtrArray* g_ptr_array_new_take_null_terminated (gpointer *data,
+ GDestroyNotify element_free_func);
+GLIB_AVAILABLE_IN_2_76
+GPtrArray* g_ptr_array_new_from_null_terminated_array (gpointer *data,
+ GCopyFunc copy_func,
+ gpointer copy_func_user_data,
+ GDestroyNotify element_free_func);
GLIB_AVAILABLE_IN_ALL
gpointer* g_ptr_array_free (GPtrArray *array,
gboolean free_seg);
diff --git a/glib/tests/array-test.c b/glib/tests/array-test.c
index cd617200a..72d6924ff 100644
--- a/glib/tests/array-test.c
+++ b/glib/tests/array-test.c
@@ -142,6 +142,196 @@ array_new_zero_terminated (void)
g_free (out_str);
}
+static void
+array_new_take (void)
+{
+ const size_t array_size = 10000;
+ GArray *garray;
+ gpointer *data;
+ gpointer *old_data_copy;
+ gsize len;
+
+ garray = g_array_new (FALSE, FALSE, sizeof (size_t));
+ for (size_t i = 0; i < array_size; i++)
+ g_array_append_val (garray, i);
+
+ data = g_array_steal (garray, &len);
+ g_assert_cmpuint (array_size, ==, len);
+ g_assert_nonnull (data);
+ g_clear_pointer (&garray, g_array_unref);
+
+ old_data_copy = g_memdup2 (data, len * sizeof (size_t));
+ garray = g_array_new_take (g_steal_pointer (&data), len, FALSE, sizeof (size_t));
+ g_assert_cmpuint (garray->len, ==, array_size);
+
+ g_assert_cmpuint (g_array_index (garray, size_t, 0), ==, 0);
+ g_assert_cmpuint (g_array_index (garray, size_t, 10), ==, 10);
+
+ g_assert_cmpmem (old_data_copy, array_size * sizeof (size_t),
+ garray->data, array_size * sizeof (size_t));
+
+ size_t val = 55;
+ g_array_append_val (garray, val);
+ val = 33;
+ g_array_prepend_val (garray, val);
+
+ g_assert_cmpuint (garray->len, ==, array_size + 2);
+ g_assert_cmpuint (g_array_index (garray, size_t, 0), ==, 33);
+ g_assert_cmpuint (g_array_index (garray, size_t, garray->len - 1), ==, 55);
+
+ g_array_remove_index (garray, 0);
+ g_assert_cmpuint (garray->len, ==, array_size + 1);
+ g_array_remove_index (garray, garray->len - 1);
+ g_assert_cmpuint (garray->len, ==, array_size);
+
+ g_assert_cmpmem (old_data_copy, array_size * sizeof (size_t),
+ garray->data, array_size * sizeof (size_t));
+
+ g_array_unref (garray);
+ g_free (old_data_copy);
+}
+
+static void
+array_new_take_empty (void)
+{
+ GArray *garray;
+ size_t empty_array[] = {0};
+
+ garray = g_array_new_take (
+ g_memdup2 (&empty_array, sizeof (size_t)), 0, FALSE, sizeof (size_t));
+ g_assert_cmpuint (garray->len, ==, 0);
+
+ g_clear_pointer (&garray, g_array_unref);
+
+ garray = g_array_new_take (NULL, 0, FALSE, sizeof (size_t));
+ g_assert_cmpuint (garray->len, ==, 0);
+
+ g_clear_pointer (&garray, g_array_unref);
+}
+
+static void
+array_new_take_zero_terminated (void)
+{
+ size_t array_size = 10000;
+ GArray *garray;
+ gpointer *data;
+ gpointer *old_data_copy;
+ gsize len;
+
+ garray = g_array_new (TRUE, FALSE, sizeof (size_t));
+ for (size_t i = 1; i <= array_size; i++)
+ g_array_append_val (garray, i);
+
+ data = g_array_steal (garray, &len);
+ g_assert_cmpuint (array_size, ==, len);
+ g_assert_nonnull (data);
+ g_clear_pointer (&garray, g_array_unref);
+
+ old_data_copy = g_memdup2 (data, len * sizeof (size_t));
+ garray = g_array_new_take_zero_terminated (
+ g_steal_pointer (&data), FALSE, sizeof (size_t));
+ g_assert_cmpuint (garray->len, ==, array_size);
+ g_assert_cmpuint (g_array_index (garray, size_t, garray->len), ==, 0);
+
+ g_assert_cmpuint (g_array_index (garray, size_t, 0), ==, 1);
+ g_assert_cmpuint (g_array_index (garray, size_t, 10), ==, 11);
+
+ g_assert_cmpmem (old_data_copy, array_size * sizeof (size_t),
+ garray->data, array_size * sizeof (size_t));
+
+ size_t val = 55;
+ g_array_append_val (garray, val);
+ val = 33;
+ g_array_prepend_val (garray, val);
+
+ g_assert_cmpuint (garray->len, ==, array_size + 2);
+ g_assert_cmpuint (g_array_index (garray, size_t, 0), ==, 33);
+ g_assert_cmpuint (g_array_index (garray, size_t, garray->len - 1), ==, 55);
+
+ g_array_remove_index (garray, 0);
+ g_assert_cmpuint (garray->len, ==, array_size + 1);
+ g_array_remove_index (garray, garray->len - 1);
+ g_assert_cmpuint (garray->len, ==, array_size);
+ g_assert_cmpuint (g_array_index (garray, size_t, garray->len), ==, 0);
+
+ g_assert_cmpmem (old_data_copy, array_size * sizeof (size_t),
+ garray->data, array_size * sizeof (size_t));
+
+ g_clear_pointer (&garray, g_array_unref);
+ g_clear_pointer (&old_data_copy, g_free);
+
+ array_size = G_MAXUINT8;
+ garray = g_array_new (TRUE, FALSE, sizeof (guint8));
+ for (guint8 i = 1; i < array_size; i++)
+ g_array_append_val (garray, i);
+
+ val = G_MAXUINT8 / 2;
+ g_array_append_val (garray, val);
+
+ data = g_array_steal (garray, &len);
+ g_assert_cmpuint (array_size, ==, len);
+ g_assert_nonnull (data);
+ g_clear_pointer (&garray, g_array_unref);
+
+ old_data_copy = g_memdup2 (data, len * sizeof (guint8));
+ garray = g_array_new_take_zero_terminated (
+ g_steal_pointer (&data), FALSE, sizeof (guint8));
+ g_assert_cmpuint (garray->len, ==, array_size);
+ g_assert_cmpuint (g_array_index (garray, guint8, garray->len), ==, 0);
+
+ g_assert_cmpuint (g_array_index (garray, guint8, 0), ==, 1);
+ g_assert_cmpuint (g_array_index (garray, guint8, 10), ==, 11);
+
+ g_assert_cmpmem (old_data_copy, array_size * sizeof (guint8),
+ garray->data, array_size * sizeof (guint8));
+
+ val = 55;
+ g_array_append_val (garray, val);
+ val = 33;
+ g_array_prepend_val (garray, val);
+
+ g_assert_cmpuint (garray->len, ==, array_size + 2);
+ g_assert_cmpuint (g_array_index (garray, guint8, 0), ==, 33);
+ g_assert_cmpuint (g_array_index (garray, guint8, garray->len - 1), ==, 55);
+
+ g_array_remove_index (garray, 0);
+ g_assert_cmpuint (garray->len, ==, array_size + 1);
+ g_array_remove_index (garray, garray->len - 1);
+ g_assert_cmpuint (garray->len, ==, array_size);
+ g_assert_cmpuint (g_array_index (garray, guint8, garray->len), ==, 0);
+
+ g_assert_cmpmem (old_data_copy, array_size * sizeof (guint8),
+ garray->data, array_size * sizeof (guint8));
+
+ g_clear_pointer (&garray, g_array_unref);
+ g_clear_pointer (&old_data_copy, g_free);
+}
+
+static void
+array_new_take_overflow (void)
+{
+#if SIZE_WIDTH <= UINT_WIDTH
+ g_test_skip ("Overflow test requires UINT_WIDTH > SIZE_WIDTH.");
+#else
+ if (!g_test_undefined ())
+ return;
+
+ /* Check for overflow should happen before data is accessed. */
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "*assertion 'len <= G_MAXUINT' failed");
+ g_assert_null (
+ g_array_new_take (
+ (gpointer) (int []) { 0 }, (gsize) G_MAXUINT + 1, FALSE, sizeof (int)));
+ g_test_assert_expected_messages ();
+
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "*assertion 'element_size <= G_MAXUINT' failed");
+ g_assert_null (
+ g_array_new_take (NULL, 0, FALSE, (gsize) G_MAXUINT + 1));
+ g_test_assert_expected_messages ();
+#endif
+}
+
/* Check g_array_steal() function */
static void
array_steal (void)
@@ -1014,6 +1204,638 @@ pointer_array_insert (void)
}
static void
+pointer_array_new_take (void)
+{
+ const size_t array_size = 10000;
+ GPtrArray *gparray;
+ gpointer *pdata;
+ gpointer *old_pdata_copy;
+ gsize len;
+
+ gparray = g_ptr_array_new ();
+ for (size_t i = 0; i < array_size; i++)
+ g_ptr_array_add (gparray, GUINT_TO_POINTER (i));
+
+ pdata = g_ptr_array_steal (gparray, &len);
+ g_assert_cmpuint (array_size, ==, len);
+ g_assert_nonnull (pdata);
+ g_clear_pointer (&gparray, g_ptr_array_unref);
+
+ old_pdata_copy = g_memdup2 (pdata, len * sizeof (gpointer));
+ gparray = g_ptr_array_new_take (g_steal_pointer (&pdata), len, NULL);
+ g_assert_false (g_ptr_array_is_null_terminated (gparray));
+ g_assert_cmpuint (gparray->len, ==, array_size);
+
+ g_assert_cmpuint (GPOINTER_TO_UINT (g_ptr_array_index (gparray, 0)), ==, 0);
+ g_assert_cmpuint (GPOINTER_TO_UINT (g_ptr_array_index (gparray, 10)), ==, 10);
+
+ g_assert_cmpmem (old_pdata_copy, array_size * sizeof (gpointer),
+ gparray->pdata, array_size * sizeof (gpointer));
+
+ g_ptr_array_add (gparray, GUINT_TO_POINTER (55));
+ g_ptr_array_insert (gparray, 0, GUINT_TO_POINTER (33));
+
+ g_assert_cmpuint (gparray->len, ==, array_size + 2);
+ g_assert_cmpuint (GPOINTER_TO_UINT (g_ptr_array_index (gparray, 0)), ==, 33);
+ g_assert_cmpuint (
+ GPOINTER_TO_UINT (g_ptr_array_index (gparray, gparray->len - 1)), ==, 55);
+
+ g_ptr_array_remove_index (gparray, 0);
+ g_assert_cmpuint (gparray->len, ==, array_size + 1);
+ g_ptr_array_remove_index (gparray, gparray->len - 1);
+ g_assert_cmpuint (gparray->len, ==, array_size);
+
+ g_assert_cmpmem (old_pdata_copy, array_size * sizeof (gpointer),
+ gparray->pdata, array_size * sizeof (gpointer));
+
+ g_ptr_array_unref (gparray);
+ g_free (old_pdata_copy);
+}
+
+static void
+pointer_array_new_take_empty (void)
+{
+ GPtrArray *gparray;
+ gpointer empty_array[] = {0};
+
+ gparray = g_ptr_array_new_take (
+ g_memdup2 (&empty_array, sizeof (gpointer)), 0, NULL);
+ g_assert_false (g_ptr_array_is_null_terminated (gparray));
+ g_assert_cmpuint (gparray->len, ==, 0);
+
+ g_clear_pointer (&gparray, g_ptr_array_unref);
+
+ gparray = g_ptr_array_new_take (NULL, 0, NULL);
+ g_assert_false (g_ptr_array_is_null_terminated (gparray));
+ g_assert_cmpuint (gparray->len, ==, 0);
+
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "*data*!=*NULL*||*len*==*0*");
+ g_assert_null (g_ptr_array_new_take (NULL, 10, NULL));
+ g_test_assert_expected_messages ();
+
+ g_clear_pointer (&gparray, g_ptr_array_unref);
+}
+
+static void
+pointer_array_new_take_overflow (void)
+{
+#if SIZE_WIDTH <= UINT_WIDTH
+ g_test_skip ("Overflow test requires UINT_WIDTH > SIZE_WIDTH.");
+#else
+ if (!g_test_undefined ())
+ return;
+
+ /* Check for overflow should happen before data is accessed. */
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "*assertion 'len <= G_MAXUINT' failed");
+ g_assert_null (g_ptr_array_new_take (
+ (gpointer []) { NULL }, (gsize) G_MAXUINT + 1, NULL));
+ g_test_assert_expected_messages ();
+#endif
+}
+
+static void
+pointer_array_new_take_with_free_func (void)
+{
+ const size_t array_size = 10000;
+ GPtrArray *gparray;
+ gpointer *pdata;
+ gpointer *old_pdata_copy;
+ gsize len;
+
+ gparray = g_ptr_array_new_with_free_func (g_free);
+ for (size_t i = 0; i < array_size; i++)
+ g_ptr_array_add (gparray, g_strdup_printf ("%" G_GSIZE_FORMAT, i));
+
+ pdata = g_ptr_array_steal (gparray, &len);
+ g_assert_cmpuint (array_size, ==, len);
+ g_assert_nonnull (pdata);
+ g_clear_pointer (&gparray, g_ptr_array_unref);
+
+ old_pdata_copy = g_memdup2 (pdata, len * sizeof (gpointer));
+ gparray = g_ptr_array_new_take (g_steal_pointer (&pdata), len, g_free);
+ g_assert_false (g_ptr_array_is_null_terminated (gparray));
+ g_assert_cmpuint (gparray->len, ==, array_size);
+
+ g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, 0), ==, "0");
+ g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, 101), ==, "101");
+
+ g_assert_cmpmem (old_pdata_copy, array_size * sizeof (gpointer),
+ gparray->pdata, array_size * sizeof (gpointer));
+
+ g_ptr_array_add (gparray, g_strdup_printf ("%d", 55));
+ g_ptr_array_insert (gparray, 0, g_strdup_printf ("%d", 33));
+
+ g_assert_cmpuint (gparray->len, ==, array_size + 2);
+ g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, 0), ==, "33");
+ g_assert_cmpstr (
+ (const char *) g_ptr_array_index (gparray, gparray->len - 1), ==, "55");
+
+ g_ptr_array_remove_index (gparray, 0);
+ g_assert_cmpuint (gparray->len, ==, array_size + 1);
+ g_ptr_array_remove_index (gparray, gparray->len - 1);
+ g_assert_cmpuint (gparray->len, ==, array_size);
+
+ g_assert_cmpmem (old_pdata_copy, array_size * sizeof (gpointer),
+ gparray->pdata, array_size * sizeof (gpointer));
+
+ g_ptr_array_unref (gparray);
+ g_free (old_pdata_copy);
+}
+
+static void
+pointer_array_new_take_null_terminated (void)
+{
+ const size_t array_size = 10000;
+ GPtrArray *gparray;
+ gpointer *pdata;
+ gpointer *old_pdata_copy;
+ gsize len;
+
+ gparray = g_ptr_array_new_null_terminated (array_size, NULL, TRUE);
+ g_assert_true (g_ptr_array_is_null_terminated (gparray));
+
+ for (size_t i = 0; i < array_size; i++)
+ g_ptr_array_add (gparray, GUINT_TO_POINTER (i + 1));
+
+ assert_ptr_array_null_terminated (gparray, TRUE);
+ pdata = g_ptr_array_steal (gparray, &len);
+ g_assert_cmpuint (array_size, ==, len);
+ g_assert_nonnull (pdata);
+ g_clear_pointer (&gparray, g_ptr_array_unref);
+
+ old_pdata_copy = g_memdup2 (pdata, len * sizeof (gpointer));
+ gparray = g_ptr_array_new_take_null_terminated (g_steal_pointer (&pdata), NULL);
+ g_assert_true (g_ptr_array_is_null_terminated (gparray));
+ assert_ptr_array_null_terminated (gparray, TRUE);
+ g_assert_cmpuint (gparray->len, ==, array_size);
+
+ g_assert_cmpuint (GPOINTER_TO_UINT (g_ptr_array_index (gparray, 0)), ==, 1);
+ g_assert_cmpuint (GPOINTER_TO_UINT (g_ptr_array_index (gparray, 10)), ==, 11);
+
+ g_assert_cmpmem (old_pdata_copy, array_size * sizeof (gpointer),
+ gparray->pdata, array_size * sizeof (gpointer));
+
+ g_ptr_array_add (gparray, GUINT_TO_POINTER (55));
+ assert_ptr_array_null_terminated (gparray, TRUE);
+
+ g_ptr_array_insert (gparray, 0, GUINT_TO_POINTER (33));
+ assert_ptr_array_null_terminated (gparray, TRUE);
+
+ g_assert_cmpuint (gparray->len, ==, array_size + 2);
+ g_assert_cmpuint (GPOINTER_TO_UINT (g_ptr_array_index (gparray, 0)), ==, 33);
+ g_assert_cmpuint (
+ GPOINTER_TO_UINT (g_ptr_array_index (gparray, gparray->len - 1)), ==, 55);
+
+ g_ptr_array_remove_index (gparray, 0);
+ g_assert_cmpuint (gparray->len, ==, array_size + 1);
+ assert_ptr_array_null_terminated (gparray, TRUE);
+
+ g_ptr_array_remove_index (gparray, gparray->len - 1);
+ g_assert_cmpuint (gparray->len, ==, array_size);
+ assert_ptr_array_null_terminated (gparray, TRUE);
+
+ g_assert_cmpmem (old_pdata_copy, array_size * sizeof (gpointer),
+ gparray->pdata, array_size * sizeof (gpointer));
+
+ g_ptr_array_unref (gparray);
+ g_free (old_pdata_copy);
+}
+
+static void
+pointer_array_new_take_null_terminated_empty (void)
+{
+ GPtrArray *gparray;
+ const gpointer *data = (gpointer []) { NULL };
+
+ gparray = g_ptr_array_new_take_null_terminated (
+ g_memdup2 (data, sizeof (gpointer)), NULL);
+ g_assert_true (g_ptr_array_is_null_terminated (gparray));
+ assert_ptr_array_null_terminated (gparray, TRUE);
+ g_assert_cmpuint (gparray->len, ==, 0);
+
+ g_clear_pointer (&gparray, g_ptr_array_unref);
+
+ gparray = g_ptr_array_new_take_null_terminated (NULL, NULL);
+ g_assert_true (g_ptr_array_is_null_terminated (gparray));
+ assert_ptr_array_null_terminated (gparray, TRUE);
+ g_assert_cmpuint (gparray->len, ==, 0);
+
+ g_clear_pointer (&gparray, g_ptr_array_unref);
+}
+
+static void
+pointer_array_new_take_null_terminated_with_free_func (void)
+{
+ const size_t array_size = 10000;
+ GPtrArray *gparray;
+ gpointer *pdata;
+ gpointer *old_pdata_copy;
+ gsize len;
+
+ gparray = g_ptr_array_new_null_terminated (array_size, g_free, TRUE);
+ g_assert_true (g_ptr_array_is_null_terminated (gparray));
+
+ for (size_t i = 0; i < array_size; i++)
+ g_ptr_array_add (gparray, g_strdup_printf ("%" G_GSIZE_FORMAT, i));
+
+ assert_ptr_array_null_terminated (gparray, TRUE);
+
+ pdata = g_ptr_array_steal (gparray, &len);
+ g_assert_cmpuint (array_size, ==, len);
+ g_assert_nonnull (pdata);
+ g_clear_pointer (&gparray, g_ptr_array_unref);
+
+ old_pdata_copy = g_memdup2 (pdata, len * sizeof (gpointer));
+ gparray = g_ptr_array_new_take_null_terminated (g_steal_pointer (&pdata), g_free);
+ g_assert_true (g_ptr_array_is_null_terminated (gparray));
+ assert_ptr_array_null_terminated (gparray, TRUE);
+ g_assert_cmpuint (gparray->len, ==, array_size);
+
+ g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, 0), ==, "0");
+ g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, 101), ==, "101");
+
+ g_assert_cmpmem (old_pdata_copy, array_size * sizeof (gpointer),
+ gparray->pdata, array_size * sizeof (gpointer));
+
+ g_ptr_array_add (gparray, g_strdup_printf ("%d", 55));
+ assert_ptr_array_null_terminated (gparray, TRUE);
+
+ g_ptr_array_insert (gparray, 0, g_strdup_printf ("%d", 33));
+ assert_ptr_array_null_terminated (gparray, TRUE);
+
+ g_assert_cmpuint (gparray->len, ==, array_size + 2);
+ g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, 0), ==, "33");
+ g_assert_cmpstr (
+ (const char *) g_ptr_array_index (gparray, gparray->len - 1), ==, "55");
+
+ g_ptr_array_remove_index (gparray, 0);
+ g_assert_cmpuint (gparray->len, ==, array_size + 1);
+ assert_ptr_array_null_terminated (gparray, TRUE);
+
+ g_ptr_array_remove_index (gparray, gparray->len - 1);
+ g_assert_cmpuint (gparray->len, ==, array_size);
+ assert_ptr_array_null_terminated (gparray, TRUE);
+
+ g_assert_cmpmem (old_pdata_copy, array_size * sizeof (gpointer),
+ gparray->pdata, array_size * sizeof (gpointer));
+
+ g_ptr_array_unref (gparray);
+ g_free (old_pdata_copy);
+}
+
+static void
+pointer_array_new_take_null_terminated_from_gstrv (void)
+{
+ GPtrArray *gparray;
+ char *joined;
+
+ gparray = g_ptr_array_new_take_null_terminated (
+ (gpointer) g_strsplit ("A.dot.separated.string", ".", -1), g_free);
+
+ g_assert_cmpstr (
+ (const char *) g_ptr_array_index (gparray, 0), ==, "A");
+ g_assert_cmpstr (
+ (const char *) g_ptr_array_index (gparray, 1), ==, "dot");
+ g_assert_cmpstr (
+ (const char *) g_ptr_array_index (gparray, 2), ==, "separated");
+ g_assert_cmpstr (
+ (const char *) g_ptr_array_index (gparray, 3), ==, "string");
+
+ g_assert_null (g_ptr_array_index (gparray, 4));
+
+ joined = g_strjoinv (".", (char **) gparray->pdata);
+ g_assert_cmpstr (joined, ==, "A.dot.separated.string");
+
+ g_ptr_array_unref (gparray);
+ g_free (joined);
+}
+
+static void
+pointer_array_new_from_array (void)
+{
+ const size_t array_size = 10000;
+ GPtrArray *source_array;
+ GPtrArray *gparray;
+ gpointer *old_pdata_copy;
+
+ source_array = g_ptr_array_new ();
+ for (size_t i = 0; i < array_size; i++)
+ g_ptr_array_add (source_array, GUINT_TO_POINTER (i));
+
+ g_assert_cmpuint (array_size, ==, source_array->len);
+ g_assert_nonnull (source_array->pdata);
+
+ gparray = g_ptr_array_new_from_array (source_array->pdata, source_array->len,
+ NULL, NULL, NULL);
+
+ old_pdata_copy =
+ g_memdup2 (source_array->pdata, source_array->len * sizeof (gpointer));
+ g_assert_nonnull (old_pdata_copy);
+ g_clear_pointer (&source_array, g_ptr_array_unref);
+
+ g_assert_false (g_ptr_array_is_null_terminated (gparray));
+ g_assert_cmpuint (gparray->len, ==, array_size);
+
+ g_assert_cmpuint (GPOINTER_TO_UINT (g_ptr_array_index (gparray, 0)), ==, 0);
+ g_assert_cmpuint (GPOINTER_TO_UINT (g_ptr_array_index (gparray, 10)), ==, 10);
+
+ g_assert_cmpmem (old_pdata_copy, array_size * sizeof (gpointer),
+ gparray->pdata, array_size * sizeof (gpointer));
+
+ g_ptr_array_add (gparray, GUINT_TO_POINTER (55));
+ g_ptr_array_insert (gparray, 0, GUINT_TO_POINTER (33));
+
+ g_assert_cmpuint (gparray->len, ==, array_size + 2);
+ g_assert_cmpuint (GPOINTER_TO_UINT (g_ptr_array_index (gparray, 0)), ==, 33);
+ g_assert_cmpuint (
+ GPOINTER_TO_UINT (g_ptr_array_index (gparray, gparray->len - 1)), ==, 55);
+
+ g_ptr_array_remove_index (gparray, 0);
+ g_assert_cmpuint (gparray->len, ==, array_size + 1);
+ g_ptr_array_remove_index (gparray, gparray->len - 1);
+ g_assert_cmpuint (gparray->len, ==, array_size);
+
+ g_assert_cmpmem (old_pdata_copy, array_size * sizeof (gpointer),
+ gparray->pdata, array_size * sizeof (gpointer));
+
+ g_ptr_array_unref (gparray);
+ g_free (old_pdata_copy);
+}
+
+static void
+pointer_array_new_from_array_empty (void)
+{
+ GPtrArray *gparray;
+ gpointer empty_array[] = {0};
+
+ gparray = g_ptr_array_new_from_array (empty_array, 0, NULL, NULL, NULL);
+ g_assert_false (g_ptr_array_is_null_terminated (gparray));
+ g_assert_cmpuint (gparray->len, ==, 0);
+
+ g_clear_pointer (&gparray, g_ptr_array_unref);
+
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "*data*!=*NULL*||*len*==*0*");
+ g_assert_null (g_ptr_array_new_from_array (NULL, 10, NULL, NULL, NULL));
+ g_test_assert_expected_messages ();
+}
+
+static void
+pointer_array_new_from_array_overflow (void)
+{
+#if SIZE_WIDTH <= UINT_WIDTH
+ g_test_skip ("Overflow test requires UINT_WIDTH > SIZE_WIDTH.");
+#else
+ if (!g_test_undefined ())
+ return;
+
+ /* Check for overflow should happen before data is accessed. */
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "*assertion 'len <= G_MAXUINT' failed");
+ g_assert_null (g_ptr_array_new_from_array (
+ (gpointer []) { NULL }, (gsize) G_MAXUINT + 1, NULL, NULL, NULL));
+ g_test_assert_expected_messages ();
+#endif
+}
+
+static void
+pointer_array_new_from_array_with_copy_and_free_func (void)
+{
+ const size_t array_size = 10000;
+ GPtrArray *source_array;
+ GPtrArray *gparray;
+ gpointer *old_pdata_copy;
+
+ source_array = g_ptr_array_new_with_free_func (g_free);
+ for (size_t i = 0; i < array_size; i++)
+ g_ptr_array_add (source_array, g_strdup_printf ("%" G_GSIZE_FORMAT, i));
+
+ g_assert_cmpuint (array_size, ==, source_array->len);
+ g_assert_nonnull (source_array->pdata);
+
+ gparray = g_ptr_array_new_from_array (source_array->pdata, source_array->len,
+ (GCopyFunc) g_strdup, NULL, g_free);
+
+ old_pdata_copy =
+ g_memdup2 (source_array->pdata, source_array->len * sizeof (gpointer));
+ g_assert_nonnull (old_pdata_copy);
+
+ for (size_t i = 0; i < gparray->len; i++)
+ {
+ g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, i), ==,
+ (const char *) old_pdata_copy[i]);
+ }
+
+ g_clear_pointer (&source_array, g_ptr_array_unref);
+
+ g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, 0), ==, "0");
+ g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, 101), ==, "101");
+
+ g_ptr_array_add (gparray, g_strdup_printf ("%d", 55));
+ g_ptr_array_insert (gparray, 0, g_strdup_printf ("%d", 33));
+
+ g_assert_cmpuint (gparray->len, ==, array_size + 2);
+ g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, 0), ==, "33");
+ g_assert_cmpstr (
+ (const char *) g_ptr_array_index (gparray, gparray->len - 1), ==, "55");
+
+ g_ptr_array_remove_index (gparray, 0);
+ g_assert_cmpuint (gparray->len, ==, array_size + 1);
+ g_ptr_array_remove_index (gparray, gparray->len - 1);
+ g_assert_cmpuint (gparray->len, ==, array_size);
+
+ g_ptr_array_unref (gparray);
+ g_free (old_pdata_copy);
+}
+
+static void
+pointer_array_new_from_null_terminated_array (void)
+{
+ const size_t array_size = 10000;
+ GPtrArray *source_array;
+ GPtrArray *gparray;
+ gpointer *old_pdata_copy;
+
+ source_array = g_ptr_array_new_null_terminated (array_size, NULL, TRUE);
+ g_assert_true (g_ptr_array_is_null_terminated (source_array));
+
+ for (size_t i = 0; i < array_size; i++)
+ g_ptr_array_add (source_array, GUINT_TO_POINTER (i + 1));
+
+ g_assert_cmpuint (array_size, ==, source_array->len);
+ g_assert_nonnull (source_array->pdata);
+
+ old_pdata_copy =
+ g_memdup2 (source_array->pdata, source_array->len * sizeof (gpointer));
+ g_assert_nonnull (old_pdata_copy);
+
+ gparray = g_ptr_array_new_from_null_terminated_array (source_array->pdata,
+ NULL, NULL, NULL);
+ g_assert_true (g_ptr_array_is_null_terminated (source_array));
+ assert_ptr_array_null_terminated (gparray, TRUE);
+
+ g_clear_pointer (&source_array, g_ptr_array_unref);
+
+ g_assert_true (g_ptr_array_is_null_terminated (gparray));
+ g_assert_cmpuint (gparray->len, ==, array_size);
+
+ g_assert_cmpuint (GPOINTER_TO_UINT (g_ptr_array_index (gparray, 0)), ==, 1);
+ g_assert_cmpuint (GPOINTER_TO_UINT (g_ptr_array_index (gparray, 10)), ==, 11);
+
+ g_assert_cmpmem (old_pdata_copy, array_size * sizeof (gpointer),
+ gparray->pdata, array_size * sizeof (gpointer));
+
+ g_ptr_array_add (gparray, GUINT_TO_POINTER (55));
+ assert_ptr_array_null_terminated (gparray, TRUE);
+
+ g_ptr_array_insert (gparray, 0, GUINT_TO_POINTER (33));
+ assert_ptr_array_null_terminated (gparray, TRUE);
+
+ g_assert_cmpuint (gparray->len, ==, array_size + 2);
+ g_assert_cmpuint (GPOINTER_TO_UINT (g_ptr_array_index (gparray, 0)), ==, 33);
+ g_assert_cmpuint (
+ GPOINTER_TO_UINT (g_ptr_array_index (gparray, gparray->len - 1)), ==, 55);
+
+ g_ptr_array_remove_index (gparray, 0);
+ g_assert_cmpuint (gparray->len, ==, array_size + 1);
+ assert_ptr_array_null_terminated (gparray, TRUE);
+
+ g_ptr_array_remove_index (gparray, gparray->len - 1);
+ g_assert_cmpuint (gparray->len, ==, array_size);
+ assert_ptr_array_null_terminated (gparray, TRUE);
+
+ g_assert_cmpmem (old_pdata_copy, array_size * sizeof (gpointer),
+ gparray->pdata, array_size * sizeof (gpointer));
+
+ g_ptr_array_unref (gparray);
+ g_free (old_pdata_copy);
+}
+
+static void
+pointer_array_new_from_null_terminated_array_empty (void)
+{
+ GPtrArray *gparray;
+
+ gparray = g_ptr_array_new_from_null_terminated_array (
+ (gpointer []) { NULL }, NULL, NULL, NULL);
+ g_assert_true (g_ptr_array_is_null_terminated (gparray));
+ assert_ptr_array_null_terminated (gparray, TRUE);
+ g_assert_cmpuint (gparray->len, ==, 0);
+
+ g_clear_pointer (&gparray, g_ptr_array_unref);
+
+ gparray = g_ptr_array_new_from_null_terminated_array (
+ NULL, NULL, NULL, NULL);
+ g_assert_true (g_ptr_array_is_null_terminated (gparray));
+ assert_ptr_array_null_terminated (gparray, TRUE);
+ g_assert_cmpuint (gparray->len, ==, 0);
+
+ g_clear_pointer (&gparray, g_ptr_array_unref);
+}
+
+static void
+pointer_array_new_from_null_terminated_array_with_copy_and_free_func (void)
+{
+ const size_t array_size = 10000;
+ GPtrArray *source_array;
+ GPtrArray *gparray;
+ GStrv old_pdata_copy;
+
+ source_array = g_ptr_array_new_null_terminated (array_size, g_free, TRUE);
+ g_assert_true (g_ptr_array_is_null_terminated (source_array));
+
+ for (size_t i = 0; i < array_size; i++)
+ g_ptr_array_add (source_array, g_strdup_printf ("%" G_GSIZE_FORMAT, i));
+
+ g_assert_cmpuint (array_size, ==, source_array->len);
+ g_assert_nonnull (source_array->pdata);
+
+ old_pdata_copy = g_strdupv ((char **) source_array->pdata);
+ g_assert_cmpuint (g_strv_length (old_pdata_copy), ==, array_size);
+ g_assert_nonnull (old_pdata_copy);
+ g_clear_pointer (&source_array, g_ptr_array_unref);
+
+ gparray = g_ptr_array_new_from_null_terminated_array (
+ (gpointer* ) old_pdata_copy, (GCopyFunc) g_strdup, NULL, g_free);
+ g_assert_true (g_ptr_array_is_null_terminated (gparray));
+ assert_ptr_array_null_terminated (gparray, TRUE);
+
+ for (size_t i = 0; i < gparray->len; i++)
+ {
+ g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, i), ==,
+ (const char *) old_pdata_copy[i]);
+ }
+
+ g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, 0), ==, "0");
+ g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, 101), ==, "101");
+
+ g_ptr_array_add (gparray, g_strdup_printf ("%d", 55));
+ assert_ptr_array_null_terminated (gparray, TRUE);
+
+ g_ptr_array_insert (gparray, 0, g_strdup_printf ("%d", 33));
+ assert_ptr_array_null_terminated (gparray, TRUE);
+
+ g_assert_cmpuint (gparray->len, ==, array_size + 2);
+ g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, 0), ==, "33");
+ g_assert_cmpstr (
+ (const char *) g_ptr_array_index (gparray, gparray->len - 1), ==, "55");
+
+ g_ptr_array_remove_index (gparray, 0);
+ assert_ptr_array_null_terminated (gparray, TRUE);
+ g_assert_cmpuint (gparray->len, ==, array_size + 1);
+
+ g_ptr_array_remove_index (gparray, gparray->len - 1);
+ assert_ptr_array_null_terminated (gparray, TRUE);
+ g_assert_cmpuint (gparray->len, ==, array_size);
+
+ for (size_t i = 0; i < gparray->len; i++)
+ {
+ g_assert_cmpstr ((const char *) g_ptr_array_index (gparray, i), ==,
+ (const char *) old_pdata_copy[i]);
+ }
+
+ g_ptr_array_unref (gparray);
+ g_strfreev (old_pdata_copy);
+}
+
+static void
+pointer_array_new_from_null_terminated_array_from_gstrv (void)
+{
+ GPtrArray *gparray;
+ GStrv strv;
+ char *joined;
+
+ strv = g_strsplit ("A.dot.separated.string", ".", -1);
+ gparray = g_ptr_array_new_from_null_terminated_array (
+ (gpointer) strv, NULL, NULL, NULL);
+
+ g_assert_cmpstr (
+ (const char *) g_ptr_array_index (gparray, 0), ==, "A");
+ g_assert_true (g_ptr_array_index (gparray, 0) == strv[0]);
+ g_assert_cmpstr (
+ (const char *) g_ptr_array_index (gparray, 1), ==, "dot");
+ g_assert_true (g_ptr_array_index (gparray, 1) == strv[1]);
+ g_assert_cmpstr (
+ (const char *) g_ptr_array_index (gparray, 2), ==, "separated");
+ g_assert_true (g_ptr_array_index (gparray, 2) == strv[2]);
+ g_assert_cmpstr (
+ (const char *) g_ptr_array_index (gparray, 3), ==, "string");
+ g_assert_true (g_ptr_array_index (gparray, 3) == strv[3]);
+
+ g_assert_null (strv[4]);
+ g_assert_null (g_ptr_array_index (gparray, 4));
+
+ joined = g_strjoinv (".", (char **) gparray->pdata);
+ g_assert_cmpstr (joined, ==, "A.dot.separated.string");
+
+ g_ptr_array_unref (gparray);
+ g_strfreev (strv);
+ g_free (joined);
+}
+
+static void
pointer_array_ref_count (gconstpointer test_data)
{
const gboolean null_terminated = GPOINTER_TO_INT (test_data);
@@ -2158,6 +2980,10 @@ main (int argc, char *argv[])
/* array tests */
g_test_add_func ("/array/new/zero-terminated", array_new_zero_terminated);
+ g_test_add_func ("/array/new/take", array_new_take);
+ g_test_add_func ("/array/new/take/empty", array_new_take_empty);
+ g_test_add_func ("/array/new/take/overflow", array_new_take_overflow);
+ g_test_add_func ("/array/new/take-zero-terminated", array_new_take_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);
@@ -2186,6 +3012,22 @@ main (int argc, char *argv[])
g_test_add_func ("/pointerarray/free/null-terminated", pointer_array_free_null_terminated);
g_test_add_func ("/pointerarray/add", pointer_array_add);
g_test_add_func ("/pointerarray/insert", pointer_array_insert);
+ g_test_add_func ("/pointerarray/new-take", pointer_array_new_take);
+ g_test_add_func ("/pointerarray/new-take/empty", pointer_array_new_take_empty);
+ g_test_add_func ("/pointerarray/new-take/overflow", pointer_array_new_take_overflow);
+ g_test_add_func ("/pointerarray/new-take/with-free-func", pointer_array_new_take_with_free_func);
+ g_test_add_func ("/pointerarray/new-take-null-terminated", pointer_array_new_take_null_terminated);
+ g_test_add_func ("/pointerarray/new-take-null-terminated/empty", pointer_array_new_take_null_terminated_empty);
+ g_test_add_func ("/pointerarray/new-take-null-terminated/with-free-func", pointer_array_new_take_null_terminated_with_free_func);
+ g_test_add_func ("/pointerarray/new-take-null-terminated/from-gstrv", pointer_array_new_take_null_terminated_from_gstrv);
+ g_test_add_func ("/pointerarray/new-from-array", pointer_array_new_from_array);
+ g_test_add_func ("/pointerarray/new-from-array/empty", pointer_array_new_from_array_empty);
+ g_test_add_func ("/pointerarray/new-from-array/overflow", pointer_array_new_from_array_overflow);
+ g_test_add_func ("/pointerarray/new-from-array/with-copy-and-free-func", pointer_array_new_from_array_with_copy_and_free_func);
+ g_test_add_func ("/pointerarray/new-from-null-terminated-array", pointer_array_new_from_null_terminated_array);
+ g_test_add_func ("/pointerarray/new-from-null-terminated-array/empty", pointer_array_new_from_null_terminated_array_empty);
+ g_test_add_func ("/pointerarray/new-from-null-terminated-array/with-copy-and-free-func", pointer_array_new_from_null_terminated_array_with_copy_and_free_func);
+ g_test_add_func ("/pointerarray/new-from-null-terminated-array/from-gstrv", pointer_array_new_from_null_terminated_array_from_gstrv);
g_test_add_data_func ("/pointerarray/ref-count/not-null-terminated", GINT_TO_POINTER (0), pointer_array_ref_count);
g_test_add_data_func ("/pointerarray/ref-count/null-terminated", GINT_TO_POINTER (1), pointer_array_ref_count);
g_test_add_func ("/pointerarray/free-func", pointer_array_free_func);