123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- #include "asmc_types.h"
- // All code in this file was taken from PDClib
- /* This implementation is taken from Paul Edward's PDPCLIB.
- 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.
- */
- #define _memswp( i, j, size ) char tmp; do { tmp = *i; *i++ = *j; *j++ = tmp; } while ( --size );
- /* Wrapper for _memswp protects against multiple argument evaluation. */
- static void memswp( char * i, char * j, size_t size )
- {
- _memswp( i, j, size );
- }
- /* 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
- void qsort( void * base, size_t nmemb, size_t size, int (*compar)( const void *, const void * ) )
- {
- char * i;
- char * j;
- 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 ( ;; )
- {
- 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 );
- }
- /* move pivot into correct place */
- memswp( base_, j, size );
- /* larger subfile base / limit to stack, sort smaller */
- if ( j - base_ > limit - i )
- {
- /* left is larger */
- PUSH( base_, j );
- base_ = i;
- }
- else
- {
- /* 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;
- }
- }
- }
- }
- #undef T
- #undef PREPARE_STACK
- #undef PUSH
- #undef POP
|