quicksort optimization to avoid const worstcase
This commit is contained in:
parent
f7c025c0dd
commit
83c79f4832
61
thiersort.h
61
thiersort.h
@ -527,6 +527,20 @@ static inline TSU8 ts_radixi(
|
|||||||
assert(false);
|
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 */
|
/** Simple inplace quicksort for tselems */
|
||||||
static inline void ts_quicksort_inplace(
|
static inline void ts_quicksort_inplace(
|
||||||
struct tselem *arr,
|
struct tselem *arr,
|
||||||
@ -539,16 +553,44 @@ static inline void ts_quicksort_inplace(
|
|||||||
const TSU32 bi,
|
const TSU32 bi,
|
||||||
void *reent_data),
|
void *reent_data),
|
||||||
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! */
|
/* Must do this early exit! */
|
||||||
// TODO: TS_UNLIKELY
|
// TODO: TS_UNLIKELY
|
||||||
if(to == 0) return;
|
if(to == 0) return;
|
||||||
if(from >= to - 1) 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 len = (to - from);
|
||||||
TSU32 mid = from + len / 2;
|
TSU32 mid = from + len / 2;
|
||||||
const union tskey pivotkey = arr[mid].key;
|
const union tskey pivotkey = arr[mid].key;
|
||||||
TSU32 pivoti = arr[mid].i;
|
TSU32 pivoti = arr[mid].i;
|
||||||
|
|
||||||
|
/* Main loop */
|
||||||
TSU32 left = from;
|
TSU32 left = from;
|
||||||
TSU32 right = to - 1;
|
TSU32 right = to - 1;
|
||||||
while(left < right) {
|
while(left < right) {
|
||||||
@ -556,6 +598,7 @@ static inline void ts_quicksort_inplace(
|
|||||||
union tskey leftkey = arr[left].key;
|
union tskey leftkey = arr[left].key;
|
||||||
TSU32 lefti = arr[left].i;
|
TSU32 lefti = arr[left].i;
|
||||||
while((left < right) && lt(leftkey, pivotkey, lefti, pivoti, reent_data)) {
|
while((left < right) && lt(leftkey, pivotkey, lefti, pivoti, reent_data)) {
|
||||||
|
/* Step */
|
||||||
++left;
|
++left;
|
||||||
leftkey = arr[left].key;
|
leftkey = arr[left].key;
|
||||||
lefti = arr[left].i;
|
lefti = arr[left].i;
|
||||||
@ -565,6 +608,16 @@ static inline void ts_quicksort_inplace(
|
|||||||
union tskey rightkey = arr[right].key;
|
union tskey rightkey = arr[right].key;
|
||||||
TSU32 righti = arr[right].i;
|
TSU32 righti = arr[right].i;
|
||||||
while((left < right) && !lt(rightkey, pivotkey, righti, pivoti, reent_data)) {
|
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;
|
--right;
|
||||||
rightkey = arr[right].key;
|
rightkey = arr[right].key;
|
||||||
righti = arr[right].i;
|
righti = arr[right].i;
|
||||||
@ -608,8 +661,12 @@ static inline void ts_quicksort_inplace(
|
|||||||
arr[left] = arr[mid];
|
arr[left] = arr[mid];
|
||||||
arr[mid] = tmp;
|
arr[mid] = tmp;
|
||||||
|
|
||||||
/* Bad case: could shrink the array by one element only */
|
/* XXX: Instead of (**) above, we could so some other sort here as a fallback (like a heapsort or merge) */
|
||||||
ts_quicksort_inplace(arr, left + 1, to, lt, reent_data);
|
/* 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user