Merge branch 'wsign-conversion' into 'main'

gqsort: Add g_sort_array() and deprecate g_qsort_with_data()

See merge request GNOME/glib!4127
This commit is contained in:
Philip Withnall 2024-07-04 12:33:38 +00:00
commit 70784b99b1
6 changed files with 146 additions and 41 deletions

View File

@ -925,10 +925,10 @@ g_array_sort (GArray *farray,
/* Don't use qsort as we want a guaranteed stable sort */ /* Don't use qsort as we want a guaranteed stable sort */
if (array->len > 0) if (array->len > 0)
g_qsort_with_data (array->data, g_sort_array (array->data,
array->len, array->len,
array->elt_size, array->elt_size,
(GCompareDataFunc)compare_func, (GCompareDataFunc) compare_func,
NULL); NULL);
} }
@ -957,7 +957,7 @@ g_array_sort_with_data (GArray *farray,
g_return_if_fail (array != NULL); g_return_if_fail (array != NULL);
if (array->len > 0) if (array->len > 0)
g_qsort_with_data (array->data, g_sort_array (array->data,
array->len, array->len,
array->elt_size, array->elt_size,
compare_func, compare_func,
@ -2338,23 +2338,23 @@ g_ptr_array_insert (GPtrArray *array,
gpointer data) gpointer data)
{ {
GRealPtrArray *rarray = (GRealPtrArray *)array; GRealPtrArray *rarray = (GRealPtrArray *)array;
guint real_index;
g_return_if_fail (rarray); g_return_if_fail (rarray);
g_return_if_fail (index_ >= -1); g_return_if_fail (index_ >= -1);
g_return_if_fail (index_ <= (gint)rarray->len); g_return_if_fail (index_ < 0 || (guint) index_ <= rarray->len);
g_ptr_array_maybe_expand (rarray, 1u + rarray->null_terminated); g_ptr_array_maybe_expand (rarray, 1u + rarray->null_terminated);
if (index_ < 0) real_index = (index_ >= 0) ? (guint) index_ : rarray->len;
index_ = rarray->len;
if ((guint) index_ < rarray->len) if (real_index < rarray->len)
memmove (&(rarray->pdata[index_ + 1]), memmove (&(rarray->pdata[real_index + 1]),
&(rarray->pdata[index_]), &(rarray->pdata[real_index]),
(rarray->len - index_) * sizeof (gpointer)); (rarray->len - real_index) * sizeof (gpointer));
rarray->len++; rarray->len++;
rarray->pdata[index_] = data; rarray->pdata[real_index] = data;
ptr_array_maybe_null_terminate (rarray); ptr_array_maybe_null_terminate (rarray);
} }
@ -2413,10 +2413,10 @@ g_ptr_array_sort (GPtrArray *array,
/* Don't use qsort as we want a guaranteed stable sort */ /* Don't use qsort as we want a guaranteed stable sort */
if (array->len > 0) if (array->len > 0)
g_qsort_with_data (array->pdata, g_sort_array (array->pdata,
array->len, array->len,
sizeof (gpointer), sizeof (gpointer),
(GCompareDataFunc)compare_func, (GCompareDataFunc) compare_func,
NULL); NULL);
} }
@ -2493,7 +2493,7 @@ g_ptr_array_sort_with_data (GPtrArray *array,
g_return_if_fail (array != NULL); g_return_if_fail (array != NULL);
if (array->len > 0) if (array->len > 0)
g_qsort_with_data (array->pdata, g_sort_array (array->pdata,
array->len, array->len,
sizeof (gpointer), sizeof (gpointer),
compare_func, compare_func,

View File

@ -289,10 +289,14 @@ msort_r (void *b, size_t n, size_t s, GCompareDataFunc cmp, void *arg)
* @compare_func: (scope call): function to compare elements * @compare_func: (scope call): function to compare elements
* @user_data: data to pass to @compare_func * @user_data: data to pass to @compare_func
* *
* This is just like the standard C qsort() function, but * This is just like the standard C [`qsort()`](man:qsort(3)) function, but
* the comparison routine accepts a user data argument. * the comparison routine accepts a user data argument
* (like [`qsort_r()`](man:qsort_r(3))).
* *
* This is guaranteed to be a stable sort since version 2.32. * Unlike `qsort()`, this is guaranteed to be a stable sort (since GLib 2.32).
*
* Deprecated: 2.82: `total_elems` is too small to represent larger arrays; use
* [func@GLib.sort_array] instead
*/ */
void void
g_qsort_with_data (gconstpointer pbase, g_qsort_with_data (gconstpointer pbase,
@ -301,5 +305,29 @@ g_qsort_with_data (gconstpointer pbase,
GCompareDataFunc compare_func, GCompareDataFunc compare_func,
gpointer user_data) gpointer user_data)
{ {
msort_r ((gpointer)pbase, total_elems, size, compare_func, user_data); g_sort_array (pbase, total_elems, size, compare_func, user_data);
}
/**
* g_sort_array:
* @array: (not nullable) (array length=n_elements): start of array to sort
* @n_elements: number of elements in the array
* @element_size: size of each element
* @compare_func: (scope call): function to compare elements
* @user_data: data to pass to @compare_func
*
* This is just like the standard C [`qsort()`](man:qsort(3)) function, but
* the comparison routine accepts a user data argument
* (like [`qsort_r()`](man:qsort_r(3))).
*
* Unlike `qsort()`, this is guaranteed to be a stable sort.
*/
void
g_sort_array (const void *array,
size_t n_elements,
size_t element_size,
GCompareDataFunc compare_func,
void *user_data)
{
msort_r ((void *) array, n_elements, element_size, compare_func, user_data);
} }

View File

@ -35,13 +35,20 @@
G_BEGIN_DECLS G_BEGIN_DECLS
GLIB_AVAILABLE_IN_ALL GLIB_DEPRECATED_IN_2_82_FOR(g_sort_array)
void g_qsort_with_data (gconstpointer pbase, void g_qsort_with_data (gconstpointer pbase,
gint total_elems, gint total_elems,
gsize size, gsize size,
GCompareDataFunc compare_func, GCompareDataFunc compare_func,
gpointer user_data); gpointer user_data);
GLIB_AVAILABLE_IN_2_82
void g_sort_array (const void *array,
size_t n_elements,
size_t element_size,
GCompareDataFunc compare_func,
void *user_data);
G_END_DECLS G_END_DECLS
#endif /* __G_QSORT_H__ */ #endif /* __G_QSORT_H__ */

View File

@ -40,7 +40,7 @@ test_sort_basic (void)
data[i] = g_random_int_range (0, 10000); data[i] = g_random_int_range (0, 10000);
} }
g_qsort_with_data (data, 10000, sizeof (int), int_compare_data, NULL); g_sort_array (data, 10000, sizeof (int), int_compare_data, NULL);
for (i = 1; i < 10000; i++) for (i = 1; i < 10000; i++)
g_assert_cmpint (data[i -1], <=, data[i]); g_assert_cmpint (data[i -1], <=, data[i]);
@ -63,7 +63,7 @@ test_sort_zero_elements (void)
} }
/* 0 elements is a valid case */ /* 0 elements is a valid case */
g_qsort_with_data (data, 0, sizeof (int), int_compare_data, NULL); g_sort_array (data, 0, sizeof (int), int_compare_data, NULL);
for (i = 0; i < 100; i++) for (i = 0; i < 100; i++)
g_assert_cmpint (data[i], ==, data_copy[i]); g_assert_cmpint (data[i], ==, data_copy[i]);
@ -105,7 +105,7 @@ test_sort_stable (void)
data[i].i = i; data[i].i = i;
} }
g_qsort_with_data (data, 10000, sizeof (SortItem), item_compare_data, NULL); g_sort_array (data, 10000, sizeof (SortItem), item_compare_data, NULL);
for (i = 1; i < 10000; i++) for (i = 1; i < 10000; i++)
{ {
@ -129,7 +129,7 @@ test_sort_big (void)
data[i].i = i; data[i].i = i;
} }
g_qsort_with_data (data, 10000, sizeof (BigItem), item_compare_data, NULL); g_sort_array (data, 10000, sizeof (BigItem), item_compare_data, NULL);
for (i = 1; i < 10000; i++) for (i = 1; i < 10000; i++)
{ {
@ -140,6 +140,28 @@ test_sort_big (void)
g_free (data); g_free (data);
} }
static void
test_sort_deprecated (void)
{
gint *data;
gint i;
data = g_malloc (10000 * sizeof (int));
for (i = 0; i < 10000; i++)
{
data[i] = g_random_int_range (0, 10000);
}
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
g_qsort_with_data (data, 10000, sizeof (int), int_compare_data, NULL);
G_GNUC_END_IGNORE_DEPRECATIONS
for (i = 1; i < 10000; i++)
g_assert_cmpint (data[i -1], <=, data[i]);
g_free (data);
}
int int
main (int argc, char *argv[]) main (int argc, char *argv[])
{ {
@ -149,6 +171,7 @@ main (int argc, char *argv[])
g_test_add_func ("/sort/zero-elements", test_sort_zero_elements); g_test_add_func ("/sort/zero-elements", test_sort_zero_elements);
g_test_add_func ("/sort/stable", test_sort_stable); g_test_add_func ("/sort/stable", test_sort_stable);
g_test_add_func ("/sort/big", test_sort_big); g_test_add_func ("/sort/big", test_sort_big);
g_test_add_func ("/sort/deprecated", test_sort_deprecated);
return g_test_run (); return g_test_run ();
} }

View File

@ -364,7 +364,7 @@ g_value_array_sort_with_data (GValueArray *value_array,
g_return_val_if_fail (compare_func != NULL, NULL); g_return_val_if_fail (compare_func != NULL, NULL);
if (value_array->n_values) if (value_array->n_values)
g_qsort_with_data (value_array->values, g_sort_array (value_array->values,
value_array->n_values, value_array->n_values,
sizeof (value_array->values[0]), sizeof (value_array->values[0]),
compare_func, user_data); compare_func, user_data);

View File

@ -664,6 +664,52 @@ test_valuearray_basic (void)
g_value_array_free (a2); g_value_array_free (a2);
} }
static gint
cmpint_with_data (gconstpointer a,
gconstpointer b,
gpointer user_data)
{
const GValue *aa = a;
const GValue *bb = b;
g_assert_cmpuint (GPOINTER_TO_UINT (user_data), ==, 123);
return g_value_get_int (aa) - g_value_get_int (bb);
}
static void
test_value_array_sort_with_data (void)
{
GValueArray *a, *a2;
GValue v = G_VALUE_INIT;
a = g_value_array_new (20);
/* Try sorting an empty array. */
a2 = g_value_array_sort_with_data (a, cmpint_with_data, GUINT_TO_POINTER (456));
g_assert_cmpuint (a->n_values, ==, 0);
g_assert_true (a2 == a);
/* Add some values and try sorting them. */
g_value_init (&v, G_TYPE_INT);
for (unsigned int i = 0; i < 100; i++)
{
g_value_set_int (&v, 100 - i);
g_value_array_append (a, &v);
}
g_assert_cmpint (a->n_values, ==, 100);
a2 = g_value_array_sort_with_data (a, cmpint_with_data, GUINT_TO_POINTER (123));
for (unsigned int i = 0; i < a->n_values - 1; i++)
g_assert_cmpint (g_value_get_int (&a->values[i]), <=, g_value_get_int (&a->values[i+1]));
g_assert_true (a2 == a);
g_value_array_free (a);
}
/* We create some dummy objects with this relationship: /* We create some dummy objects with this relationship:
* *
* GObject TestInterface * GObject TestInterface
@ -765,6 +811,7 @@ main (int argc, char *argv[])
g_test_add_func ("/value/basic", test_value_basic); g_test_add_func ("/value/basic", test_value_basic);
g_test_add_func ("/value/array/basic", test_valuearray_basic); g_test_add_func ("/value/array/basic", test_valuearray_basic);
g_test_add_func ("/value/array/sort-with-data", test_value_array_sort_with_data);
g_test_add_func ("/value/collection", test_collection); g_test_add_func ("/value/collection", test_collection);
g_test_add_func ("/value/copying", test_copying); g_test_add_func ("/value/copying", test_copying);
g_test_add_func ("/value/enum-transformation", test_enum_transformation); g_test_add_func ("/value/enum-transformation", test_enum_transformation);