866af0ecd6c2a394f896a8e3d8a0403e9da94577
[musl] / src / stdlib / qsort.c
1 /* Copyright (C) 2011 by Valentin Ochs
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21
22 /* Minor changes by Rich Felker for integration in musl, 2011-04-27. */
23
24 #include <stdint.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "atomic.h"
29 #define ntz(x) a_ctz_l((x))
30
31 typedef int (*cmpfun)(const void *, const void *);
32
33 static inline int pntz(size_t p[2]) {
34         int r = ntz(p[0] - 1);
35         if(r != 0 || (r = 8*sizeof(size_t) + ntz(p[1])) != 8*sizeof(size_t)) {
36                 return r;
37         }
38         return 0;
39 }
40
41 static void cycle(size_t width, unsigned char* ar[], int n)
42 {
43         unsigned char tmp[256];
44         size_t l;
45         int i;
46
47         if(n < 2) {
48                 return;
49         }
50
51         ar[n] = tmp;
52         while(width) {
53                 l = sizeof(tmp) < width ? sizeof(tmp) : width;
54                 memcpy(ar[n], ar[0], l);
55                 for(i = 0; i < n; i++) {
56                         memcpy(ar[i], ar[i + 1], l);
57                         ar[i] += l;
58                 }
59                 width -= l;
60         }
61 }
62
63 /* shl() and shr() need n > 0 */
64 static inline void shl(size_t p[2], int n)
65 {
66         if(n >= 8 * sizeof(size_t)) {
67                 n -= 8 * sizeof(size_t);
68                 p[1] = p[0];
69                 p[0] = 0;
70         }
71         p[1] <<= n;
72         p[1] |= p[0] >> (sizeof(size_t) * 8 - n);
73         p[0] <<= n;
74 }
75
76 static inline void shr(size_t p[2], int n)
77 {
78         if(n >= 8 * sizeof(size_t)) {
79                 n -= 8 * sizeof(size_t);
80                 p[0] = p[1];
81                 p[1] = 0;
82         }
83         p[0] >>= n;
84         p[0] |= p[1] << (sizeof(size_t) * 8 - n);
85         p[1] >>= n;
86 }
87
88 static void sift(unsigned char *head, size_t width, cmpfun cmp, int pshift, size_t lp[])
89 {
90         unsigned char *rt, *lf;
91         unsigned char *ar[14 * sizeof(size_t) + 1];
92         int i = 1;
93
94         ar[0] = head;
95         while(pshift > 1) {
96                 rt = head - width;
97                 lf = head - width - lp[pshift - 2];
98
99                 if((*cmp)(ar[0], lf) >= 0 && (*cmp)(ar[0], rt) >= 0) {
100                         break;
101                 }
102                 if((*cmp)(lf, rt) >= 0) {
103                         ar[i++] = lf;
104                         head = lf;
105                         pshift -= 1;
106                 } else {
107                         ar[i++] = rt;
108                         head = rt;
109                         pshift -= 2;
110                 }
111         }
112         cycle(width, ar, i);
113 }
114
115 static void trinkle(unsigned char *head, size_t width, cmpfun cmp, size_t pp[2], int pshift, int trusty, size_t lp[])
116 {
117         unsigned char *stepson,
118                       *rt, *lf;
119         size_t p[2];
120         unsigned char *ar[14 * sizeof(size_t) + 1];
121         int i = 1;
122         int trail;
123
124         p[0] = pp[0];
125         p[1] = pp[1];
126
127         ar[0] = head;
128         while(p[0] != 1 || p[1] != 0) {
129                 stepson = head - lp[pshift];
130                 if((*cmp)(stepson, ar[0]) <= 0) {
131                         break;
132                 }
133                 if(!trusty && pshift > 1) {
134                         rt = head - width;
135                         lf = head - width - lp[pshift - 2];
136                         if((*cmp)(rt, stepson) >= 0 || (*cmp)(lf, stepson) >= 0) {
137                                 break;
138                         }
139                 }
140
141                 ar[i++] = stepson;
142                 head = stepson;
143                 trail = pntz(p);
144                 shr(p, trail);
145                 pshift += trail;
146                 trusty = 0;
147         }
148         if(!trusty) {
149                 cycle(width, ar, i);
150                 sift(head, width, cmp, pshift, lp);
151         }
152 }
153
154 void qsort(void *base, size_t nel, size_t width, cmpfun cmp)
155 {
156         size_t lp[12*sizeof(size_t)];
157         size_t i, size = width * nel;
158         unsigned char *head = base,
159                       *high = head + size - width;
160         size_t p[2] = {1, 0};
161         int pshift = 1;
162         int trail;
163
164         /* Precompute Leonardo numbers, scaled by element width */
165         for(lp[0]=lp[1]=width, i=2; (lp[i]=lp[i-2]+lp[i-1]+width) < size; i++);
166
167         while(head < high) {
168                 if((p[0] & 3) == 3) {
169                         sift(head, width, cmp, pshift, lp);
170                         shr(p, 2);
171                         pshift += 2;
172                 } else {
173                         if(lp[pshift - 1] >= high - head) {
174                                 trinkle(head, width, cmp, p, pshift, 0, lp);
175                         } else {
176                                 sift(head, width, cmp, pshift, lp);
177                         }
178                         
179                         if(pshift == 1) {
180                                 shl(p, 1);
181                                 pshift = 0;
182                         } else {
183                                 shl(p, pshift - 1);
184                                 pshift = 1;
185                         }
186                 }
187                 
188                 p[0] |= 1;
189                 head += width;
190         }
191
192         trinkle(head, width, cmp, p, pshift, 0, lp);
193
194         while(pshift != 1 || p[0] != 1 || p[1] != 0) {
195                 if(pshift <= 1) {
196                         trail = pntz(p);
197                         shr(p, trail);
198                         pshift += trail;
199                 } else {
200                         shl(p, 2);
201                         pshift -= 2;
202                         p[0] ^= 7;
203                         shr(p, 1);
204                         trinkle(head - lp[pshift] - width, width, cmp, p, pshift + 1, 1, lp);
205                         shl(p, 1);
206                         p[0] |= 1;
207                         trinkle(head - width, width, cmp, p, pshift, 1, lp);
208                 }
209                 head -= width;
210         }
211 }