quicksort optimization to avoid const worstcase

This commit is contained in:
Richard Thier 2023-07-01 05:52:51 +02:00
parent f7c025c0dd
commit 83c79f4832

View File

@ -527,6 +527,20 @@ static inline TSU8 ts_radixi(
assert(false);
}
/* Forward decl. */
static inline void ts_quicksort_inplace_impl(
struct tselem *arr,
TSU32 from,
TSU32 to,
const TSBOOL (*lt)(
const union tskey ak,
const union tskey bk,
const TSU32 ai,
const TSU32 bi,
void *reent_data),
void *reent_data,
TSBOOL const_check);
/** Simple inplace quicksort for tselems */
static inline void ts_quicksort_inplace(
struct tselem *arr,
@ -539,16 +553,44 @@ static inline void ts_quicksort_inplace(
const TSU32 bi,
void *reent_data),
void *reent_data) {
ts_quicksort_inplace_impl(
arr,
from,
to,
lt,
reent_data,
TSFALSE);
}
/** Implementation details for ts_quicksort_inplace(..) - use that instead! */
static inline void ts_quicksort_inplace_impl(
struct tselem *arr,
TSU32 from,
TSU32 to,
const TSBOOL (*lt)(
const union tskey ak,
const union tskey bk,
const TSU32 ai,
const TSU32 bi,
void *reent_data),
void *reent_data,
TSBOOL const_check) {
/* Must do this early exit! */
// TODO: TS_UNLIKELY
if(to == 0) return;
if(from >= to - 1) return;
/* For checking sorting constant array (same value always worst cases) */
TSU32 pivcnt = 0;
/* Pivoting */
TSU32 len = (to - from);
TSU32 mid = from + len / 2;
const union tskey pivotkey = arr[mid].key;
TSU32 pivoti = arr[mid].i;
/* Main loop */
TSU32 left = from;
TSU32 right = to - 1;
while(left < right) {
@ -556,6 +598,7 @@ static inline void ts_quicksort_inplace(
union tskey leftkey = arr[left].key;
TSU32 lefti = arr[left].i;
while((left < right) && lt(leftkey, pivotkey, lefti, pivoti, reent_data)) {
/* Step */
++left;
leftkey = arr[left].key;
lefti = arr[left].i;
@ -565,6 +608,16 @@ static inline void ts_quicksort_inplace(
union tskey rightkey = arr[right].key;
TSU32 righti = arr[right].i;
while((left < right) && !lt(rightkey, pivotkey, righti, pivoti, reent_data)) {
/* Compiler should optimize this branch out compile time! */
if(const_check) {
/* (**): Check for stepping over everything because its all the same.. */
/* This with the above if gives two GE so an equality check */
if(!lt(pivotkey, rightkey, pivoti, righti, reent_data)) {
++pivcnt;
}
}
/* Step */
--right;
rightkey = arr[right].key;
righti = arr[right].i;
@ -608,8 +661,12 @@ static inline void ts_quicksort_inplace(
arr[left] = arr[mid];
arr[mid] = tmp;
/* Bad case: could shrink the array by one element only */
ts_quicksort_inplace(arr, left + 1, to, lt, reent_data);
/* XXX: Instead of (**) above, we could so some other sort here as a fallback (like a heapsort or merge) */
/* This ignores constantly the same arrays */
if(pivcnt < len - 1) {
/* Bad case: could shrink the array by one element only */
ts_quicksort_inplace_impl(arr, left + 1, to, lt, reent_data, TSTRUE);
}
}
}