xref: /f-stack/app/redis-5.0.5/src/pqsort.c (revision 572c4311)
1 /* The following is the NetBSD libc qsort implementation modified in order to
2  * support partial sorting of ranges for Redis.
3  *
4  * Copyright(C) 2009-2012 Salvatore Sanfilippo. All rights reserved.
5  *
6  * The original copyright notice follows. */
7 
8 
9 /*	$NetBSD: qsort.c,v 1.19 2009/01/30 23:38:44 lukem Exp $	*/
10 
11 /*-
12  * Copyright (c) 1992, 1993
13  *	The Regents of the University of California.  All rights reserved.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer.
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  * 3. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  */
39 
40 #include <sys/types.h>
41 
42 #include <errno.h>
43 #include <stdlib.h>
44 
45 static inline char	*med3 (char *, char *, char *,
46     int (*)(const void *, const void *));
47 static inline void	 swapfunc (char *, char *, size_t, int);
48 
49 #define min(a, b)	(a) < (b) ? a : b
50 
51 /*
52  * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
53  */
54 #define swapcode(TYPE, parmi, parmj, n) { 		\
55 	size_t i = (n) / sizeof (TYPE); 		\
56 	TYPE *pi = (TYPE *)(void *)(parmi); 		\
57 	TYPE *pj = (TYPE *)(void *)(parmj); 		\
58 	do { 						\
59 		TYPE	t = *pi;			\
60 		*pi++ = *pj;				\
61 		*pj++ = t;				\
62         } while (--i > 0);				\
63 }
64 
65 #define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
66 	es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
67 
68 static inline void
swapfunc(char * a,char * b,size_t n,int swaptype)69 swapfunc(char *a, char *b, size_t n, int swaptype)
70 {
71 
72 	if (swaptype <= 1)
73 		swapcode(long, a, b, n)
74 	else
75 		swapcode(char, a, b, n)
76 }
77 
78 #define swap(a, b)						\
79 	if (swaptype == 0) {					\
80 		long t = *(long *)(void *)(a);			\
81 		*(long *)(void *)(a) = *(long *)(void *)(b);	\
82 		*(long *)(void *)(b) = t;			\
83 	} else							\
84 		swapfunc(a, b, es, swaptype)
85 
86 #define vecswap(a, b, n) if ((n) > 0) swapfunc((a), (b), (size_t)(n), swaptype)
87 
88 static inline char *
med3(char * a,char * b,char * c,int (* cmp)(const void *,const void *))89 med3(char *a, char *b, char *c,
90     int (*cmp) (const void *, const void *))
91 {
92 
93 	return cmp(a, b) < 0 ?
94 	       (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
95               :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
96 }
97 
98 static void
_pqsort(void * a,size_t n,size_t es,int (* cmp)(const void *,const void *),void * lrange,void * rrange)99 _pqsort(void *a, size_t n, size_t es,
100     int (*cmp) (const void *, const void *), void *lrange, void *rrange)
101 {
102 	char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
103 	size_t d, r;
104 	int swaptype, cmp_result;
105 
106 loop:	SWAPINIT(a, es);
107 	if (n < 7) {
108 		for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
109 			for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
110 			     pl -= es)
111 				swap(pl, pl - es);
112 		return;
113 	}
114 	pm = (char *) a + (n / 2) * es;
115 	if (n > 7) {
116 		pl = (char *) a;
117 		pn = (char *) a + (n - 1) * es;
118 		if (n > 40) {
119 			d = (n / 8) * es;
120 			pl = med3(pl, pl + d, pl + 2 * d, cmp);
121 			pm = med3(pm - d, pm, pm + d, cmp);
122 			pn = med3(pn - 2 * d, pn - d, pn, cmp);
123 		}
124 		pm = med3(pl, pm, pn, cmp);
125 	}
126 	swap(a, pm);
127 	pa = pb = (char *) a + es;
128 
129 	pc = pd = (char *) a + (n - 1) * es;
130 	for (;;) {
131 		while (pb <= pc && (cmp_result = cmp(pb, a)) <= 0) {
132 			if (cmp_result == 0) {
133 				swap(pa, pb);
134 				pa += es;
135 			}
136 			pb += es;
137 		}
138 		while (pb <= pc && (cmp_result = cmp(pc, a)) >= 0) {
139 			if (cmp_result == 0) {
140 				swap(pc, pd);
141 				pd -= es;
142 			}
143 			pc -= es;
144 		}
145 		if (pb > pc)
146 			break;
147 		swap(pb, pc);
148 		pb += es;
149 		pc -= es;
150 	}
151 
152 	pn = (char *) a + n * es;
153 	r = min(pa - (char *) a, pb - pa);
154 	vecswap(a, pb - r, r);
155 	r = min((size_t)(pd - pc), pn - pd - es);
156 	vecswap(pb, pn - r, r);
157 	if ((r = pb - pa) > es) {
158                 void *_l = a, *_r = ((unsigned char*)a)+r-1;
159                 if (!((lrange < _l && rrange < _l) ||
160                     (lrange > _r && rrange > _r)))
161 		    _pqsort(a, r / es, es, cmp, lrange, rrange);
162         }
163 	if ((r = pd - pc) > es) {
164                 void *_l, *_r;
165 
166 		/* Iterate rather than recurse to save stack space */
167 		a = pn - r;
168 		n = r / es;
169 
170                 _l = a;
171                 _r = ((unsigned char*)a)+r-1;
172                 if (!((lrange < _l && rrange < _l) ||
173                     (lrange > _r && rrange > _r)))
174 		    goto loop;
175 	}
176 /*		qsort(pn - r, r / es, es, cmp);*/
177 }
178 
179 void
pqsort(void * a,size_t n,size_t es,int (* cmp)(const void *,const void *),size_t lrange,size_t rrange)180 pqsort(void *a, size_t n, size_t es,
181     int (*cmp) (const void *, const void *), size_t lrange, size_t rrange)
182 {
183     _pqsort(a,n,es,cmp,((unsigned char*)a)+(lrange*es),
184                        ((unsigned char*)a)+((rrange+1)*es)-1);
185 }
186