2015-06-21 09:33:46 -06:00
|
|
|
#include "../SDL_internal.h"
|
|
|
|
|
|
|
|
#include "SDL_stdinc.h"
|
|
|
|
#include "SDL_assert.h"
|
|
|
|
|
|
|
|
#if defined(HAVE_QSORT)
|
|
|
|
void
|
|
|
|
SDL_qsort(void *base, size_t nmemb, size_t size, int (*compare) (const void *, const void *))
|
|
|
|
{
|
|
|
|
qsort(base, nmemb, size, compare);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
#ifdef REGTEST
|
|
|
|
#undef REGTEST
|
2015-06-21 09:33:46 -06:00
|
|
|
#endif
|
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
#ifdef TEST
|
|
|
|
#undef TEST
|
|
|
|
#endif
|
2015-06-21 09:33:46 -06:00
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
#ifndef _PDCLIB_memswp
|
|
|
|
#define _PDCLIB_memswp( i, j, size ) char tmp; do { tmp = *i; *i++ = *j; *j++ = tmp; } while ( --size );
|
|
|
|
#endif
|
2015-06-21 09:33:46 -06:00
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
#ifndef _PDCLIB_size_t
|
|
|
|
#define _PDCLIB_size_t size_t
|
|
|
|
#endif
|
2015-06-21 09:33:46 -06:00
|
|
|
|
2016-02-15 01:21:26 -07:00
|
|
|
#ifdef qsort
|
|
|
|
#undef qsort
|
|
|
|
#endif
|
2016-02-15 01:16:46 -07:00
|
|
|
#define qsort SDL_qsort
|
2015-06-21 09:33:46 -06:00
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
#define inline SDL_INLINE
|
2015-06-21 09:33:46 -06:00
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
/*
|
|
|
|
This code came from PDCLib, under the public domain. Specifically this:
|
|
|
|
https://bitbucket.org/pdclib/pdclib/raw/a82b02d0c7d4ed633b97f2a7639d9a10b1c92ec8/functions/stdlib/qsort.c
|
|
|
|
The _PDCLIB_memswp macro was from
|
|
|
|
https://bitbucket.org/pdclib/pdclib/src/a82b02d0c7d4ed633b97f2a7639d9a10b1c92ec8/platform/posix/internals/_PDCLIB_config.h?at=default&fileviewer=file-view-default#_PDCLIB_config.h-28
|
2015-06-21 09:33:46 -06:00
|
|
|
|
2016-02-15 01:37:01 -07:00
|
|
|
Everything below this comment until the HAVE_QSORT #endif was from PDCLib (minor changes noted inline).
|
2016-02-15 01:16:46 -07:00
|
|
|
--ryan.
|
|
|
|
*/
|
2015-06-21 09:33:46 -06:00
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
/* $Id$ */
|
2015-06-21 09:33:46 -06:00
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
/* qsort( void *, size_t, size_t, int(*)( const void *, const void * ) )
|
2015-06-21 09:33:46 -06:00
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
This file is part of the Public Domain C Library (PDCLib).
|
|
|
|
Permission is granted to use, modify, and / or redistribute at will.
|
|
|
|
*/
|
2015-06-21 09:33:46 -06:00
|
|
|
|
2016-02-15 01:37:01 -07:00
|
|
|
/* I commented this out. --ryan. #include <stdlib.h> */
|
2015-06-21 09:33:46 -06:00
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
#ifndef REGTEST
|
2015-06-21 09:33:46 -06:00
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
/* This implementation is taken from Paul Edward's PDPCLIB.
|
2015-06-21 09:33:46 -06:00
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
Original code is credited to Raymond Gardner, Englewood CO.
|
|
|
|
Minor mods are credited to Paul Edwards.
|
|
|
|
Some reformatting and simplification done by Martin Baute.
|
|
|
|
All code is still Public Domain.
|
|
|
|
*/
|
2015-06-21 09:33:46 -06:00
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
/* Wrapper for _PDCLIB_memswp protects against multiple argument evaluation. */
|
|
|
|
static inline void memswp( char * i, char * j, size_t size )
|
2015-06-21 09:33:46 -06:00
|
|
|
{
|
2016-02-15 01:16:46 -07:00
|
|
|
_PDCLIB_memswp( i, j, size );
|
2015-06-21 09:33:46 -06:00
|
|
|
}
|
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
/* For small sets, insertion sort is faster than quicksort.
|
|
|
|
T is the threshold below which insertion sort will be used.
|
|
|
|
Must be 3 or larger.
|
|
|
|
*/
|
|
|
|
#define T 7
|
|
|
|
|
|
|
|
/* Macros for handling the QSort stack */
|
|
|
|
#define PREPARE_STACK char * stack[STACKSIZE]; char * * stackptr = stack
|
|
|
|
#define PUSH( base, limit ) stackptr[0] = base; stackptr[1] = limit; stackptr += 2
|
|
|
|
#define POP( base, limit ) stackptr -= 2; base = stackptr[0]; limit = stackptr[1]
|
|
|
|
/* TODO: Stack usage is log2( nmemb ) (minus what T shaves off the worst case).
|
|
|
|
Worst-case nmemb is platform dependent and should probably be
|
|
|
|
configured through _PDCLIB_config.h.
|
|
|
|
*/
|
|
|
|
#define STACKSIZE 64
|
2015-06-21 09:33:46 -06:00
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
void qsort( void * base, size_t nmemb, size_t size, int (*compar)( const void *, const void * ) )
|
2015-06-21 09:33:46 -06:00
|
|
|
{
|
2016-02-15 01:16:46 -07:00
|
|
|
char * i;
|
|
|
|
char * j;
|
|
|
|
_PDCLIB_size_t thresh = T * size;
|
|
|
|
char * base_ = (char *)base;
|
|
|
|
char * limit = base_ + nmemb * size;
|
|
|
|
PREPARE_STACK;
|
|
|
|
|
|
|
|
for ( ;; )
|
|
|
|
{
|
|
|
|
if ( (size_t)( limit - base_ ) > thresh ) /* QSort for more than T elements. */
|
|
|
|
{
|
|
|
|
/* We work from second to last - first will be pivot element. */
|
|
|
|
i = base_ + size;
|
|
|
|
j = limit - size;
|
|
|
|
/* We swap first with middle element, then sort that with second
|
|
|
|
and last element so that eventually first element is the median
|
|
|
|
of the three - avoiding pathological pivots.
|
|
|
|
TODO: Instead of middle element, chose one randomly.
|
|
|
|
*/
|
|
|
|
memswp( ( ( ( (size_t)( limit - base_ ) ) / size ) / 2 ) * size + base_, base_, size );
|
|
|
|
if ( compar( i, j ) > 0 ) memswp( i, j, size );
|
|
|
|
if ( compar( base_, j ) > 0 ) memswp( base_, j, size );
|
|
|
|
if ( compar( i, base_ ) > 0 ) memswp( i, base_, size );
|
|
|
|
/* Now we have the median for pivot element, entering main Quicksort. */
|
|
|
|
for ( ;; )
|
2015-06-21 09:33:46 -06:00
|
|
|
{
|
2016-02-15 01:16:46 -07:00
|
|
|
do
|
|
|
|
{
|
|
|
|
/* move i right until *i >= pivot */
|
|
|
|
i += size;
|
|
|
|
} while ( compar( i, base_ ) < 0 );
|
|
|
|
do
|
|
|
|
{
|
|
|
|
/* move j left until *j <= pivot */
|
|
|
|
j -= size;
|
|
|
|
} while ( compar( j, base_ ) > 0 );
|
|
|
|
if ( i > j )
|
|
|
|
{
|
|
|
|
/* break loop if pointers crossed */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* else swap elements, keep scanning */
|
|
|
|
memswp( i, j, size );
|
2015-06-21 09:33:46 -06:00
|
|
|
}
|
2016-02-15 01:16:46 -07:00
|
|
|
/* move pivot into correct place */
|
|
|
|
memswp( base_, j, size );
|
|
|
|
/* larger subfile base / limit to stack, sort smaller */
|
|
|
|
if ( j - base_ > limit - i )
|
2015-06-21 09:33:46 -06:00
|
|
|
{
|
2016-02-15 01:16:46 -07:00
|
|
|
/* left is larger */
|
|
|
|
PUSH( base_, j );
|
|
|
|
base_ = i;
|
2015-06-21 09:33:46 -06:00
|
|
|
}
|
2016-02-15 01:16:46 -07:00
|
|
|
else
|
2015-06-21 09:33:46 -06:00
|
|
|
{
|
2016-02-15 01:16:46 -07:00
|
|
|
/* right is larger */
|
|
|
|
PUSH( i, limit );
|
|
|
|
limit = j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else /* insertion sort for less than T elements */
|
|
|
|
{
|
|
|
|
for ( j = base_, i = j + size; i < limit; j = i, i += size )
|
|
|
|
{
|
|
|
|
for ( ; compar( j, j + size ) > 0; j -= size )
|
|
|
|
{
|
|
|
|
memswp( j, j + size, size );
|
|
|
|
if ( j == base_ )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( stackptr != stack ) /* if any entries on stack */
|
|
|
|
{
|
|
|
|
POP( base_, limit );
|
|
|
|
}
|
|
|
|
else /* else stack empty, done */
|
|
|
|
{
|
|
|
|
break;
|
2015-06-21 09:33:46 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
#endif
|
2015-06-21 09:33:46 -06:00
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
#ifdef TEST
|
|
|
|
#include <_PDCLIB_test.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
static int compare( const void * left, const void * right )
|
2015-06-21 09:33:46 -06:00
|
|
|
{
|
2016-02-15 01:16:46 -07:00
|
|
|
return *( (unsigned char *)left ) - *( (unsigned char *)right );
|
|
|
|
}
|
2015-06-21 09:33:46 -06:00
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
int main( void )
|
|
|
|
{
|
|
|
|
char presort[] = { "shreicnyjqpvozxmbt" };
|
|
|
|
char sorted1[] = { "bcehijmnopqrstvxyz" };
|
|
|
|
char sorted2[] = { "bticjqnyozpvreshxm" };
|
|
|
|
char s[19];
|
|
|
|
strcpy( s, presort );
|
|
|
|
qsort( s, 18, 1, compare );
|
|
|
|
TESTCASE( strcmp( s, sorted1 ) == 0 );
|
|
|
|
strcpy( s, presort );
|
|
|
|
qsort( s, 9, 2, compare );
|
|
|
|
TESTCASE( strcmp( s, sorted2 ) == 0 );
|
|
|
|
strcpy( s, presort );
|
|
|
|
qsort( s, 1, 1, compare );
|
|
|
|
TESTCASE( strcmp( s, presort ) == 0 );
|
|
|
|
#if defined(REGTEST) && (__BSD_VISIBLE || __APPLE__)
|
|
|
|
puts( "qsort.c: Skipping test #4 for BSD as it goes into endless loop here." );
|
|
|
|
#else
|
|
|
|
qsort( s, 100, 0, compare );
|
|
|
|
TESTCASE( strcmp( s, presort ) == 0 );
|
|
|
|
#endif
|
|
|
|
return TEST_RESULTS;
|
2015-06-21 09:33:46 -06:00
|
|
|
}
|
|
|
|
|
2016-02-15 01:16:46 -07:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif /* HAVE_QSORT */
|
2015-06-21 09:33:46 -06:00
|
|
|
|
|
|
|
/* vi: set ts=4 sw=4 expandtab: */
|