github.com/afumu/libc@v0.0.6/musl/src/stdlib/qsort.c (about) 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 }