From 83c79f4832892f82a3e45b9a238930d5030bdbb4 Mon Sep 17 00:00:00 2001 From: Richard Thier Date: Sat, 1 Jul 2023 05:52:51 +0200 Subject: [PATCH] quicksort optimization to avoid const worstcase --- thiersort.h | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/thiersort.h b/thiersort.h index 4ad8dc0..de81338 100644 --- a/thiersort.h +++ b/thiersort.h @@ -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); + } } }