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