root/tags/v0.4.1/functions/stdlib/qsort.c

Revision 262, 4.6 kB (checked in by solar, 4 years ago)

v0.4.1 bugfix backport.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /* $Id$ */
2
3 /* Release $Name$ */
4
5 /* qsort( void *, size_t, size_t, int(*)( const void *, const void * ) )
6
7    This file is part of the Public Domain C Library (PDCLib).
8    Permission is granted to use, modify, and / or redistribute at will.
9 */
10
11 #include <stdlib.h>
12
13 #ifndef REGTEST
14
15 /* This implementation is losely based on Paul Edward's PDPCLIB, but
16    uses pure recursion on the larger subarray instead of the iterative
17    stack used by the original (and the v0.4 release of PDCLib), as a
18    possible stack overflow was suspected.
19 */
20
21 /* Wrapper for _PDCLIB_memswp protects against multiple argument evaluation. */
22 static inline void memswp( char * i, char * j, unsigned int size )
23 {
24     _PDCLIB_memswp( i, j, size );
25 }
26
27 /* For small sets, insertion sort is faster than quicksort.
28    T is the threshold below which insertion sort will be used.
29    Must be 3 or larger.
30 */
31 #define T 7
32
33 void qsort( void * base, size_t nmemb, size_t size, int (*compar)( const void *, const void * ) )
34 {
35     char * i;
36     char * j;
37     size_t thresh     = T * size;
38     char * base_      = (char *)base;
39     char * limit      = base_ + nmemb * size;
40
41     if ( ( nmemb == 0 ) || ( size == 0 ) || ( base == NULL ) )
42     {
43         return;
44     }
45
46     for ( ;; )
47     {
48         if ( limit - base_ > thresh ) /* QSort for more than T elements. */
49         {
50             /* We work from second to last - first will be pivot element. */
51             i = base_ + size;
52             j = limit - size;
53             /* We swap first with middle element, then sort that with second
54             and last element so that eventually first element is the median
55             of the three - avoiding pathological pivots.
56             */
57             memswp( ( ( ( (size_t)( limit - base_ ) ) / size ) / 2 ) * size + base_, base_, size );
58             if ( compar( i, j ) > 0 ) memswp( i, j, size );
59             if ( compar( base_, j ) > 0 ) memswp( base_, j, size );
60             if ( compar( i, base_ ) > 0 ) memswp( i, base_, size );
61             /* Now we have the median for pivot element, entering main Quicksort. */
62             for ( ;; )
63             {
64                 do
65                 {
66                     /* move i right until *i >= pivot */
67                     i += size;
68                 } while ( compar( i, base_ ) < 0 );
69                 do
70                 {
71                     /* move j left until *j <= pivot */
72                     j -= size;
73                 } while ( compar( j, base_ ) > 0 );
74                 if ( i > j )
75                 {
76                     /* break loop if pointers crossed */
77                     break;
78                 }
79                 /* else swap elements, keep scanning */
80                 memswp( i, j, size );
81             }
82             /* move pivot into correct place */
83             memswp( base_, j, size );
84             /* recurse into larger subpartition, iterate on smaller */
85             if ( j - base_ > limit - i )
86             {
87                 /* left is larger */
88                 qsort( base, ( j - base_ ) / size, size, compar );
89                 base_ = i;
90             }
91             else
92             {
93                 /* right is larger */
94                 qsort( i, ( limit - i ) / size, size, compar );
95                 limit = j;
96             }
97         }
98         else /* insertion sort for less than T elements              */
99         {
100             for ( j = base_, i = j + size; i < limit; j = i, i += size )
101             {
102                 for ( ; compar( j, j + size ) > 0; j -= size )
103                 {
104                     memswp( j, j + size, size );
105                     if ( j == base_ )
106                     {
107                         break;
108                     }
109                 }
110             }
111             break;
112         }
113     }
114     return;
115 }
116
117 #endif
118
119 #ifdef TEST
120 #include <_PDCLIB_test.h>
121 #include <string.h>
122 #include <limits.h>
123
124 int compare( const void * left, const void * right )
125 {
126     return *( (unsigned char *)left ) - *( (unsigned char *)right );
127 }
128
129 int main()
130 {
131     char presort[] = { "shreicnyjqpvozxmbt" };
132     char sorted1[] = { "bcehijmnopqrstvxyz" };
133     char sorted2[] = { "bticjqnyozpvreshxm" };
134     char s[19];
135     BEGIN_TESTS;
136     strcpy( s, presort );
137     qsort( s, 18, 1, compare );
138     TESTCASE( strcmp( s, sorted1 ) == 0 );
139     strcpy( s, presort );
140     qsort( s, 9, 2, compare );
141     TESTCASE( strcmp( s, sorted2 ) == 0 );
142     strcpy( s, presort );
143     qsort( s, 1, 1, compare );
144     TESTCASE( strcmp( s, presort ) == 0 );
145 #if __BSD_VISIBLE
146     puts( "qsort.c: Skipping test #4 for BSD as it goes into endless loop here." );
147 #else
148     qsort( s, 100, 0, compare );
149     TESTCASE( strcmp( s, presort ) == 0 );
150 #endif
151     return TEST_RESULTS;
152 }
153
154 #endif
155
Note: See TracBrowser for help on using the browser.