mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 23:32:09 +00:00
[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:
parent
7106411bc0
commit
7c06012383
2 changed files with 81 additions and 3 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue