garray: Add g_ptr_array_sort_values[_with_data]() wrappers

Historically GPtrArray made possible to compare pointers of pointers values
that it holds, however this is inconvenient in most cases as it requires
wrapper functions and not friendly castings.

So, add two functions that allow to perform the comparisons between the
pointer values that a GPtrArray holds following the same syntax that we
share everywhere in the codebase.
This commit is contained in:
Marco Trevisan (Treviño) 2022-12-20 00:14:18 +01:00 committed by Philip Withnall
parent abd76e0286
commit 0ffd23cac4
4 changed files with 307 additions and 4 deletions

View File

@ -2736,6 +2736,8 @@ g_ptr_array_steal_index
g_ptr_array_steal_index_fast
g_ptr_array_sort
g_ptr_array_sort_with_data
g_ptr_array_sort_values
g_ptr_array_sort_values_with_data
g_ptr_array_set_size
g_ptr_array_index
g_ptr_array_free

View File

@ -2124,7 +2124,10 @@ g_ptr_array_insert (GPtrArray *array,
*
* Note that the comparison function for g_ptr_array_sort() doesn't
* take the pointers from the array as arguments, it takes pointers to
* the pointers in the array. Here is a full example of usage:
* the pointers in the array.
*
* Use g_ptr_array_sort_with_data() if you want to use normal
* #GCompareFuncs, otherwise here is a full example of use:
*
* |[<!-- language="C" -->
* typedef struct
@ -2181,7 +2184,10 @@ g_ptr_array_sort (GPtrArray *array,
*
* Note that the comparison function for g_ptr_array_sort_with_data()
* doesn't take the pointers from the array as arguments, it takes
* pointers to the pointers in the array. Here is a full example of use:
* pointers to the pointers in the array.
*
* Use g_ptr_array_sort_with_data() if you want to use normal
* #GCompareDataFuncs, otherwise here is a full example of use:
*
* |[<!-- language="C" -->
* typedef enum { SORT_NAME, SORT_SIZE } SortMode;
@ -2245,6 +2251,80 @@ g_ptr_array_sort_with_data (GPtrArray *array,
user_data);
}
static inline gint
compare_ptr_array_values (gconstpointer a, gconstpointer b, gpointer user_data)
{
gconstpointer aa = *((gconstpointer *) a);
gconstpointer bb = *((gconstpointer *) b);
GCompareFunc compare_func = user_data;
return compare_func (aa, bb);
}
/**
* g_ptr_array_sort_values:
* @array: a #GPtrArray
* @compare_func: a #GCompareFunc comparison function
*
* 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 first arg is
* greater than second arg).
*
* This is guaranteed to be a stable sort.
*
* Since: 2.76
*/
void
g_ptr_array_sort_values (GPtrArray *array,
GCompareFunc compare_func)
{
g_ptr_array_sort_with_data (array, compare_ptr_array_values, compare_func);
}
typedef struct
{
GCompareDataFunc compare_func;
gpointer user_data;
} GPtrArraySortValuesData;
static inline gint
compare_ptr_array_values_with_data (gconstpointer a,
gconstpointer b,
gpointer user_data)
{
gconstpointer aa = *((gconstpointer *) a);
gconstpointer bb = *((gconstpointer *) b);
GPtrArraySortValuesData *data = user_data;
return data->compare_func (aa, bb, data->user_data);
}
/**
* g_ptr_array_sort_values_with_data:
* @array: a #GPtrArray
* @compare_func: a #GCompareDataFunc comparison function
* @user_data: data to pass to @compare_func
*
* Like g_ptr_array_sort_values(), but the comparison function has an extra
* user data argument.
*
* This is guaranteed to be a stable sort.
*
* Since: 2.76
*/
void
g_ptr_array_sort_values_with_data (GPtrArray *array,
GCompareDataFunc compare_func,
gpointer user_data)
{
g_ptr_array_sort_with_data (array, compare_ptr_array_values_with_data,
&(GPtrArraySortValuesData){
.compare_func = compare_func,
.user_data = user_data,
});
}
/**
* g_ptr_array_foreach:
* @array: a #GPtrArray

View File

@ -242,6 +242,13 @@ GLIB_AVAILABLE_IN_ALL
void g_ptr_array_sort_with_data (GPtrArray *array,
GCompareDataFunc compare_func,
gpointer user_data);
GLIB_AVAILABLE_IN_2_76
void g_ptr_array_sort_values (GPtrArray *array,
GCompareFunc compare_func);
GLIB_AVAILABLE_IN_2_76
void g_ptr_array_sort_values_with_data (GPtrArray *array,
GCompareDataFunc compare_func,
gpointer user_data);
GLIB_AVAILABLE_IN_ALL
void g_ptr_array_foreach (GPtrArray *array,
GFunc func,

View File

@ -1474,13 +1474,25 @@ pointer_array_extend_and_steal (void)
g_free (array_test);
}
static gint
ptr_compare_values (gconstpointer p1, gconstpointer p2)
{
return GPOINTER_TO_INT (p1) - GPOINTER_TO_INT (p2);
}
static gint
ptr_compare (gconstpointer p1, gconstpointer p2)
{
gpointer i1 = *(gpointer*)p1;
gpointer i2 = *(gpointer*)p2;
return GPOINTER_TO_INT (i1) - GPOINTER_TO_INT (i2);
return ptr_compare_values (i1, i2);
}
static gint
ptr_compare_values_data (gconstpointer p1, gconstpointer p2, gpointer data)
{
return GPOINTER_TO_INT (p1) - GPOINTER_TO_INT (p2);
}
static gint
@ -1489,7 +1501,7 @@ ptr_compare_data (gconstpointer p1, gconstpointer p2, gpointer data)
gpointer i1 = *(gpointer*)p1;
gpointer i2 = *(gpointer*)p2;
return GPOINTER_TO_INT (i1) - GPOINTER_TO_INT (i2);
return ptr_compare_values_data (i1, i2, data);
}
static void
@ -1696,6 +1708,204 @@ pointer_array_sort_with_data (void)
g_ptr_array_free (gparray, TRUE);
}
static void
pointer_array_sort_values (void)
{
GPtrArray *gparray;
gint i;
gint val;
gint prev, cur;
gparray = g_ptr_array_new ();
/* Sort empty array */
g_ptr_array_sort_values (gparray, ptr_compare_values);
for (i = 0; i < 10000; i++)
{
val = g_random_int_range (0, 10000);
g_ptr_array_add (gparray, GINT_TO_POINTER (val));
}
g_ptr_array_sort_values (gparray, ptr_compare_values);
prev = -1;
for (i = 0; i < 10000; i++)
{
cur = GPOINTER_TO_INT (g_ptr_array_index (gparray, i));
g_assert_cmpint (prev, <=, cur);
prev = cur;
}
g_clear_pointer (&gparray, g_ptr_array_unref);
gparray = g_ptr_array_new ();
g_ptr_array_add (gparray, "dddd");
g_ptr_array_add (gparray, "cccc");
g_ptr_array_add (gparray, NULL);
g_ptr_array_add (gparray, "bbbb");
g_ptr_array_add (gparray, "aaaa");
g_ptr_array_sort_values (gparray, (GCompareFunc) g_strcmp0);
i = 0;
g_assert_cmpstr (g_ptr_array_index (gparray, i++), ==, NULL);
g_assert_cmpstr (g_ptr_array_index (gparray, i++), ==, "aaaa");
g_assert_cmpstr (g_ptr_array_index (gparray, i++), ==, "bbbb");
g_assert_cmpstr (g_ptr_array_index (gparray, i++), ==, "cccc");
g_assert_cmpstr (g_ptr_array_index (gparray, i++), ==, "dddd");
g_clear_pointer (&gparray, g_ptr_array_unref);
}
static gint
sort_filelist_values (gconstpointer a, gconstpointer b)
{
const FileListEntry *entry1 = a;
const FileListEntry *entry2 = b;
return g_ascii_strcasecmp (entry1->name, entry2->name);
}
static void
pointer_array_sort_values_example (void)
{
GPtrArray *file_list = NULL;
FileListEntry *entry;
file_list = g_ptr_array_new_with_free_func (file_list_entry_free);
entry = g_new0 (FileListEntry, 1);
entry->name = g_strdup ("README");
entry->size = 42;
g_ptr_array_add (file_list, g_steal_pointer (&entry));
entry = g_new0 (FileListEntry, 1);
entry->name = g_strdup ("empty");
entry->size = 0;
g_ptr_array_add (file_list, g_steal_pointer (&entry));
entry = g_new0 (FileListEntry, 1);
entry->name = g_strdup ("aardvark");
entry->size = 23;
g_ptr_array_add (file_list, g_steal_pointer (&entry));
g_ptr_array_sort_values (file_list, sort_filelist_values);
g_assert_cmpuint (file_list->len, ==, 3);
entry = g_ptr_array_index (file_list, 0);
g_assert_cmpstr (entry->name, ==, "aardvark");
entry = g_ptr_array_index (file_list, 1);
g_assert_cmpstr (entry->name, ==, "empty");
entry = g_ptr_array_index (file_list, 2);
g_assert_cmpstr (entry->name, ==, "README");
g_ptr_array_unref (file_list);
}
static gint
sort_filelist_how_values (gconstpointer a, gconstpointer b, gpointer user_data)
{
gint order;
const SortMode sort_mode = GPOINTER_TO_INT (user_data);
const FileListEntry *entry1 = a;
const FileListEntry *entry2 = b;
switch (sort_mode)
{
case SORT_NAME:
order = g_ascii_strcasecmp (entry1->name, entry2->name);
break;
case SORT_SIZE:
order = entry1->size - entry2->size;
break;
default:
order = 0;
break;
}
return order;
}
static void
pointer_array_sort_values_with_data_example (void)
{
GPtrArray *file_list = NULL;
FileListEntry *entry;
SortMode sort_mode;
file_list = g_ptr_array_new_with_free_func (file_list_entry_free);
entry = g_new0 (FileListEntry, 1);
entry->name = g_strdup ("README");
entry->size = 42;
g_ptr_array_add (file_list, g_steal_pointer (&entry));
entry = g_new0 (FileListEntry, 1);
entry->name = g_strdup ("empty");
entry->size = 0;
g_ptr_array_add (file_list, g_steal_pointer (&entry));
entry = g_new0 (FileListEntry, 1);
entry->name = g_strdup ("aardvark");
entry->size = 23;
g_ptr_array_add (file_list, g_steal_pointer (&entry));
sort_mode = SORT_NAME;
g_ptr_array_sort_values_with_data (file_list, sort_filelist_how_values,
GINT_TO_POINTER (sort_mode));
g_assert_cmpuint (file_list->len, ==, 3);
entry = g_ptr_array_index (file_list, 0);
g_assert_cmpstr (entry->name, ==, "aardvark");
entry = g_ptr_array_index (file_list, 1);
g_assert_cmpstr (entry->name, ==, "empty");
entry = g_ptr_array_index (file_list, 2);
g_assert_cmpstr (entry->name, ==, "README");
sort_mode = SORT_SIZE;
g_ptr_array_sort_values_with_data (file_list, sort_filelist_how_values,
GINT_TO_POINTER (sort_mode));
g_assert_cmpuint (file_list->len, ==, 3);
entry = g_ptr_array_index (file_list, 0);
g_assert_cmpstr (entry->name, ==, "empty");
entry = g_ptr_array_index (file_list, 1);
g_assert_cmpstr (entry->name, ==, "aardvark");
entry = g_ptr_array_index (file_list, 2);
g_assert_cmpstr (entry->name, ==, "README");
g_ptr_array_unref (file_list);
}
static void
pointer_array_sort_values_with_data (void)
{
GPtrArray *gparray;
gint i;
gint prev, cur;
gparray = g_ptr_array_new ();
/* Sort empty array */
g_ptr_array_sort_values_with_data (gparray, ptr_compare_values_data, NULL);
for (i = 0; i < 10000; i++)
g_ptr_array_add (gparray, GINT_TO_POINTER (g_random_int_range (0, 10000)));
g_ptr_array_sort_values_with_data (gparray, ptr_compare_values_data, NULL);
prev = -1;
for (i = 0; i < 10000; i++)
{
cur = GPOINTER_TO_INT (g_ptr_array_index (gparray, i));
g_assert_cmpint (prev, <=, cur);
prev = cur;
}
g_ptr_array_free (gparray, TRUE);
}
static void
pointer_array_find_empty (void)
{
@ -2240,6 +2450,10 @@ main (int argc, char *argv[])
g_test_add_func ("/pointerarray/sort/example", pointer_array_sort_example);
g_test_add_func ("/pointerarray/sort-with-data", pointer_array_sort_with_data);
g_test_add_func ("/pointerarray/sort-with-data/example", pointer_array_sort_with_data_example);
g_test_add_func ("/pointerarray/sort-values", pointer_array_sort_values);
g_test_add_func ("/pointerarray/sort-values/example", pointer_array_sort_values_example);
g_test_add_func ("/pointerarray/sort-values-with-data", pointer_array_sort_values_with_data);
g_test_add_func ("/pointerarray/sort-values-with-data/example", pointer_array_sort_values_with_data_example);
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/remove-range", pointer_array_remove_range);