da58fd3177814634d7e1b9b06ea2135ee633295f
[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 /* Smoothsort, an adaptive variant of Heapsort.  Memory usage: O(1).
25    Run time: Worst case O(n log n), close to O(n) in the mostly-sorted case. */
26
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "atomic.h"
32 #define ntz(x) a_ctz_l((x))
33
34 typedef int (*cmpfun)(const void *, const void *);
35
36 static inline int pntz(size_t p[2]) {
37         int r = ntz(p[0] - 1);
38         if(r != 0 || (r = 8*sizeof(size_t) + ntz(p[1])) != 8*sizeof(size_t)) {
39                 return r;
40         }
41         return 0;
42 }
43
44 static void cycle(size_t width, unsigned char* ar[], int n)
45 {
46         unsigned char tmp[256];
47         size_t l;
48         int i;
49
50         if(n < 2) {
51                 return;
52         }
53
54         ar[n] = tmp;
55         while(width) {
56                 l = sizeof(tmp) < width ? sizeof(tmp) : width;
57                 memcpy(ar[n], ar[0], l);
58                 for(i = 0; i < n; i++) {
59                         memcpy(ar[i], ar[i + 1], l);
60                         ar[i] += l;
61                 }
62                 width -= l;
63         }
64 }
65
66 /* shl() and shr() need n > 0 */
67 static inline void shl(size_t p[2], int n)
68 {
69         if(n >= 8 * sizeof(size_t)) {
70                 n -= 8 * sizeof(size_t);
71                 p[1] = p[0];
72                 p[0] = 0;
73         }
74         p[1] <<= n;
75         p[1] |= p[0] >> (sizeof(size_t) * 8 - n);
76         p[0] <<= n;
77 }
78
79 static inline void shr(size_t p[2], int n)
80 {
81         if(n >= 8 * sizeof(size_t)) {
82                 n -= 8 * sizeof(size_t);
83                 p[0] = p[1];
84                 p[1] = 0;
85         }
86         p[0] >>= n;
87         p[0] |= p[1] << (sizeof(size_t) * 8 - n);
88         p[1] >>= n;
89 }
90
91 static void sift(unsigned char *head, size_t width, cmpfun cmp, int pshift, size_t lp[])
92 {
93         unsigned char *rt, *lf;
94         unsigned char *ar[14 * sizeof(size_t) + 1];
95         int i = 1;
96
97         ar[0] = head;
98         while(pshift > 1) {
99                 rt = head - width;
100                 lf = head - width - lp[pshift - 2];
101
102                 if((*cmp)(ar[0], lf) >= 0 && (*cmp)(ar[0], rt) >= 0) {
103                         break;
104                 }
105                 if((*cmp)(lf, rt) >= 0) {
106                         ar[i++] = lf;
107                         head = lf;
108                         pshift -= 1;
109                 } else {
110                         ar[i++] = rt;
111                         head = rt;
112                         pshift -= 2;
113                 }
114         }
115         cycle(width, ar, i);
116 }
117
118 static void trinkle(unsigned char *head, size_t width, cmpfun cmp, size_t pp[2], int pshift, int trusty, size_t lp[])
119 {
120         unsigned char *stepson,
121                       *rt, *lf;
122         size_t p[2];
123         unsigned char *ar[14 * sizeof(size_t) + 1];
124         int i = 1;
125         int trail;
126
127         p[0] = pp[0];
128         p[1] = pp[1];
129
130         ar[0] = head;
131         while(p[0] != 1 || p[1] != 0) {
132                 stepson = head - lp[pshift];
133                 if((*cmp)(stepson, ar[0]) <= 0) {
134                         break;
135                 }
136                 if(!trusty && pshift > 1) {
137                         rt = head - width;
138                         lf = head - width - lp[pshift - 2];
139                         if((*cmp)(rt, stepson) >= 0 || (*cmp)(lf, stepson) >= 0) {
140                                 break;
141                         }
142                 }
143
144                 ar[i++] = stepson;
145                 head = stepson;
146                 trail = pntz(p);
147                 shr(p, trail);
148                 pshift += trail;
149                 trusty = 0;
150         }
151         if(!trusty) {
152                 cycle(width, ar, i);
153                 sift(head, width, cmp, pshift, lp);
154         }
155 }
156
157 void qsort(void *base, size_t nel, size_t width, cmpfun cmp)
158 {
159         size_t lp[12*sizeof(size_t)];
160         size_t i, size = width * nel;
161         unsigned char *head, *high;
162         size_t p[2] = {1, 0};
163         int pshift = 1;
164         int trail;
165
166         if (!size) return;
167
168         head = base;
169         high = head + size - width;
170
171         /* Precompute Leonardo numbers, scaled by element width */
172         for(lp[0]=lp[1]=width, i=2; (lp[i]=lp[i-2]+lp[i-1]+width) < size; i++);
173
174         while(head < high) {
175                 if((p[0] & 3) == 3) {
176                         sift(head, width, cmp, pshift, lp);
177                         shr(p, 2);
178                         pshift += 2;
179                 } else {
180                         if(lp[pshift - 1] >= high - head) {
181                                 trinkle(head, width, cmp, p, pshift, 0, lp);
182                         } else {
183                                 sift(head, width, cmp, pshift, lp);
184                         }
185                         
186                         if(pshift == 1) {
187                                 shl(p, 1);
188                                 pshift = 0;
189                         } else {
190                                 shl(p, pshift - 1);
191                                 pshift = 1;
192                         }
193                 }
194                 
195                 p[0] |= 1;
196                 head += width;
197         }
198
199         trinkle(head, width, cmp, p, pshift, 0, lp);
200
201         while(pshift != 1 || p[0] != 1 || p[1] != 0) {
202                 if(pshift <= 1) {
203                         trail = pntz(p);
204                         shr(p, trail);
205                         pshift += trail;
206                 } else {
207                         shl(p, 2);
208                         pshift -= 2;
209                         p[0] ^= 7;
210                         shr(p, 1);
211                         trinkle(head - lp[pshift] - width, width, cmp, p, pshift + 1, 1, lp);
212                         shl(p, 1);
213                         p[0] |= 1;
214                         trinkle(head - width, width, cmp, p, pshift, 1, lp);
215                 }
216                 head -= width;
217         }
218 }