[util] Support custom swap function for heapsort

Sorting ECS component pools needs to swap multiple chunks of data for
each element being swapped, so the standard swap function isn't enough.
This commit is contained in:
Bill Currie 2022-10-30 23:38:14 +09:00
parent 7106411bc0
commit 7c06012383
2 changed files with 81 additions and 3 deletions

View file

@ -40,22 +40,35 @@ typedef int (*__compar_fn_t)(const void *, const void *);
typedef int (*__compar_d_fn_t)(const void *, const void *, void *);
#endif
#ifndef __swap_d_fn_t_defined
#define __swap_d_fn_t_defined
typedef void (*__swap_d_fn_t)(void *, void *, void *);
#endif
void heap_sink (void *base, size_t ind, size_t nmemb, size_t size,
__compar_fn_t cmp);
void heap_sink_r (void *base, size_t ind, size_t nmemb, size_t size,
__compar_d_fn_t cmp, void *arg);
void heap_sink_s (void *base, size_t ind, size_t nmemb, size_t size,
__compar_d_fn_t cmp, __swap_d_fn_t swp, void *arg);
void heap_swim (void *base, size_t ind, size_t nmemb, size_t size,
__compar_fn_t cmp);
void heap_swim_r (void *base, size_t ind, size_t nmemb, size_t size,
__compar_d_fn_t cmp, void *arg);
void heap_swim_s (void *base, size_t ind, size_t nmemb, size_t size,
__compar_d_fn_t cmp, __swap_d_fn_t swp, void *arg);
void heap_build (void *base, size_t nmemb, size_t size, __compar_fn_t cmp);
void heap_build_r (void *base, size_t nmemb, size_t size,
__compar_d_fn_t cmp, void *arg);
void heap_build_s (void *base, size_t nmemb, size_t size,
__compar_d_fn_t cmp, __swap_d_fn_t swp, void *arg);
void heapsort (void *base, size_t nmemb, size_t size, __compar_fn_t cmp);
void heapsort_r (void *base, size_t nmemb, size_t size,
__compar_d_fn_t cmp, void *arg);
void heapsort_s (void *base, size_t nmemb, size_t size,
__compar_d_fn_t cmp, __swap_d_fn_t swp, void *arg);
#endif//__QF_heapsort_h

View file

@ -46,7 +46,7 @@ heap_sink (void *base, size_t ind, size_t nmemb, size_t size,
VISIBLE void
heap_sink_r (void *base, size_t ind, size_t nmemb, size_t size,
__compar_d_fn_t cmp, void *arg)
__compar_d_fn_t cmp, void *arg)
{
size_t left_ind = 2 * ind + 1;
size_t right_ind = 2 * ind + 2;
@ -71,6 +71,33 @@ heap_sink_r (void *base, size_t ind, size_t nmemb, size_t size,
}
}
VISIBLE void
heap_sink_s (void *base, size_t ind, size_t nmemb, size_t size,
__compar_d_fn_t cmp, __swap_d_fn_t swp, void *arg)
{
size_t left_ind = 2 * ind + 1;
size_t right_ind = 2 * ind + 2;
void *node = (byte *) base + ind * size;
void *left = (byte *) base + left_ind * size;
void *right = (byte *) base + right_ind * size;
size_t largest_ind = ind;
void *largest = node;
if (left_ind < nmemb && cmp (left, node, arg) > 0) {
largest = left;
largest_ind = left_ind;
}
if (right_ind < nmemb && cmp (right, largest, arg) > 0) {
largest = right;
largest_ind = right_ind;
}
if (largest_ind != ind) {
swp (largest, node, arg);
heap_sink_s (base, largest_ind, nmemb, size, cmp, swp, arg);
}
}
VISIBLE void
heap_swim (void *base, size_t ind, size_t nmemb, size_t size,
__compar_fn_t cmp)
@ -87,7 +114,7 @@ heap_swim (void *base, size_t ind, size_t nmemb, size_t size,
VISIBLE void
heap_swim_r (void *base, size_t ind, size_t nmemb, size_t size,
__compar_d_fn_t cmp, void *arg)
__compar_d_fn_t cmp, void *arg)
{
size_t parent_ind = (ind - 1) / 2;
void *node = (byte *) base + ind * size;
@ -99,6 +126,20 @@ heap_swim_r (void *base, size_t ind, size_t nmemb, size_t size,
}
}
VISIBLE void
heap_swim_s (void *base, size_t ind, size_t nmemb, size_t size,
__compar_d_fn_t cmp, __swap_d_fn_t swp, void *arg)
{
size_t parent_ind = (ind - 1) / 2;
void *node = (byte *) base + ind * size;
void *parent = (byte *) base + parent_ind * size;
if (ind > 0 && cmp (node, parent, arg) > 0) {
swp (node, parent, arg);
heap_swim_s (base, parent_ind, nmemb, size, cmp, swp, arg);
}
}
VISIBLE void
heap_build (void *base, size_t nmemb, size_t size, __compar_fn_t cmp)
{
@ -112,7 +153,7 @@ heap_build (void *base, size_t nmemb, size_t size, __compar_fn_t cmp)
VISIBLE void
heap_build_r (void *base, size_t nmemb, size_t size,
__compar_d_fn_t cmp, void *arg)
__compar_d_fn_t cmp, void *arg)
{
if (nmemb < 2) {
return;
@ -122,6 +163,18 @@ heap_build_r (void *base, size_t nmemb, size_t size,
}
}
VISIBLE void
heap_build_s (void *base, size_t nmemb, size_t size,
__compar_d_fn_t cmp, __swap_d_fn_t swp, void *arg)
{
if (nmemb < 2) {
return;
}
for (size_t i = nmemb / 2; i-- > 0; ) {
heap_sink_s (base, i, nmemb, size, cmp, swp, arg);
}
}
VISIBLE void
heapsort (void *base, size_t nmemb, size_t size, __compar_fn_t cmp)
{
@ -144,3 +197,15 @@ heapsort_r (void *base, size_t nmemb, size_t size, __compar_d_fn_t cmp,
heap_sink_r (base, 0, i, size, cmp, arg);
}
}
VISIBLE void
heapsort_s (void *base, size_t nmemb, size_t size, __compar_d_fn_t cmp,
__swap_d_fn_t swp, void *arg)
{
heap_build_s (base, nmemb, size, cmp, swp, arg);
for (size_t i = nmemb; i-- > 1; ) {
void *last = (byte *) base + i * size;
swp (base, last, arg);
heap_sink_s (base, 0, i, size, cmp, swp, arg);
}
}