stdlib: qsort and bsearch changes.
- Always use internal qsort and bsearch implementation. - add "_r" reentrant versions. The reasons for always using the internal versions is that the C runtime versions' callbacks are not mark STDCALL, so we would have add bridge functions for them anyhow, The C runtime qsort_r/qsort_s have different orders of arguments on different platforms, and most importantly: qsort() isn't a stable sort, and isn't guaranteed to give the same ordering for two objects marked as equal by the callback...as such, Visual Studio and glibc can give different sort results for the same data set...in this sense, having one piece of code shared on all platforms makes sense here, for reliabillity. bsearch does not have a standard _r version at all, and suffers from the same SDLCALL concern. Since the code is simple and we would have to work around the C runtime, it's easier to just go with the built-in function and remove all the CMake C runtime tests. Fixes #9159.main
parent
af58ed978e
commit
1e8b006d43
|
@ -1058,7 +1058,7 @@ if(SDL_LIBC)
|
||||||
|
|
||||||
set(symbols_to_check
|
set(symbols_to_check
|
||||||
abs acos acosf asin asinf atan atan2 atan2f atanf atof atoi
|
abs acos acosf asin asinf atan atan2 atan2f atanf atof atoi
|
||||||
bcopy bsearch
|
bcopy
|
||||||
calloc ceil ceilf copysign copysignf cos cosf
|
calloc ceil ceilf copysign copysignf cos cosf
|
||||||
_Exit exp expf
|
_Exit exp expf
|
||||||
fabs fabsf floor floorf fmod fmodf fopen64 free fseeko fseeko64
|
fabs fabsf floor floorf fmod fmodf fopen64 free fseeko fseeko64
|
||||||
|
@ -1067,7 +1067,6 @@ if(SDL_LIBC)
|
||||||
log log10 log10f logf lround lroundf _ltoa
|
log log10 log10f logf lround lroundf _ltoa
|
||||||
malloc memcmp memcpy memmove memset modf modff
|
malloc memcmp memcpy memmove memset modf modff
|
||||||
pow powf putenv
|
pow powf putenv
|
||||||
qsort
|
|
||||||
realloc rindex round roundf
|
realloc rindex round roundf
|
||||||
scalbn scalbnf setenv sin sinf sqr sqrt sqrtf sscanf strchr
|
scalbn scalbnf setenv sin sinf sqr sqrt sqrtf sscanf strchr
|
||||||
strcmp strlcat strlcpy strlen strncmp strnlen
|
strcmp strlcat strlcpy strlen strncmp strnlen
|
||||||
|
|
|
@ -42,6 +42,7 @@ words = [
|
||||||
'atanf',
|
'atanf',
|
||||||
'atof',
|
'atof',
|
||||||
'atoi',
|
'atoi',
|
||||||
|
'bsearch',
|
||||||
'calloc',
|
'calloc',
|
||||||
'ceil',
|
'ceil',
|
||||||
'ceilf',
|
'ceilf',
|
||||||
|
@ -90,6 +91,8 @@ words = [
|
||||||
'pow',
|
'pow',
|
||||||
'powf',
|
'powf',
|
||||||
'qsort',
|
'qsort',
|
||||||
|
'qsort_r',
|
||||||
|
'qsort_s',
|
||||||
'realloc',
|
'realloc',
|
||||||
'round',
|
'round',
|
||||||
'roundf',
|
'roundf',
|
||||||
|
|
|
@ -498,6 +498,9 @@ extern DECLSPEC int SDLCALL SDL_setenv(const char *name, const char *value, int
|
||||||
extern DECLSPEC void SDLCALL SDL_qsort(void *base, size_t nmemb, size_t size, int (SDLCALL *compare) (const void *, const void *));
|
extern DECLSPEC void SDLCALL SDL_qsort(void *base, size_t nmemb, size_t size, int (SDLCALL *compare) (const void *, const void *));
|
||||||
extern DECLSPEC void * SDLCALL SDL_bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (SDLCALL *compare) (const void *, const void *));
|
extern DECLSPEC void * SDLCALL SDL_bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (SDLCALL *compare) (const void *, const void *));
|
||||||
|
|
||||||
|
extern DECLSPEC void SDLCALL SDL_qsort_r(void *base, size_t nmemb, size_t size, int (SDLCALL *compare) (void *, const void *, const void *), void *userdata);
|
||||||
|
extern DECLSPEC void * SDLCALL SDL_bsearch_r(const void *key, const void *base, size_t nmemb, size_t size, int (SDLCALL *compare) (void *, const void *, const void *), void *userdata);
|
||||||
|
|
||||||
extern DECLSPEC int SDLCALL SDL_abs(int x);
|
extern DECLSPEC int SDLCALL SDL_abs(int x);
|
||||||
|
|
||||||
/* NOTE: these double-evaluate their arguments, so you should never have side effects in the parameters */
|
/* NOTE: these double-evaluate their arguments, so you should never have side effects in the parameters */
|
||||||
|
|
|
@ -82,8 +82,6 @@
|
||||||
#cmakedefine HAVE_PUTENV 1
|
#cmakedefine HAVE_PUTENV 1
|
||||||
#cmakedefine HAVE_UNSETENV 1
|
#cmakedefine HAVE_UNSETENV 1
|
||||||
#endif
|
#endif
|
||||||
#cmakedefine HAVE_QSORT 1
|
|
||||||
#cmakedefine HAVE_BSEARCH 1
|
|
||||||
#cmakedefine HAVE_ABS 1
|
#cmakedefine HAVE_ABS 1
|
||||||
#cmakedefine HAVE_BCOPY 1
|
#cmakedefine HAVE_BCOPY 1
|
||||||
#cmakedefine HAVE_MEMSET 1
|
#cmakedefine HAVE_MEMSET 1
|
||||||
|
|
|
@ -63,8 +63,6 @@
|
||||||
#define HAVE_PUTENV 1
|
#define HAVE_PUTENV 1
|
||||||
#define HAVE_SETENV 1
|
#define HAVE_SETENV 1
|
||||||
#define HAVE_UNSETENV 1
|
#define HAVE_UNSETENV 1
|
||||||
#define HAVE_QSORT 1
|
|
||||||
#define HAVE_BSEARCH 1
|
|
||||||
#define HAVE_ABS 1
|
#define HAVE_ABS 1
|
||||||
#define HAVE_BCOPY 1
|
#define HAVE_BCOPY 1
|
||||||
#define HAVE_MEMSET 1
|
#define HAVE_MEMSET 1
|
||||||
|
|
|
@ -65,8 +65,6 @@
|
||||||
#define HAVE_SETENV 1
|
#define HAVE_SETENV 1
|
||||||
#define HAVE_PUTENV 1
|
#define HAVE_PUTENV 1
|
||||||
#define HAVE_UNSETENV 1
|
#define HAVE_UNSETENV 1
|
||||||
#define HAVE_QSORT 1
|
|
||||||
#define HAVE_BSEARCH 1
|
|
||||||
#define HAVE_ABS 1
|
#define HAVE_ABS 1
|
||||||
#define HAVE_BCOPY 1
|
#define HAVE_BCOPY 1
|
||||||
#define HAVE_MEMSET 1
|
#define HAVE_MEMSET 1
|
||||||
|
|
|
@ -55,8 +55,6 @@
|
||||||
#define HAVE_PUTENV 1
|
#define HAVE_PUTENV 1
|
||||||
#define HAVE_SETENV 1
|
#define HAVE_SETENV 1
|
||||||
#define HAVE_UNSETENV 1
|
#define HAVE_UNSETENV 1
|
||||||
#define HAVE_QSORT 1
|
|
||||||
#define HAVE_BSEARCH 1
|
|
||||||
#define HAVE_ABS 1
|
#define HAVE_ABS 1
|
||||||
#define HAVE_BCOPY 1
|
#define HAVE_BCOPY 1
|
||||||
#define HAVE_MEMSET 1
|
#define HAVE_MEMSET 1
|
||||||
|
|
|
@ -59,8 +59,6 @@
|
||||||
#define HAVE_SETENV 1
|
#define HAVE_SETENV 1
|
||||||
#define HAVE_PUTENV 1
|
#define HAVE_PUTENV 1
|
||||||
#define HAVE_UNSETENV 1
|
#define HAVE_UNSETENV 1
|
||||||
#define HAVE_QSORT 1
|
|
||||||
#define HAVE_BSEARCH 1
|
|
||||||
#define HAVE_ABS 1
|
#define HAVE_ABS 1
|
||||||
#define HAVE_BCOPY 1
|
#define HAVE_BCOPY 1
|
||||||
#define HAVE_MEMSET 1
|
#define HAVE_MEMSET 1
|
||||||
|
|
|
@ -135,8 +135,6 @@ typedef unsigned int uintptr_t;
|
||||||
#define HAVE_CALLOC 1
|
#define HAVE_CALLOC 1
|
||||||
#define HAVE_REALLOC 1
|
#define HAVE_REALLOC 1
|
||||||
#define HAVE_FREE 1
|
#define HAVE_FREE 1
|
||||||
#define HAVE_QSORT 1
|
|
||||||
#define HAVE_BSEARCH 1
|
|
||||||
#define HAVE_ABS 1
|
#define HAVE_ABS 1
|
||||||
#define HAVE_MEMSET 1
|
#define HAVE_MEMSET 1
|
||||||
#define HAVE_MEMCPY 1
|
#define HAVE_MEMCPY 1
|
||||||
|
|
|
@ -76,8 +76,6 @@
|
||||||
#define HAVE_CALLOC 1
|
#define HAVE_CALLOC 1
|
||||||
#define HAVE_REALLOC 1
|
#define HAVE_REALLOC 1
|
||||||
#define HAVE_FREE 1
|
#define HAVE_FREE 1
|
||||||
#define HAVE_QSORT 1
|
|
||||||
#define HAVE_BSEARCH 1
|
|
||||||
#define HAVE_ABS 1
|
#define HAVE_ABS 1
|
||||||
#define HAVE_MEMSET 1
|
#define HAVE_MEMSET 1
|
||||||
#define HAVE_MEMCPY 1
|
#define HAVE_MEMCPY 1
|
||||||
|
|
|
@ -76,8 +76,6 @@
|
||||||
#define HAVE_CALLOC 1
|
#define HAVE_CALLOC 1
|
||||||
#define HAVE_REALLOC 1
|
#define HAVE_REALLOC 1
|
||||||
#define HAVE_FREE 1
|
#define HAVE_FREE 1
|
||||||
#define HAVE_QSORT 1
|
|
||||||
#define HAVE_BSEARCH 1
|
|
||||||
#define HAVE_ABS 1
|
#define HAVE_ABS 1
|
||||||
#define HAVE_MEMSET 1
|
#define HAVE_MEMSET 1
|
||||||
#define HAVE_MEMCPY 1
|
#define HAVE_MEMCPY 1
|
||||||
|
|
|
@ -76,8 +76,6 @@
|
||||||
#define HAVE_CALLOC 1
|
#define HAVE_CALLOC 1
|
||||||
#define HAVE_REALLOC 1
|
#define HAVE_REALLOC 1
|
||||||
#define HAVE_FREE 1
|
#define HAVE_FREE 1
|
||||||
#define HAVE_QSORT 1
|
|
||||||
#define HAVE_BSEARCH 1
|
|
||||||
#define HAVE_ABS 1
|
#define HAVE_ABS 1
|
||||||
#define HAVE_MEMSET 1
|
#define HAVE_MEMSET 1
|
||||||
#define HAVE_MEMCPY 1
|
#define HAVE_MEMCPY 1
|
||||||
|
|
|
@ -971,6 +971,8 @@ SDL3_0.0.0 {
|
||||||
SDL_CloseCamera;
|
SDL_CloseCamera;
|
||||||
SDL_GetCameraPermissionState;
|
SDL_GetCameraPermissionState;
|
||||||
SDL_GetCameraDevicePosition;
|
SDL_GetCameraDevicePosition;
|
||||||
|
SDL_qsort_r;
|
||||||
|
SDL_bsearch_r;
|
||||||
# extra symbols go here (don't modify this line)
|
# extra symbols go here (don't modify this line)
|
||||||
local: *;
|
local: *;
|
||||||
};
|
};
|
||||||
|
|
|
@ -996,3 +996,5 @@
|
||||||
#define SDL_CloseCamera SDL_CloseCamera_REAL
|
#define SDL_CloseCamera SDL_CloseCamera_REAL
|
||||||
#define SDL_GetCameraPermissionState SDL_GetCameraPermissionState_REAL
|
#define SDL_GetCameraPermissionState SDL_GetCameraPermissionState_REAL
|
||||||
#define SDL_GetCameraDevicePosition SDL_GetCameraDevicePosition_REAL
|
#define SDL_GetCameraDevicePosition SDL_GetCameraDevicePosition_REAL
|
||||||
|
#define SDL_qsort_r SDL_qsort_r_REAL
|
||||||
|
#define SDL_bsearch_r SDL_bsearch_r_REAL
|
||||||
|
|
|
@ -1021,3 +1021,5 @@ SDL_DYNAPI_PROC(int,SDL_ReleaseCameraFrame,(SDL_Camera *a, SDL_Surface *b),(a,b)
|
||||||
SDL_DYNAPI_PROC(void,SDL_CloseCamera,(SDL_Camera *a),(a),)
|
SDL_DYNAPI_PROC(void,SDL_CloseCamera,(SDL_Camera *a),(a),)
|
||||||
SDL_DYNAPI_PROC(int,SDL_GetCameraPermissionState,(SDL_Camera *a),(a),return)
|
SDL_DYNAPI_PROC(int,SDL_GetCameraPermissionState,(SDL_Camera *a),(a),return)
|
||||||
SDL_DYNAPI_PROC(SDL_CameraPosition,SDL_GetCameraDevicePosition,(SDL_CameraDeviceID a),(a),return)
|
SDL_DYNAPI_PROC(SDL_CameraPosition,SDL_GetCameraDevicePosition,(SDL_CameraDeviceID a),(a),return)
|
||||||
|
SDL_DYNAPI_PROC(void,SDL_qsort_r,(void *a, size_t b, size_t c, int (SDLCALL *d)(void *, const void *, const void *), void *e),(a,b,c,d,e),)
|
||||||
|
SDL_DYNAPI_PROC(void*,SDL_bsearch_r,(const void *a, const void *b, size_t c, size_t d, int (SDLCALL *e)(void *, const void *, const void *), void *f),(a,b,c,d,e,f),return)
|
||||||
|
|
|
@ -20,17 +20,10 @@
|
||||||
*/
|
*/
|
||||||
#include "SDL_internal.h"
|
#include "SDL_internal.h"
|
||||||
|
|
||||||
|
// SDL3 always uses its own internal qsort implementation, below, so
|
||||||
#ifdef HAVE_QSORT
|
// it can guarantee stable sorts across platforms and not have to
|
||||||
void SDL_qsort(void *base, size_t nmemb, size_t size, int (*compare) (const void *, const void *))
|
// tapdance to support the various qsort_r interfaces, or bridge from
|
||||||
{
|
// the C runtime's non-SDLCALL compare functions.
|
||||||
if (!base) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
qsort(base, nmemb, size, compare);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#ifdef assert
|
#ifdef assert
|
||||||
#undef assert
|
#undef assert
|
||||||
|
@ -52,10 +45,6 @@ void SDL_qsort(void *base, size_t nmemb, size_t size, int (*compare) (const void
|
||||||
#undef memmove
|
#undef memmove
|
||||||
#endif
|
#endif
|
||||||
#define memmove SDL_memmove
|
#define memmove SDL_memmove
|
||||||
#ifdef qsortG
|
|
||||||
#undef qsortG
|
|
||||||
#endif
|
|
||||||
#define qsortG SDL_qsort
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This code came from Gareth McCaughan, under the zlib license.
|
This code came from Gareth McCaughan, under the zlib license.
|
||||||
|
@ -67,6 +56,8 @@ Everything below this comment until the HAVE_QSORT #endif was from Gareth
|
||||||
Thank you to Gareth for relicensing this code under the zlib license for our
|
Thank you to Gareth for relicensing this code under the zlib license for our
|
||||||
benefit!
|
benefit!
|
||||||
|
|
||||||
|
Update for SDL3: we have modified this from a qsort function to qsort_r.
|
||||||
|
|
||||||
--ryan.
|
--ryan.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -152,7 +143,7 @@ benefit!
|
||||||
|
|
||||||
#undef DEBUG_QSORT
|
#undef DEBUG_QSORT
|
||||||
|
|
||||||
static char _ID[]="<qsort.c gjm 1.15 2016-03-10>";
|
static char _ID[]="<qsort.c gjm WITH CHANGES FOR SDL3 1.15 2016-03-10>";
|
||||||
#endif
|
#endif
|
||||||
/* END SDL CHANGE ... commented this out with an #if 0 block. --ryan. */
|
/* END SDL CHANGE ... commented this out with an #if 0 block. --ryan. */
|
||||||
|
|
||||||
|
@ -274,19 +265,19 @@ typedef struct { char * first; char * last; } stack_entry;
|
||||||
|
|
||||||
/* and so is the pivoting logic (note: last is inclusive): */
|
/* and so is the pivoting logic (note: last is inclusive): */
|
||||||
#define Pivot(swapper,sz) \
|
#define Pivot(swapper,sz) \
|
||||||
if ((size_t)(last-first)>PIVOT_THRESHOLD*sz) mid=pivot_big(first,mid,last,sz,compare);\
|
if ((size_t)(last-first)>PIVOT_THRESHOLD*sz) mid=pivot_big(first,mid,last,sz,compare,userdata);\
|
||||||
else { \
|
else { \
|
||||||
if (compare(first,mid)<0) { \
|
if (compare(userdata,first,mid)<0) { \
|
||||||
if (compare(mid,last)>0) { \
|
if (compare(userdata,mid,last)>0) { \
|
||||||
swapper(mid,last); \
|
swapper(mid,last); \
|
||||||
if (compare(first,mid)>0) swapper(first,mid);\
|
if (compare(userdata,first,mid)>0) swapper(first,mid);\
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
else { \
|
else { \
|
||||||
if (compare(mid,last)>0) swapper(first,last)\
|
if (compare(userdata,mid,last)>0) swapper(first,last)\
|
||||||
else { \
|
else { \
|
||||||
swapper(first,mid); \
|
swapper(first,mid); \
|
||||||
if (compare(mid,last)>0) swapper(mid,last);\
|
if (compare(userdata,mid,last)>0) swapper(mid,last);\
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
first+=sz; last-=sz; \
|
first+=sz; last-=sz; \
|
||||||
|
@ -299,8 +290,8 @@ typedef struct { char * first; char * last; } stack_entry;
|
||||||
/* and so is the partitioning logic: */
|
/* and so is the partitioning logic: */
|
||||||
#define Partition(swapper,sz) { \
|
#define Partition(swapper,sz) { \
|
||||||
do { \
|
do { \
|
||||||
while (compare(first,pivot)<0) first+=sz; \
|
while (compare(userdata,first,pivot)<0) first+=sz; \
|
||||||
while (compare(pivot,last)<0) last-=sz; \
|
while (compare(userdata,pivot,last)<0) last-=sz; \
|
||||||
if (first<last) { \
|
if (first<last) { \
|
||||||
swapper(first,last); \
|
swapper(first,last); \
|
||||||
first+=sz; last-=sz; } \
|
first+=sz; last-=sz; } \
|
||||||
|
@ -323,7 +314,7 @@ typedef struct { char * first; char * last; } stack_entry;
|
||||||
first=base; \
|
first=base; \
|
||||||
last=first + ((nmemb>limit ? limit : nmemb)-1)*sz;\
|
last=first + ((nmemb>limit ? limit : nmemb)-1)*sz;\
|
||||||
while (last!=base) { \
|
while (last!=base) { \
|
||||||
if (compare(first,last)>0) first=last; \
|
if (compare(userdata,first,last)>0) first=last; \
|
||||||
last-=sz; } \
|
last-=sz; } \
|
||||||
if (first!=base) swapper(first,(char*)base);
|
if (first!=base) swapper(first,(char*)base);
|
||||||
|
|
||||||
|
@ -334,7 +325,7 @@ typedef struct { char * first; char * last; } stack_entry;
|
||||||
char *test; \
|
char *test; \
|
||||||
/* Find the right place for |first|. \
|
/* Find the right place for |first|. \
|
||||||
* My apologies for var reuse. */ \
|
* My apologies for var reuse. */ \
|
||||||
for (test=first-size;compare(test,first)>0;test-=size) ; \
|
for (test=first-size;compare(userdata,test,first)>0;test-=size) ; \
|
||||||
test+=size; \
|
test+=size; \
|
||||||
if (test!=first) { \
|
if (test!=first) { \
|
||||||
/* Shift everything in [test,first) \
|
/* Shift everything in [test,first) \
|
||||||
|
@ -362,7 +353,7 @@ typedef struct { char * first; char * last; } stack_entry;
|
||||||
/* ---------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
static char * pivot_big(char *first, char *mid, char *last, size_t size,
|
static char * pivot_big(char *first, char *mid, char *last, size_t size,
|
||||||
int compare(const void *, const void *)) {
|
int (SDLCALL * compare)(void *, const void *, const void *), void *userdata) {
|
||||||
size_t d=(((last-first)/size)>>3)*size;
|
size_t d=(((last-first)/size)>>3)*size;
|
||||||
#ifdef DEBUG_QSORT
|
#ifdef DEBUG_QSORT
|
||||||
fprintf(stderr, "pivot_big: first=%p last=%p size=%lu n=%lu\n", first, (unsigned long)last, size, (unsigned long)((last-first+1)/size));
|
fprintf(stderr, "pivot_big: first=%p last=%p size=%lu n=%lu\n", first, (unsigned long)last, size, (unsigned long)((last-first+1)/size));
|
||||||
|
@ -372,38 +363,38 @@ fprintf(stderr, "pivot_big: first=%p last=%p size=%lu n=%lu\n", first, (unsigned
|
||||||
#ifdef DEBUG_QSORT
|
#ifdef DEBUG_QSORT
|
||||||
fprintf(stderr,"< %d %d %d @ %p %p %p\n",*(int*)a,*(int*)b,*(int*)c, a,b,c);
|
fprintf(stderr,"< %d %d %d @ %p %p %p\n",*(int*)a,*(int*)b,*(int*)c, a,b,c);
|
||||||
#endif
|
#endif
|
||||||
m1 = compare(a,b)<0 ?
|
m1 = compare(userdata,a,b)<0 ?
|
||||||
(compare(b,c)<0 ? b : (compare(a,c)<0 ? c : a))
|
(compare(userdata,b,c)<0 ? b : (compare(userdata,a,c)<0 ? c : a))
|
||||||
: (compare(a,c)<0 ? a : (compare(b,c)<0 ? c : b));
|
: (compare(userdata,a,c)<0 ? a : (compare(userdata,b,c)<0 ? c : b));
|
||||||
}
|
}
|
||||||
{ char *a=mid-d, *b=mid, *c=mid+d;
|
{ char *a=mid-d, *b=mid, *c=mid+d;
|
||||||
#ifdef DEBUG_QSORT
|
#ifdef DEBUG_QSORT
|
||||||
fprintf(stderr,". %d %d %d @ %p %p %p\n",*(int*)a,*(int*)b,*(int*)c, a,b,c);
|
fprintf(stderr,". %d %d %d @ %p %p %p\n",*(int*)a,*(int*)b,*(int*)c, a,b,c);
|
||||||
#endif
|
#endif
|
||||||
m2 = compare(a,b)<0 ?
|
m2 = compare(userdata,a,b)<0 ?
|
||||||
(compare(b,c)<0 ? b : (compare(a,c)<0 ? c : a))
|
(compare(userdata,b,c)<0 ? b : (compare(userdata,a,c)<0 ? c : a))
|
||||||
: (compare(a,c)<0 ? a : (compare(b,c)<0 ? c : b));
|
: (compare(userdata,a,c)<0 ? a : (compare(userdata,b,c)<0 ? c : b));
|
||||||
}
|
}
|
||||||
{ char *a=last-2*d, *b=last-d, *c=last;
|
{ char *a=last-2*d, *b=last-d, *c=last;
|
||||||
#ifdef DEBUG_QSORT
|
#ifdef DEBUG_QSORT
|
||||||
fprintf(stderr,"> %d %d %d @ %p %p %p\n",*(int*)a,*(int*)b,*(int*)c, a,b,c);
|
fprintf(stderr,"> %d %d %d @ %p %p %p\n",*(int*)a,*(int*)b,*(int*)c, a,b,c);
|
||||||
#endif
|
#endif
|
||||||
m3 = compare(a,b)<0 ?
|
m3 = compare(userdata,a,b)<0 ?
|
||||||
(compare(b,c)<0 ? b : (compare(a,c)<0 ? c : a))
|
(compare(userdata,b,c)<0 ? b : (compare(userdata,a,c)<0 ? c : a))
|
||||||
: (compare(a,c)<0 ? a : (compare(b,c)<0 ? c : b));
|
: (compare(userdata,a,c)<0 ? a : (compare(userdata,b,c)<0 ? c : b));
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_QSORT
|
#ifdef DEBUG_QSORT
|
||||||
fprintf(stderr,"-> %d %d %d @ %p %p %p\n",*(int*)m1,*(int*)m2,*(int*)m3, m1,m2,m3);
|
fprintf(stderr,"-> %d %d %d @ %p %p %p\n",*(int*)m1,*(int*)m2,*(int*)m3, m1,m2,m3);
|
||||||
#endif
|
#endif
|
||||||
return compare(m1,m2)<0 ?
|
return compare(userdata,m1,m2)<0 ?
|
||||||
(compare(m2,m3)<0 ? m2 : (compare(m1,m3)<0 ? m3 : m1))
|
(compare(userdata,m2,m3)<0 ? m2 : (compare(userdata,m1,m3)<0 ? m3 : m1))
|
||||||
: (compare(m1,m3)<0 ? m1 : (compare(m2,m3)<0 ? m3 : m2));
|
: (compare(userdata,m1,m3)<0 ? m1 : (compare(userdata,m2,m3)<0 ? m3 : m2));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
static void qsort_nonaligned(void *base, size_t nmemb, size_t size,
|
static void qsort_r_nonaligned(void *base, size_t nmemb, size_t size,
|
||||||
int (*compare)(const void *, const void *)) {
|
int (SDLCALL * compare)(void *, const void *, const void *), void *userdata) {
|
||||||
|
|
||||||
stack_entry stack[STACK_SIZE];
|
stack_entry stack[STACK_SIZE];
|
||||||
int stacktop=0;
|
int stacktop=0;
|
||||||
|
@ -433,8 +424,8 @@ static void qsort_nonaligned(void *base, size_t nmemb, size_t size,
|
||||||
free(pivot);
|
free(pivot);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qsort_aligned(void *base, size_t nmemb, size_t size,
|
static void qsort_r_aligned(void *base, size_t nmemb, size_t size,
|
||||||
int (*compare)(const void *, const void *)) {
|
int (SDLCALL * compare)(void *,const void *, const void *), void *userdata) {
|
||||||
|
|
||||||
stack_entry stack[STACK_SIZE];
|
stack_entry stack[STACK_SIZE];
|
||||||
int stacktop=0;
|
int stacktop=0;
|
||||||
|
@ -464,8 +455,8 @@ static void qsort_aligned(void *base, size_t nmemb, size_t size,
|
||||||
free(pivot);
|
free(pivot);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qsort_words(void *base, size_t nmemb,
|
static void qsort_r_words(void *base, size_t nmemb,
|
||||||
int (*compare)(const void *, const void *)) {
|
int (SDLCALL * compare)(void *,const void *, const void *), void *userdata) {
|
||||||
|
|
||||||
stack_entry stack[STACK_SIZE];
|
stack_entry stack[STACK_SIZE];
|
||||||
int stacktop=0;
|
int stacktop=0;
|
||||||
|
@ -507,7 +498,7 @@ fprintf(stderr, "after partitioning first=#%lu last=#%lu\n", (first-(char*)base)
|
||||||
/* Find the right place for |first|. My apologies for var reuse */
|
/* Find the right place for |first|. My apologies for var reuse */
|
||||||
int *pl=(int*)(first-WORD_BYTES),*pr=(int*)first;
|
int *pl=(int*)(first-WORD_BYTES),*pr=(int*)first;
|
||||||
*(int*)pivot=*(int*)first;
|
*(int*)pivot=*(int*)first;
|
||||||
for (;compare(pl,pivot)>0;pr=pl,--pl) {
|
for (;compare(userdata,pl,pivot)>0;pr=pl,--pl) {
|
||||||
*pr=*pl; }
|
*pr=*pl; }
|
||||||
if (pr!=(int*)first) *pr=*(int*)pivot;
|
if (pr!=(int*)first) *pr=*(int*)pivot;
|
||||||
}
|
}
|
||||||
|
@ -516,28 +507,34 @@ fprintf(stderr, "after partitioning first=#%lu last=#%lu\n", (first-(char*)base)
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
extern void qsortG(void *base, size_t nmemb, size_t size,
|
extern void SDL_qsort_r(void *base, size_t nmemb, size_t size,
|
||||||
int (*compare)(const void *, const void *)) {
|
int (SDLCALL * compare)(void *, const void *, const void *), void *userdata) {
|
||||||
|
|
||||||
if (nmemb<=1) return;
|
if (nmemb<=1) return;
|
||||||
if (((size_t)base|size)&(WORD_BYTES-1))
|
if (((size_t)base|size)&(WORD_BYTES-1))
|
||||||
qsort_nonaligned(base,nmemb,size,compare);
|
qsort_r_nonaligned(base,nmemb,size,compare,userdata);
|
||||||
else if (size!=WORD_BYTES)
|
else if (size!=WORD_BYTES)
|
||||||
qsort_aligned(base,nmemb,size,compare);
|
qsort_r_aligned(base,nmemb,size,compare,userdata);
|
||||||
else
|
else
|
||||||
qsort_words(base,nmemb,compare);
|
qsort_r_words(base,nmemb,compare,userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* HAVE_QSORT */
|
static int SDLCALL qsort_non_r_bridge(void *userdata, const void *a, const void *b)
|
||||||
|
{
|
||||||
void *SDL_bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compare)(const void *, const void *))
|
int (SDLCALL *compare)(const void *, const void *) = (int (SDLCALL *)(const void *, const void *)) userdata;
|
||||||
|
return compare(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDL_qsort(void *base, size_t nmemb, size_t size, int (SDLCALL *compare) (const void *, const void *))
|
||||||
|
{
|
||||||
|
SDL_qsort_r(base, nmemb, size, qsort_non_r_bridge, compare);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't use the C runtime for such a simple function, since we want to allow SDLCALL callbacks and userdata.
|
||||||
|
// SDL's replacement: Taken from the Public Domain C Library (PDCLib):
|
||||||
|
// Permission is granted to use, modify, and / or redistribute at will.
|
||||||
|
void *SDL_bsearch_r(const void *key, const void *base, size_t nmemb, size_t size, int (SDLCALL *compare)(void *, const void *, const void *), void *userdata)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_BSEARCH
|
|
||||||
return bsearch(key, base, nmemb, size, compare);
|
|
||||||
#else
|
|
||||||
/* SDL's replacement: Taken from the Public Domain C Library (PDCLib):
|
|
||||||
Permission is granted to use, modify, and / or redistribute at will.
|
|
||||||
*/
|
|
||||||
const void *pivot;
|
const void *pivot;
|
||||||
size_t corr;
|
size_t corr;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -547,7 +544,7 @@ void *SDL_bsearch(const void *key, const void *base, size_t nmemb, size_t size,
|
||||||
corr = nmemb % 2;
|
corr = nmemb % 2;
|
||||||
nmemb /= 2;
|
nmemb /= 2;
|
||||||
pivot = (const char *)base + (nmemb * size);
|
pivot = (const char *)base + (nmemb * size);
|
||||||
rc = compare(key, pivot);
|
rc = compare(userdata, key, pivot);
|
||||||
|
|
||||||
if (rc > 0) {
|
if (rc > 0) {
|
||||||
base = (const char *)pivot + size;
|
base = (const char *)pivot + size;
|
||||||
|
@ -559,5 +556,11 @@ void *SDL_bsearch(const void *key, const void *base, size_t nmemb, size_t size,
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
#endif /* HAVE_BSEARCH */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *SDL_bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (SDLCALL *compare)(const void *, const void *))
|
||||||
|
{
|
||||||
|
// qsort_non_r_bridge just happens to match calling conventions, so reuse it.
|
||||||
|
return SDL_bsearch_r(key, base, nmemb, size, qsort_non_r_bridge, compare);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include <SDL3/SDL_main.h>
|
#include <SDL3/SDL_main.h>
|
||||||
#include <SDL3/SDL_test.h>
|
#include <SDL3/SDL_test.h>
|
||||||
|
|
||||||
|
static int a_global_var = 77;
|
||||||
|
|
||||||
static int SDLCALL
|
static int SDLCALL
|
||||||
num_compare(const void *_a, const void *_b)
|
num_compare(const void *_a, const void *_b)
|
||||||
{
|
{
|
||||||
|
@ -22,20 +24,36 @@ num_compare(const void *_a, const void *_b)
|
||||||
return (a < b) ? -1 : ((a > b) ? 1 : 0);
|
return (a < b) ? -1 : ((a > b) ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int SDLCALL
|
||||||
|
num_compare_r(void *userdata, const void *a, const void *b)
|
||||||
|
{
|
||||||
|
if (userdata != &a_global_var) {
|
||||||
|
SDL_Log("Uhoh, invalid userdata during qsort!");
|
||||||
|
}
|
||||||
|
return num_compare(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_sort(const char *desc, int *nums, const int arraylen)
|
test_sort(const char *desc, int *nums, const int arraylen)
|
||||||
{
|
{
|
||||||
|
static int nums_copy[1024 * 100];
|
||||||
int i;
|
int i;
|
||||||
int prev;
|
int prev;
|
||||||
|
|
||||||
|
SDL_assert(SDL_arraysize(nums_copy) >= arraylen);
|
||||||
|
|
||||||
SDL_Log("test: %s arraylen=%d", desc, arraylen);
|
SDL_Log("test: %s arraylen=%d", desc, arraylen);
|
||||||
|
|
||||||
|
SDL_memcpy(nums_copy, nums, arraylen * sizeof (*nums));
|
||||||
|
|
||||||
SDL_qsort(nums, arraylen, sizeof(nums[0]), num_compare);
|
SDL_qsort(nums, arraylen, sizeof(nums[0]), num_compare);
|
||||||
|
SDL_qsort_r(nums_copy, arraylen, sizeof(nums[0]), num_compare_r, &a_global_var);
|
||||||
|
|
||||||
prev = nums[0];
|
prev = nums[0];
|
||||||
for (i = 1; i < arraylen; i++) {
|
for (i = 1; i < arraylen; i++) {
|
||||||
const int val = nums[i];
|
const int val = nums[i];
|
||||||
if (val < prev) {
|
const int val2 = nums_copy[i];
|
||||||
|
if ((val < prev) || (val != val2)) {
|
||||||
SDL_Log("sort is broken!");
|
SDL_Log("sort is broken!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue