3 /* qsort( void *, size_t, size_t, int(*)( const void *, const void * ) )
5 This file is part of the Public Domain C Library (PDCLib).
6 Permission is granted to use, modify, and / or redistribute at will.
13 /* This implementation is taken from Paul Edward's PDPCLIB.
15 Original code is credited to Raymond Gardner, Englewood CO.
16 Minor mods are credited to Paul Edwards.
17 Some reformatting and simplification done by Martin Baute.
18 All code is still Public Domain.
21 /* Wrapper for _PDCLIB_memswp protects against multiple argument evaluation. */
22 static inline void memswp( char * i, char * j, size_t size )
24 _PDCLIB_memswp( i, j, size );
27 /* For small sets, insertion sort is faster than quicksort.
28 T is the threshold below which insertion sort will be used.
33 /* Macros for handling the QSort stack */
34 #define PREPARE_STACK char * stack[STACKSIZE]; char * * stackptr = stack
35 #define PUSH( base, limit ) stackptr[0] = base; stackptr[1] = limit; stackptr += 2
36 #define POP( base, limit ) stackptr -= 2; base = stackptr[0]; limit = stackptr[1]
37 /* TODO: This is platform-dependent */
40 void qsort( void * base, size_t nmemb, size_t size, int (*compar)( const void *, const void * ) )
44 _PDCLIB_size_t thresh = T * size;
45 char * base_ = (char *)base;
46 char * limit = base_ + nmemb * size;
51 if ( (size_t)( limit - base_ ) > thresh ) /* QSort for more than T elements. */
53 /* We work from second to last - first will be pivot element. */
56 /* We swap first with middle element, then sort that with second
57 and last element so that eventually first element is the median
58 of the three - avoiding pathological pivots.
59 TODO: Instead of middle element, chose one randomly.
61 memswp( ( ( ( (size_t)( limit - base_ ) ) / size ) / 2 ) * size + base_, base_, size );
62 if ( compar( i, j ) > 0 ) memswp( i, j, size );
63 if ( compar( base_, j ) > 0 ) memswp( base_, j, size );
64 if ( compar( i, base_ ) > 0 ) memswp( i, base_, size );
65 /* Now we have the median for pivot element, entering main Quicksort. */
70 /* move i right until *i >= pivot */
72 } while ( compar( i, base_ ) < 0 );
75 /* move j left until *j <= pivot */
77 } while ( compar( j, base_ ) > 0 );
80 /* break loop if pointers crossed */
83 /* else swap elements, keep scanning */
86 /* move pivot into correct place */
87 memswp( base_, j, size );
88 /* larger subfile base / limit to stack, sort smaller */
89 if ( j - base_ > limit - i )
102 else /* insertion sort for less than T elements */
104 for ( j = base_, i = j + size; i < limit; j = i, i += size )
106 for ( ; compar( j, j + size ) > 0; j -= size )
108 memswp( j, j + size, size );
115 if ( stackptr != stack ) /* if any entries on stack */
119 else /* else stack empty, done */
130 #include <_PDCLIB_test.h>
134 static int compare( const void * left, const void * right )
136 return *( (unsigned char *)left ) - *( (unsigned char *)right );
141 char presort[] = { "shreicnyjqpvozxmbt" };
142 char sorted1[] = { "bcehijmnopqrstvxyz" };
143 char sorted2[] = { "bticjqnyozpvreshxm" };
145 strcpy( s, presort );
146 qsort( s, 18, 1, compare );
147 TESTCASE( strcmp( s, sorted1 ) == 0 );
148 strcpy( s, presort );
149 qsort( s, 9, 2, compare );
150 TESTCASE( strcmp( s, sorted2 ) == 0 );
151 strcpy( s, presort );
152 qsort( s, 1, 1, compare );
153 TESTCASE( strcmp( s, presort ) == 0 );
155 puts( "qsort.c: Skipping test #4 for BSD as it goes into endless loop here." );
157 qsort( s, 100, 0, compare );
158 TESTCASE( strcmp( s, presort ) == 0 );