/src/php-src/Zend/zend_sort.c
Line | Count | Source |
1 | | /* |
2 | | +----------------------------------------------------------------------+ |
3 | | | Zend Engine | |
4 | | +----------------------------------------------------------------------+ |
5 | | | Copyright © Zend Technologies Ltd., a subsidiary company of | |
6 | | | Perforce Software, Inc., and Contributors. | |
7 | | +----------------------------------------------------------------------+ |
8 | | | This source file is subject to the Modified BSD License that is | |
9 | | | bundled with this package in the file LICENSE, and is available | |
10 | | | through the World Wide Web at <https://www.php.net/license/>. | |
11 | | | | |
12 | | | SPDX-License-Identifier: BSD-3-Clause | |
13 | | +----------------------------------------------------------------------+ |
14 | | | Authors: Xinchen Hui <laruence@php.net> | |
15 | | | Sterling Hughes <sterling@php.net> | |
16 | | +----------------------------------------------------------------------+ |
17 | | */ |
18 | | |
19 | | #include "zend.h" |
20 | | #include "zend_sort.h" |
21 | | #include <limits.h> |
22 | | |
23 | 5.68k | static inline void zend_sort_2(void *a, void *b, compare_func_t cmp, swap_func_t swp) /* {{{ */ { |
24 | 5.68k | if (cmp(a, b) > 0) { |
25 | 3.92k | swp(a, b); |
26 | 3.92k | } |
27 | 5.68k | } |
28 | | /* }}} */ |
29 | | |
30 | 179k | static inline void zend_sort_3(void *a, void *b, void *c, compare_func_t cmp, swap_func_t swp) /* {{{ */ { |
31 | 179k | if (!(cmp(a, b) > 0)) { |
32 | 55.8k | if (!(cmp(b, c) > 0)) { |
33 | 42.1k | return; |
34 | 42.1k | } |
35 | 13.6k | swp(b, c); |
36 | 13.6k | if (cmp(a, b) > 0) { |
37 | 3.84k | swp(a, b); |
38 | 3.84k | } |
39 | 13.6k | return; |
40 | 55.8k | } |
41 | 123k | if (!(cmp(c, b) > 0)) { |
42 | 22.2k | swp(a, c); |
43 | 22.2k | return; |
44 | 22.2k | } |
45 | 101k | swp(a, b); |
46 | 101k | if (cmp(b, c) > 0) { |
47 | 45.5k | swp(b, c); |
48 | 45.5k | } |
49 | 101k | } |
50 | | /* }}} */ |
51 | | |
52 | 16.3k | static void zend_sort_4(void *a, void *b, void *c, void *d, compare_func_t cmp, swap_func_t swp) /* {{{ */ { |
53 | 16.3k | zend_sort_3(a, b, c, cmp, swp); |
54 | 16.3k | if (cmp(c, d) > 0) { |
55 | 12.0k | swp(c, d); |
56 | 12.0k | if (cmp(b, c) > 0) { |
57 | 7.39k | swp(b, c); |
58 | 7.39k | if (cmp(a, b) > 0) { |
59 | 5.80k | swp(a, b); |
60 | 5.80k | } |
61 | 7.39k | } |
62 | 12.0k | } |
63 | 16.3k | } |
64 | | /* }}} */ |
65 | | |
66 | 11.7k | static void zend_sort_5(void *a, void *b, void *c, void *d, void *e, compare_func_t cmp, swap_func_t swp) /* {{{ */ { |
67 | 11.7k | zend_sort_4(a, b, c, d, cmp, swp); |
68 | 11.7k | if (cmp(d, e) > 0) { |
69 | 10.2k | swp(d, e); |
70 | 10.2k | if (cmp(c, d) > 0) { |
71 | 9.21k | swp(c, d); |
72 | 9.21k | if (cmp(b, c) > 0) { |
73 | 5.69k | swp(b, c); |
74 | 5.69k | if (cmp(a, b) > 0) { |
75 | 765 | swp(a, b); |
76 | 765 | } |
77 | 5.69k | } |
78 | 9.21k | } |
79 | 10.2k | } |
80 | 11.7k | } |
81 | | /* }}} */ |
82 | | |
83 | 213k | ZEND_API void zend_insert_sort(void *base, size_t nmemb, size_t siz, compare_func_t cmp, swap_func_t swp) /* {{{ */{ |
84 | 213k | switch (nmemb) { |
85 | 0 | case 0: |
86 | 7.51k | case 1: |
87 | 7.51k | break; |
88 | 5.68k | case 2: |
89 | 5.68k | zend_sort_2(base, (char *)base + siz, cmp, swp); |
90 | 5.68k | break; |
91 | 15.3k | case 3: |
92 | 15.3k | zend_sort_3(base, (char *)base + siz, (char *)base + siz + siz, cmp, swp); |
93 | 15.3k | break; |
94 | 4.60k | case 4: |
95 | 4.60k | { |
96 | 4.60k | size_t siz2 = siz + siz; |
97 | 4.60k | zend_sort_4(base, (char *)base + siz, (char *)base + siz2, (char *)base + siz + siz2, cmp, swp); |
98 | 4.60k | } |
99 | 4.60k | break; |
100 | 10.9k | case 5: |
101 | 10.9k | { |
102 | 10.9k | size_t siz2 = siz + siz; |
103 | 10.9k | zend_sort_5(base, (char *)base + siz, (char *)base + siz2, (char *)base + siz + siz2, (char *)base + siz2 + siz2, cmp, swp); |
104 | 10.9k | } |
105 | 10.9k | break; |
106 | 169k | default: |
107 | 169k | { |
108 | 169k | char *i, *j, *k; |
109 | 169k | char *start = (char *)base; |
110 | 169k | char *end = start + (nmemb * siz); |
111 | 169k | size_t siz2= siz + siz; |
112 | 169k | char *sentry = start + (6 * siz); |
113 | 1.01M | for (i = start + siz; i < sentry; i += siz) { |
114 | 846k | j = i - siz; |
115 | 846k | if (!(cmp(j, i) > 0)) { |
116 | 233k | continue; |
117 | 233k | } |
118 | 1.03M | while (j != start) { |
119 | 860k | j -= siz; |
120 | 860k | if (!(cmp(j, i) > 0)) { |
121 | 442k | j += siz; |
122 | 442k | break; |
123 | 442k | } |
124 | 860k | } |
125 | 1.64M | for (k = i; k > j; k -= siz) { |
126 | 1.03M | swp(k, k - siz); |
127 | 1.03M | } |
128 | 613k | } |
129 | 1.21M | for (i = sentry; i < end; i += siz) { |
130 | 1.04M | j = i - siz; |
131 | 1.04M | if (!(cmp(j, i) > 0)) { |
132 | 122k | continue; |
133 | 122k | } |
134 | 1.57M | do { |
135 | 1.57M | j -= siz2; |
136 | 1.57M | if (!(cmp(j, i) > 0)) { |
137 | 890k | j += siz; |
138 | 890k | if (!(cmp(j, i) > 0)) { |
139 | 612k | j += siz; |
140 | 612k | } |
141 | 890k | break; |
142 | 890k | } |
143 | 688k | if (j == start) { |
144 | 12.7k | break; |
145 | 12.7k | } |
146 | 676k | if (j == start + siz) { |
147 | 23.2k | j -= siz; |
148 | 23.2k | if (cmp(i, j) > 0) { |
149 | 9.42k | j += siz; |
150 | 9.42k | } |
151 | 23.2k | break; |
152 | 23.2k | } |
153 | 676k | } while (1); |
154 | 3.52M | for (k = i; k > j; k -= siz) { |
155 | 2.59M | swp(k, k - siz); |
156 | 2.59M | } |
157 | 926k | } |
158 | 169k | } |
159 | 169k | break; |
160 | 213k | } |
161 | 213k | } |
162 | | /* }}} */ |
163 | | |
164 | | /* {{{ ZEND_API void zend_sort(void *base, size_t nmemb, size_t siz, compare_func_t cmp, swap_func_t swp) |
165 | | * |
166 | | * Derived from LLVM's libc++ implementation of std::sort. |
167 | | * |
168 | | * =========================================================================== |
169 | | * libc++ License |
170 | | * =========================================================================== |
171 | | * |
172 | | * The libc++ library is dual licensed under both the University of Illinois |
173 | | * "BSD-Like" license and the MIT license. As a user of this code you may |
174 | | * choose to use it under either license. As a contributor, you agree to allow |
175 | | * your code to be used under both. |
176 | | * |
177 | | * Full text of the relevant licenses is included below. |
178 | | * |
179 | | * =========================================================================== |
180 | | * |
181 | | * University of Illinois/NCSA |
182 | | * Open Source License |
183 | | * |
184 | | * Copyright (c) 2009-2012 by the contributors listed at |
185 | | * http://llvm.org/svn/llvm-project/libcxx/trunk/CREDITS.TXT |
186 | | * |
187 | | * All rights reserved. |
188 | | * |
189 | | * Developed by: |
190 | | * |
191 | | * LLVM Team |
192 | | * |
193 | | * University of Illinois at Urbana-Champaign |
194 | | * |
195 | | * http://llvm.org |
196 | | * |
197 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
198 | | * of this software and associated documentation files (the "Software"), to |
199 | | * deal with the Software without restriction, including without limitation the |
200 | | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
201 | | * sell copies of the Software, and to permit persons to whom the Software is |
202 | | * furnished to do so, subject to the following conditions: |
203 | | * |
204 | | * * Redistributions of source code must retain the above copyright notice, |
205 | | * this list of conditions and the following disclaimers. |
206 | | * |
207 | | * * Redistributions in binary form must reproduce the above copyright |
208 | | * notice, this list of conditions and the following disclaimers in the |
209 | | * documentation and/or other materials provided with the distribution. |
210 | | * |
211 | | * * Neither the names of the LLVM Team, University of Illinois at |
212 | | * Urbana-Champaign, nor the names of its contributors may be used to |
213 | | * endorse or promote products derived from this Software without |
214 | | * specific prior written permission. |
215 | | * |
216 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
217 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
218 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
219 | | * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
220 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
221 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
222 | | * WITH THE SOFTWARE. |
223 | | * |
224 | | * =========================================================================== |
225 | | * |
226 | | * Copyright (c) 2009-2012 by the contributors listed at |
227 | | * http://llvm.org/svn/llvm-project/libcxx/trunk/CREDITS.TXT |
228 | | * |
229 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
230 | | * of this software and associated documentation files (the "Software"), to |
231 | | * deal in the Software without restriction, including without limitation the |
232 | | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
233 | | * sell copies of the Software, and to permit persons to whom the Software is |
234 | | * furnished to do so, subject to the following conditions: |
235 | | * |
236 | | * The above copyright notice and this permission notice shall be included in |
237 | | * all copies or substantial portions of the Software. |
238 | | * |
239 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
240 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
241 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
242 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
243 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
244 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
245 | | * IN THE SOFTWARE. |
246 | | */ |
247 | | ZEND_API void zend_sort(void *base, size_t nmemb, size_t siz, compare_func_t cmp, swap_func_t swp) |
248 | 213k | { |
249 | 362k | while (1) { |
250 | 362k | if (nmemb <= 16) { |
251 | 213k | zend_insert_sort(base, nmemb, siz, cmp, swp); |
252 | 213k | return; |
253 | 213k | } else { |
254 | 148k | char *i, *j; |
255 | 148k | char *start = (char *)base; |
256 | 148k | char *end = start + (nmemb * siz); |
257 | 148k | size_t offset = (nmemb >> Z_L(1)); |
258 | 148k | char *pivot = start + (offset * siz); |
259 | | |
260 | 148k | if ((nmemb >> Z_L(10))) { |
261 | 838 | size_t delta = (offset >> Z_L(1)) * siz; |
262 | 838 | zend_sort_5(start, start + delta, pivot, pivot + delta, end - siz, cmp, swp); |
263 | 148k | } else { |
264 | 148k | zend_sort_3(start, pivot, end - siz, cmp, swp); |
265 | 148k | } |
266 | 148k | swp(start + siz, pivot); |
267 | 148k | pivot = start + siz; |
268 | 148k | i = pivot + siz; |
269 | 148k | j = end - siz; |
270 | 643k | while (1) { |
271 | 6.26M | while (cmp(pivot, i) > 0) { |
272 | 5.70M | i += siz; |
273 | 5.70M | if (UNEXPECTED(i == j)) { |
274 | 82.4k | goto done; |
275 | 82.4k | } |
276 | 5.70M | } |
277 | 560k | j -= siz; |
278 | 560k | if (UNEXPECTED(j == i)) { |
279 | 17.5k | goto done; |
280 | 17.5k | } |
281 | 3.61M | while (cmp(j, pivot) > 0) { |
282 | 3.09M | j -= siz; |
283 | 3.09M | if (UNEXPECTED(j == i)) { |
284 | 27.1k | goto done; |
285 | 27.1k | } |
286 | 3.09M | } |
287 | 516k | swp(i, j); |
288 | 516k | i += siz; |
289 | 516k | if (UNEXPECTED(i == j)) { |
290 | 21.7k | goto done; |
291 | 21.7k | } |
292 | 516k | } |
293 | 148k | done: |
294 | 148k | swp(pivot, i - siz); |
295 | 148k | if ((i - siz) - start < end - i) { |
296 | 51.8k | zend_sort(start, (i - start)/siz - 1, siz, cmp, swp); |
297 | 51.8k | base = i; |
298 | 51.8k | nmemb = (end - i)/siz; |
299 | 96.9k | } else { |
300 | 96.9k | zend_sort(i, (end - i)/siz, siz, cmp, swp); |
301 | 96.9k | nmemb = (i - start)/siz - 1; |
302 | 96.9k | } |
303 | 148k | } |
304 | 362k | } |
305 | 213k | } |
306 | | /* }}} */ |