Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/waterbox/libc/functions/stdlib/qsort.c
2 views
1
/* qsort( void *, size_t, size_t, int(*)( const void *, const void * ) )
2
3
This file is part of the Public Domain C Library (PDCLib).
4
Permission is granted to use, modify, and / or redistribute at will.
5
*/
6
7
#include <stdlib.h>
8
9
#ifndef REGTEST
10
11
/* This implementation is taken from Paul Edward's PDPCLIB.
12
13
Original code is credited to Raymond Gardner, Englewood CO.
14
Minor mods are credited to Paul Edwards.
15
Some reformatting and simplification done by Martin Baute.
16
All code is still Public Domain.
17
*/
18
19
/* Wrapper for _PDCLIB_memswp protects against multiple argument evaluation. */
20
static inline void memswp( char * i, char * j, size_t size )
21
{
22
_PDCLIB_memswp( i, j, size );
23
}
24
25
/* For small sets, insertion sort is faster than quicksort.
26
T is the threshold below which insertion sort will be used.
27
Must be 3 or larger.
28
*/
29
#define T 7
30
31
/* Macros for handling the QSort stack */
32
#define PREPARE_STACK char * stack[STACKSIZE]; char * * stackptr = stack
33
#define PUSH( base, limit ) stackptr[0] = base; stackptr[1] = limit; stackptr += 2
34
#define POP( base, limit ) stackptr -= 2; base = stackptr[0]; limit = stackptr[1]
35
/* TODO: Stack usage is log2( nmemb ) (minus what T shaves off the worst case).
36
Worst-case nmemb is platform dependent and should probably be
37
configured through _PDCLIB_config.h.
38
*/
39
#define STACKSIZE 64
40
41
void qsort( void * base, size_t nmemb, size_t size, int (*compar)( const void *, const void * ) )
42
{
43
char * i;
44
char * j;
45
_PDCLIB_size_t thresh = T * size;
46
char * base_ = (char *)base;
47
char * limit = base_ + nmemb * size;
48
PREPARE_STACK;
49
50
for ( ;; )
51
{
52
if ( (size_t)( limit - base_ ) > thresh ) /* QSort for more than T elements. */
53
{
54
/* We work from second to last - first will be pivot element. */
55
i = base_ + size;
56
j = limit - size;
57
/* We swap first with middle element, then sort that with second
58
and last element so that eventually first element is the median
59
of the three - avoiding pathological pivots.
60
TODO: Instead of middle element, chose one randomly.
61
*/
62
memswp( ( ( ( (size_t)( limit - base_ ) ) / size ) / 2 ) * size + base_, base_, size );
63
if ( compar( i, j ) > 0 ) memswp( i, j, size );
64
if ( compar( base_, j ) > 0 ) memswp( base_, j, size );
65
if ( compar( i, base_ ) > 0 ) memswp( i, base_, size );
66
/* Now we have the median for pivot element, entering main Quicksort. */
67
for ( ;; )
68
{
69
do
70
{
71
/* move i right until *i >= pivot */
72
i += size;
73
} while ( compar( i, base_ ) < 0 );
74
do
75
{
76
/* move j left until *j <= pivot */
77
j -= size;
78
} while ( compar( j, base_ ) > 0 );
79
if ( i > j )
80
{
81
/* break loop if pointers crossed */
82
break;
83
}
84
/* else swap elements, keep scanning */
85
memswp( i, j, size );
86
}
87
/* move pivot into correct place */
88
memswp( base_, j, size );
89
/* larger subfile base / limit to stack, sort smaller */
90
if ( j - base_ > limit - i )
91
{
92
/* left is larger */
93
PUSH( base_, j );
94
base_ = i;
95
}
96
else
97
{
98
/* right is larger */
99
PUSH( i, limit );
100
limit = j;
101
}
102
}
103
else /* insertion sort for less than T elements */
104
{
105
for ( j = base_, i = j + size; i < limit; j = i, i += size )
106
{
107
for ( ; compar( j, j + size ) > 0; j -= size )
108
{
109
memswp( j, j + size, size );
110
if ( j == base_ )
111
{
112
break;
113
}
114
}
115
}
116
if ( stackptr != stack ) /* if any entries on stack */
117
{
118
POP( base_, limit );
119
}
120
else /* else stack empty, done */
121
{
122
break;
123
}
124
}
125
}
126
}
127
128
#endif
129
130
#ifdef TEST
131
#include "_PDCLIB_test.h"
132
#include <string.h>
133
#include <limits.h>
134
135
static int compare( const void * left, const void * right )
136
{
137
return *( (unsigned char *)left ) - *( (unsigned char *)right );
138
}
139
140
int main( void )
141
{
142
char presort[] = { "shreicnyjqpvozxmbt" };
143
char sorted1[] = { "bcehijmnopqrstvxyz" };
144
char sorted2[] = { "bticjqnyozpvreshxm" };
145
char s[19];
146
strcpy( s, presort );
147
qsort( s, 18, 1, compare );
148
TESTCASE( strcmp( s, sorted1 ) == 0 );
149
strcpy( s, presort );
150
qsort( s, 9, 2, compare );
151
TESTCASE( strcmp( s, sorted2 ) == 0 );
152
strcpy( s, presort );
153
qsort( s, 1, 1, compare );
154
TESTCASE( strcmp( s, presort ) == 0 );
155
#if defined(REGTEST) && (__BSD_VISIBLE || __APPLE__)
156
puts( "qsort.c: Skipping test #4 for BSD as it goes into endless loop here." );
157
#else
158
qsort( s, 100, 0, compare );
159
TESTCASE( strcmp( s, presort ) == 0 );
160
#endif
161
return TEST_RESULTS;
162
}
163
164
#endif
165
166