• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define _BSD_SOURCE
23 #include <stdlib.h>
24 #include <string.h>
25 
26 typedef int (*cmpfun)(const void *, const void *, void *);
27 
28 #define MIDDLE_ONE(a, b, c, arg)                                    \
29     cmp(a, b, arg) < 0 ?                                            \
30     (cmp(b, c, arg) < 0 ? (b) : (cmp(a, c, arg) < 0 ? (c) : (a))) : \
31     (cmp(b, c, arg) > 0 ? (b) : (cmp(a, c, arg) < 0 ? (a) : (c)))
32 
33 #define SWAPN(a, b, n)                                           \
34     do {                                                         \
35         register char *x = (char *)(a);                          \
36         register char *y = (char *)(b);                          \
37         register char tmp;                                       \
38         int i = (n) / sizeof(char);                              \
39         for (--i; i >= 0; i--) {                                 \
40             tmp = *x;                                            \
41             *x++ = *y;                                           \
42             *y++ = tmp;                                          \
43         }                                                        \
44     } while (0)
45 
__qsort_r(void * base,size_t nel,size_t width,cmpfun cmp,void * arg)46 void __qsort_r(void *base, size_t nel, size_t width, cmpfun cmp, void *arg)
47 {
48     char *start, *end, *m, *l, *r;
49     int i, j, swapflag = 0;
50     char temp[width];
51 
52     if (width == 0 || base == NULL || nel == 0) {
53         return;
54     }
55 
56     start = (char *)base;
57     end = start + (nel - 1) * width;
58 loop:
59     if (nel < 7) { // insertion sort
60 insertqort:
61         for (l = start + width; l <= end; l += width) {
62             memcpy(temp, l, width);
63             for (m = l - width; m >= start; m -= width) {
64                 if (cmp(m, temp, arg) > 0) {
65                     memcpy((m + width), m, width);
66                 } else {
67                     break;
68                 }
69             }
70             memcpy((m + width), temp, width);
71         }
72         return;
73     }
74 
75     // quick sort
76     m = start + (nel >> 1) * width;
77     m = MIDDLE_ONE(start, m, end, arg);
78     if (m != start) {
79         SWAPN(start, m, width);
80         m = start;
81     }
82     l = start + width;
83     r = end;
84 
85     while (l <= r) {
86         while (l <= r && cmp(l, m, arg) < 0) {
87             l += width;
88         }
89         while (l <= r && cmp(r, m, arg) >= 0) {
90             r -= width;
91         }
92         if (l < r) {
93             SWAPN(l, r, width);
94             l += width;
95             r -= width;
96             swapflag = 1;
97         }
98     }
99     SWAPN(m, l - width, width);
100     m = l - width;
101     if (swapflag == 0) {
102         goto insertqort;
103     }
104 
105     if (m - start > end - m) {
106         __qsort_r(start, (m - start) / width, width, cmp, arg);
107         if (m == end) {
108             return;
109         }
110         start = m + width;
111         nel = (end - start) / width + 1;
112         goto loop;
113     } else {
114         __qsort_r(m + width, (end - m) / width, width, cmp, arg);
115         if (m == start) {
116             return;
117         }
118         end = m - width;
119         nel = (end - start) / width + 1;
120         goto loop;
121     }
122 }
123 
124 weak_alias(__qsort_r, qsort_r);
125