/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 | 6.49k | static inline void zend_sort_2(void *a, void *b, compare_func_t cmp, swap_func_t swp) /* {{{ */ { |
24 | 6.49k | if (cmp(a, b) > 0) { |
25 | 4.52k | swp(a, b); |
26 | 4.52k | } |
27 | 6.49k | } |
28 | | /* }}} */ |
29 | | |
30 | 194k | static inline void zend_sort_3(void *a, void *b, void *c, compare_func_t cmp, swap_func_t swp) /* {{{ */ { |
31 | 194k | if (!(cmp(a, b) > 0)) { |
32 | 59.4k | if (!(cmp(b, c) > 0)) { |
33 | 45.8k | return; |
34 | 45.8k | } |
35 | 13.6k | swp(b, c); |
36 | 13.6k | if (cmp(a, b) > 0) { |
37 | 3.95k | swp(a, b); |
38 | 3.95k | } |
39 | 13.6k | return; |
40 | 59.4k | } |
41 | 134k | if (!(cmp(c, b) > 0)) { |
42 | 28.4k | swp(a, c); |
43 | 28.4k | return; |
44 | 28.4k | } |
45 | 106k | swp(a, b); |
46 | 106k | if (cmp(b, c) > 0) { |
47 | 45.1k | swp(b, c); |
48 | 45.1k | } |
49 | 106k | } |
50 | | /* }}} */ |
51 | | |
52 | 14.4k | static void zend_sort_4(void *a, void *b, void *c, void *d, compare_func_t cmp, swap_func_t swp) /* {{{ */ { |
53 | 14.4k | zend_sort_3(a, b, c, cmp, swp); |
54 | 14.4k | if (cmp(c, d) > 0) { |
55 | 10.7k | swp(c, d); |
56 | 10.7k | if (cmp(b, c) > 0) { |
57 | 6.52k | swp(b, c); |
58 | 6.52k | if (cmp(a, b) > 0) { |
59 | 5.14k | swp(a, b); |
60 | 5.14k | } |
61 | 6.52k | } |
62 | 10.7k | } |
63 | 14.4k | } |
64 | | /* }}} */ |
65 | | |
66 | 10.8k | static void zend_sort_5(void *a, void *b, void *c, void *d, void *e, compare_func_t cmp, swap_func_t swp) /* {{{ */ { |
67 | 10.8k | zend_sort_4(a, b, c, d, cmp, swp); |
68 | 10.8k | if (cmp(d, e) > 0) { |
69 | 9.50k | swp(d, e); |
70 | 9.50k | if (cmp(c, d) > 0) { |
71 | 8.47k | swp(c, d); |
72 | 8.47k | if (cmp(b, c) > 0) { |
73 | 5.26k | swp(b, c); |
74 | 5.26k | if (cmp(a, b) > 0) { |
75 | 944 | swp(a, b); |
76 | 944 | } |
77 | 5.26k | } |
78 | 8.47k | } |
79 | 9.50k | } |
80 | 10.8k | } |
81 | | /* }}} */ |
82 | | |
83 | 190k | ZEND_API void zend_insert_sort(void *base, size_t nmemb, size_t siz, compare_func_t cmp, swap_func_t swp) /* {{{ */{ |
84 | 190k | switch (nmemb) { |
85 | 0 | case 0: |
86 | 6.56k | case 1: |
87 | 6.56k | break; |
88 | 6.49k | case 2: |
89 | 6.49k | zend_sort_2(base, (char *)base + siz, cmp, swp); |
90 | 6.49k | break; |
91 | 15.5k | case 3: |
92 | 15.5k | zend_sort_3(base, (char *)base + siz, (char *)base + siz + siz, cmp, swp); |
93 | 15.5k | break; |
94 | 3.58k | case 4: |
95 | 3.58k | { |
96 | 3.58k | size_t siz2 = siz + siz; |
97 | 3.58k | zend_sort_4(base, (char *)base + siz, (char *)base + siz2, (char *)base + siz + siz2, cmp, swp); |
98 | 3.58k | } |
99 | 3.58k | break; |
100 | 10.0k | case 5: |
101 | 10.0k | { |
102 | 10.0k | size_t siz2 = siz + siz; |
103 | 10.0k | zend_sort_5(base, (char *)base + siz, (char *)base + siz2, (char *)base + siz + siz2, (char *)base + siz2 + siz2, cmp, swp); |
104 | 10.0k | } |
105 | 10.0k | break; |
106 | 148k | default: |
107 | 148k | { |
108 | 148k | char *i, *j, *k; |
109 | 148k | char *start = (char *)base; |
110 | 148k | char *end = start + (nmemb * siz); |
111 | 148k | size_t siz2= siz + siz; |
112 | 148k | char *sentry = start + (6 * siz); |
113 | 889k | for (i = start + siz; i < sentry; i += siz) { |
114 | 741k | j = i - siz; |
115 | 741k | if (!(cmp(j, i) > 0)) { |
116 | 279k | continue; |
117 | 279k | } |
118 | 922k | while (j != start) { |
119 | 780k | j -= siz; |
120 | 780k | if (!(cmp(j, i) > 0)) { |
121 | 319k | j += siz; |
122 | 319k | break; |
123 | 319k | } |
124 | 780k | } |
125 | 1.38M | for (k = i; k > j; k -= siz) { |
126 | 922k | swp(k, k - siz); |
127 | 922k | } |
128 | 461k | } |
129 | 966k | for (i = sentry; i < end; i += siz) { |
130 | 818k | j = i - siz; |
131 | 818k | if (!(cmp(j, i) > 0)) { |
132 | 156k | continue; |
133 | 156k | } |
134 | 1.22M | do { |
135 | 1.22M | j -= siz2; |
136 | 1.22M | if (!(cmp(j, i) > 0)) { |
137 | 619k | j += siz; |
138 | 619k | if (!(cmp(j, i) > 0)) { |
139 | 389k | j += siz; |
140 | 389k | } |
141 | 619k | break; |
142 | 619k | } |
143 | 604k | if (j == start) { |
144 | 19.6k | break; |
145 | 19.6k | } |
146 | 584k | if (j == start + siz) { |
147 | 23.1k | j -= siz; |
148 | 23.1k | if (cmp(i, j) > 0) { |
149 | 9.12k | j += siz; |
150 | 9.12k | } |
151 | 23.1k | break; |
152 | 23.1k | } |
153 | 584k | } while (1); |
154 | 2.77M | for (k = i; k > j; k -= siz) { |
155 | 2.11M | swp(k, k - siz); |
156 | 2.11M | } |
157 | 661k | } |
158 | 148k | } |
159 | 148k | break; |
160 | 190k | } |
161 | 190k | } |
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 | 190k | { |
249 | 355k | while (1) { |
250 | 355k | if (nmemb <= 16) { |
251 | 190k | zend_insert_sort(base, nmemb, siz, cmp, swp); |
252 | 190k | return; |
253 | 190k | } else { |
254 | 165k | char *i, *j; |
255 | 165k | char *start = (char *)base; |
256 | 165k | char *end = start + (nmemb * siz); |
257 | 165k | size_t offset = (nmemb >> Z_L(1)); |
258 | 165k | char *pivot = start + (offset * siz); |
259 | | |
260 | 165k | if ((nmemb >> Z_L(10))) { |
261 | 844 | size_t delta = (offset >> Z_L(1)) * siz; |
262 | 844 | zend_sort_5(start, start + delta, pivot, pivot + delta, end - siz, cmp, swp); |
263 | 164k | } else { |
264 | 164k | zend_sort_3(start, pivot, end - siz, cmp, swp); |
265 | 164k | } |
266 | 165k | swp(start + siz, pivot); |
267 | 165k | pivot = start + siz; |
268 | 165k | i = pivot + siz; |
269 | 165k | j = end - siz; |
270 | 689k | while (1) { |
271 | 6.57M | while (cmp(pivot, i) > 0) { |
272 | 5.97M | i += siz; |
273 | 5.97M | if (UNEXPECTED(i == j)) { |
274 | 87.0k | goto done; |
275 | 87.0k | } |
276 | 5.97M | } |
277 | 602k | j -= siz; |
278 | 602k | if (UNEXPECTED(j == i)) { |
279 | 17.5k | goto done; |
280 | 17.5k | } |
281 | 3.94M | while (cmp(j, pivot) > 0) { |
282 | 3.38M | j -= siz; |
283 | 3.38M | if (UNEXPECTED(j == i)) { |
284 | 32.4k | goto done; |
285 | 32.4k | } |
286 | 3.38M | } |
287 | 552k | swp(i, j); |
288 | 552k | i += siz; |
289 | 552k | if (UNEXPECTED(i == j)) { |
290 | 28.2k | goto done; |
291 | 28.2k | } |
292 | 552k | } |
293 | 165k | done: |
294 | 165k | swp(pivot, i - siz); |
295 | 165k | if ((i - siz) - start < end - i) { |
296 | 58.6k | zend_sort(start, (i - start)/siz - 1, siz, cmp, swp); |
297 | 58.6k | base = i; |
298 | 58.6k | nmemb = (end - i)/siz; |
299 | 106k | } else { |
300 | 106k | zend_sort(i, (end - i)/siz, siz, cmp, swp); |
301 | 106k | nmemb = (i - start)/siz - 1; |
302 | 106k | } |
303 | 165k | } |
304 | 355k | } |
305 | 190k | } |
306 | | /* }}} */ |