1
0
mirror of https://github.com/postgres/postgres.git synced 2025-09-05 02:22:28 +03:00

Redesign the API for list sorting (list_qsort becomes list_sort).

In the wake of commit 1cff1b95a, the obvious way to sort a List
is to apply qsort() directly to the array of ListCells.  list_qsort
was building an intermediate array of pointers-to-ListCells, which
we no longer need, but getting rid of it forces an API change:
the comparator functions need to do one less level of indirection.

Since we're having to touch the callers anyway, let's do two additional
changes: sort the given list in-place rather than making a copy (as
none of the existing callers have any use for the copying behavior),
and rename list_qsort to list_sort.  It was argued that the old name
exposes more about the implementation than it should, which I find
pretty questionable, but a better reason to rename it is to be sure
we get the attention of any external callers about the need to fix
their comparator functions.

While we're at it, change four existing callers of qsort() to use
list_sort instead; previously, they all had local reinventions
of list_qsort, ie build-an-array-from-a-List-and-qsort-it.
(There are some other places where changing to list_sort perhaps
would be worthwhile, but they're less obviously wins.)

Discussion: https://postgr.es/m/29361.1563220190@sss.pgh.pa.us
This commit is contained in:
Tom Lane
2019-07-16 11:51:44 -04:00
parent 0896ae561b
commit 569ed7f483
7 changed files with 83 additions and 158 deletions

View File

@@ -1419,45 +1419,28 @@ list_copy_deep(const List *oldlist)
}
/*
* Sort a list as though by qsort.
* Sort a list according to the specified comparator function.
*
* A new list is built and returned. Like list_copy, this doesn't make
* fresh copies of any pointed-to data.
* The list is sorted in-place.
*
* The comparator function receives arguments of type ListCell **.
* (XXX that's really inefficient now, but changing it seems like
* material for a standalone patch.)
* The comparator function is declared to receive arguments of type
* const ListCell *; this allows it to use lfirst() and variants
* without casting its arguments. Otherwise it behaves the same as
* the comparator function for standard qsort().
*
* Like qsort(), this provides no guarantees about sort stability
* for equal keys.
*/
List *
list_qsort(const List *list, list_qsort_comparator cmp)
void
list_sort(List *list, list_sort_comparator cmp)
{
int len = list_length(list);
ListCell **list_arr;
List *newlist;
ListCell *cell;
int i;
typedef int (*qsort_comparator) (const void *a, const void *b);
int len;
/* Empty list is easy */
if (len == 0)
return NIL;
check_list_invariants(list);
/* We have to make an array of pointers to satisfy the API */
list_arr = (ListCell **) palloc(sizeof(ListCell *) * len);
i = 0;
foreach(cell, list)
list_arr[i++] = cell;
qsort(list_arr, len, sizeof(ListCell *), cmp);
/* Construct new list (this code is much like list_copy) */
newlist = new_list(list->type, len);
for (i = 0; i < len; i++)
newlist->elements[i] = *list_arr[i];
/* Might as well free the workspace array */
pfree(list_arr);
check_list_invariants(newlist);
return newlist;
/* Nothing to do if there's less than two elements */
len = list_length(list);
if (len > 1)
qsort(list->elements, len, sizeof(ListCell), (qsort_comparator) cmp);
}