From: Nicholas Nethercote Date: Tue, 30 Sep 2003 14:43:54 +0000 (+0000) Subject: Added a generic VG_(ssort)() function, like stdlib.h's qsort(). It's X-Git-Tag: svn/VALGRIND_2_1_0~162 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=79e91e16ea7fd3a2d981a2fa6640826d25bc75de;p=thirdparty%2Fvalgrind.git Added a generic VG_(ssort)() function, like stdlib.h's qsort(). It's specialised for the size == 1/2/4 cases. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1871 --- diff --git a/coregrind/vg_mylibc.c b/coregrind/vg_mylibc.c index c1c1df8a7b..d0dcb57e0b 100644 --- a/coregrind/vg_mylibc.c +++ b/coregrind/vg_mylibc.c @@ -1495,6 +1495,89 @@ Int VG_(log2) ( Int x ) } +// Generic shell sort. Like stdlib.h's qsort(). +void VG_(ssort)( void* base, UInt nmemb, UInt size, + Int (*compar)(void*, void*) ) +{ + Int incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, + 9841, 29524, 88573, 265720, + 797161, 2391484 }; + Int lo = 0; + Int hi = nmemb-1; + Int i, j, h, bigN, hp; + + bigN = hi - lo + 1; if (bigN < 2) return; + hp = 0; while (hp < 14 && incs[hp] < bigN) hp++; hp--; + vg_assert(0 <= hp && hp < 14); + + #define SORT \ + for ( ; hp >= 0; hp--) { \ + h = incs[hp]; \ + i = lo + h; \ + while (1) { \ + if (i > hi) break; \ + ASSIGN(v,0, a,i); \ + j = i; \ + while (COMPAR(a,(j-h), v,0) > 0) { \ + ASSIGN(a,j, a,(j-h)); \ + j = j - h; \ + if (j <= (lo + h - 1)) break; \ + } \ + ASSIGN(a,j, v,0); \ + i++; \ + } \ + } + + // Specialised cases + if (sizeof(UInt) == size) { + + #define ASSIGN(dst, dsti, src, srci) \ + (dst)[(dsti)] = (src)[(srci)]; + + #define COMPAR(dst, dsti, src, srci) \ + compar( (void*)(& (dst)[(dsti)]), (void*)(& (src)[(srci)]) ) + + UInt* a = (UInt*)base; + UInt v[1]; + + SORT; + + } else if (sizeof(UShort) == size) { + UShort* a = (UShort*)base; + UShort v[1]; + + SORT; + + } else if (sizeof(UChar) == size) { + UChar* a = (UChar*)base; + UChar v[1]; + + SORT; + + #undef ASSIGN + #undef COMPAR + + // General case + } else { + void* a = (void*)base; + Char vc[size]; // will be at least 'size' bytes + void* v = (void*)vc; + + #define ASSIGN(dst, dsti, src, srci) \ + VG_(memcpy)( (void*)((dst) + size*(dsti)), \ + (void*)((src) + size*(srci)), (size) ); + + #define COMPAR(dst, dsti, src, srci) \ + compar( (void*)((dst) + size*(dsti)), (void*)((src) + size*(srci)) ) + + SORT; + + #undef ASSIGN + #undef COMPAR + } + #undef SORT +} + /* --------------------------------------------------------------------- Gruesome hackery for connecting to a logging server over the network. This is all very Linux-kernel specific. diff --git a/include/vg_skin.h b/include/vg_skin.h index 8b111ce2e2..fcca0326ca 100644 --- a/include/vg_skin.h +++ b/include/vg_skin.h @@ -368,6 +368,10 @@ extern Long VG_(atoll) ( Char* str ); /* Like atoll(), but converts a number of base 2..36 */ extern Long VG_(atoll36) ( UInt base, Char* str ); +/* Like qsort(), but does shell-sort. The size==4 case is specialised. */ +extern void VG_(ssort)( void* base, UInt nmemb, UInt size, + Int (*compar)(void*, void*) ); + /* ------------------------------------------------------------------ */ /* ctype.h */