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