/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 | 4.50k | static inline void zend_sort_2(void *a, void *b, compare_func_t cmp, swap_func_t swp) /* {{{ */ { |
24 | 4.50k | if (cmp(a, b) > 0) { |
25 | 3.03k | swp(a, b); |
26 | 3.03k | } |
27 | 4.50k | } |
28 | | /* }}} */ |
29 | | |
30 | 224k | static inline void zend_sort_3(void *a, void *b, void *c, compare_func_t cmp, swap_func_t swp) /* {{{ */ { |
31 | 224k | if (!(cmp(a, b) > 0)) { |
32 | 59.4k | if (!(cmp(b, c) > 0)) { |
33 | 33.0k | return; |
34 | 33.0k | } |
35 | 26.4k | swp(b, c); |
36 | 26.4k | if (cmp(a, b) > 0) { |
37 | 4.47k | swp(a, b); |
38 | 4.47k | } |
39 | 26.4k | return; |
40 | 59.4k | } |
41 | 165k | if (!(cmp(c, b) > 0)) { |
42 | 20.8k | swp(a, c); |
43 | 20.8k | return; |
44 | 20.8k | } |
45 | 144k | swp(a, b); |
46 | 144k | if (cmp(b, c) > 0) { |
47 | 74.2k | swp(b, c); |
48 | 74.2k | } |
49 | 144k | } |
50 | | /* }}} */ |
51 | | |
52 | 20.9k | static void zend_sort_4(void *a, void *b, void *c, void *d, compare_func_t cmp, swap_func_t swp) /* {{{ */ { |
53 | 20.9k | zend_sort_3(a, b, c, cmp, swp); |
54 | 20.9k | if (cmp(c, d) > 0) { |
55 | 13.1k | swp(c, d); |
56 | 13.1k | if (cmp(b, c) > 0) { |
57 | 3.60k | swp(b, c); |
58 | 3.60k | if (cmp(a, b) > 0) { |
59 | 2.01k | swp(a, b); |
60 | 2.01k | } |
61 | 3.60k | } |
62 | 13.1k | } |
63 | 20.9k | } |
64 | | /* }}} */ |
65 | | |
66 | 15.1k | static void zend_sort_5(void *a, void *b, void *c, void *d, void *e, compare_func_t cmp, swap_func_t swp) /* {{{ */ { |
67 | 15.1k | zend_sort_4(a, b, c, d, cmp, swp); |
68 | 15.1k | if (cmp(d, e) > 0) { |
69 | 12.8k | swp(d, e); |
70 | 12.8k | if (cmp(c, d) > 0) { |
71 | 12.0k | swp(c, d); |
72 | 12.0k | if (cmp(b, c) > 0) { |
73 | 1.58k | swp(b, c); |
74 | 1.58k | if (cmp(a, b) > 0) { |
75 | 817 | swp(a, b); |
76 | 817 | } |
77 | 1.58k | } |
78 | 12.0k | } |
79 | 12.8k | } |
80 | 15.1k | } |
81 | | /* }}} */ |
82 | | |
83 | 200k | ZEND_API void zend_insert_sort(void *base, size_t nmemb, size_t siz, compare_func_t cmp, swap_func_t swp) /* {{{ */{ |
84 | 200k | switch (nmemb) { |
85 | 0 | case 0: |
86 | 5.99k | case 1: |
87 | 5.99k | break; |
88 | 4.50k | case 2: |
89 | 4.50k | zend_sort_2(base, (char *)base + siz, cmp, swp); |
90 | 4.50k | break; |
91 | 40.2k | case 3: |
92 | 40.2k | zend_sort_3(base, (char *)base + siz, (char *)base + siz + siz, cmp, swp); |
93 | 40.2k | break; |
94 | 5.78k | case 4: |
95 | 5.78k | { |
96 | 5.78k | size_t siz2 = siz + siz; |
97 | 5.78k | zend_sort_4(base, (char *)base + siz, (char *)base + siz2, (char *)base + siz + siz2, cmp, swp); |
98 | 5.78k | } |
99 | 5.78k | break; |
100 | 14.0k | case 5: |
101 | 14.0k | { |
102 | 14.0k | size_t siz2 = siz + siz; |
103 | 14.0k | zend_sort_5(base, (char *)base + siz, (char *)base + siz2, (char *)base + siz + siz2, (char *)base + siz2 + siz2, cmp, swp); |
104 | 14.0k | } |
105 | 14.0k | break; |
106 | 130k | default: |
107 | 130k | { |
108 | 130k | char *i, *j, *k; |
109 | 130k | char *start = (char *)base; |
110 | 130k | char *end = start + (nmemb * siz); |
111 | 130k | size_t siz2= siz + siz; |
112 | 130k | char *sentry = start + (6 * siz); |
113 | 781k | for (i = start + siz; i < sentry; i += siz) { |
114 | 651k | j = i - siz; |
115 | 651k | if (!(cmp(j, i) > 0)) { |
116 | 180k | continue; |
117 | 180k | } |
118 | 913k | while (j != start) { |
119 | 763k | j -= siz; |
120 | 763k | if (!(cmp(j, i) > 0)) { |
121 | 321k | j += siz; |
122 | 321k | break; |
123 | 321k | } |
124 | 763k | } |
125 | 1.38M | for (k = i; k > j; k -= siz) { |
126 | 913k | swp(k, k - siz); |
127 | 913k | } |
128 | 471k | } |
129 | 896k | for (i = sentry; i < end; i += siz) { |
130 | 766k | j = i - siz; |
131 | 766k | if (!(cmp(j, i) > 0)) { |
132 | 66.7k | continue; |
133 | 66.7k | } |
134 | 1.30M | do { |
135 | 1.30M | j -= siz2; |
136 | 1.30M | if (!(cmp(j, i) > 0)) { |
137 | 665k | j += siz; |
138 | 665k | if (!(cmp(j, i) > 0)) { |
139 | 501k | j += siz; |
140 | 501k | } |
141 | 665k | break; |
142 | 665k | } |
143 | 643k | if (j == start) { |
144 | 6.83k | break; |
145 | 6.83k | } |
146 | 636k | if (j == start + siz) { |
147 | 27.7k | j -= siz; |
148 | 27.7k | if (cmp(i, j) > 0) { |
149 | 15.5k | j += siz; |
150 | 15.5k | } |
151 | 27.7k | break; |
152 | 27.7k | } |
153 | 636k | } while (1); |
154 | 2.86M | for (k = i; k > j; k -= siz) { |
155 | 2.16M | swp(k, k - siz); |
156 | 2.16M | } |
157 | 699k | } |
158 | 130k | } |
159 | 130k | break; |
160 | 200k | } |
161 | 200k | } |
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 | 200k | { |
249 | 365k | while (1) { |
250 | 365k | if (nmemb <= 16) { |
251 | 200k | zend_insert_sort(base, nmemb, siz, cmp, swp); |
252 | 200k | return; |
253 | 200k | } else { |
254 | 164k | char *i, *j; |
255 | 164k | char *start = (char *)base; |
256 | 164k | char *end = start + (nmemb * siz); |
257 | 164k | size_t offset = (nmemb >> Z_L(1)); |
258 | 164k | char *pivot = start + (offset * siz); |
259 | | |
260 | 164k | if ((nmemb >> Z_L(10))) { |
261 | 1.17k | size_t delta = (offset >> Z_L(1)) * siz; |
262 | 1.17k | zend_sort_5(start, start + delta, pivot, pivot + delta, end - siz, cmp, swp); |
263 | 163k | } else { |
264 | 163k | zend_sort_3(start, pivot, end - siz, cmp, swp); |
265 | 163k | } |
266 | 164k | swp(start + siz, pivot); |
267 | 164k | pivot = start + siz; |
268 | 164k | i = pivot + siz; |
269 | 164k | j = end - siz; |
270 | 751k | while (1) { |
271 | 8.86M | while (cmp(pivot, i) > 0) { |
272 | 8.22M | i += siz; |
273 | 8.22M | if (UNEXPECTED(i == j)) { |
274 | 106k | goto done; |
275 | 106k | } |
276 | 8.22M | } |
277 | 645k | j -= siz; |
278 | 645k | if (UNEXPECTED(j == i)) { |
279 | 34.9k | goto done; |
280 | 34.9k | } |
281 | 4.46M | while (cmp(j, pivot) > 0) { |
282 | 3.86M | j -= siz; |
283 | 3.86M | if (UNEXPECTED(j == i)) { |
284 | 13.2k | goto done; |
285 | 13.2k | } |
286 | 3.86M | } |
287 | 597k | swp(i, j); |
288 | 597k | i += siz; |
289 | 597k | if (UNEXPECTED(i == j)) { |
290 | 10.5k | goto done; |
291 | 10.5k | } |
292 | 597k | } |
293 | 164k | done: |
294 | 164k | swp(pivot, i - siz); |
295 | 164k | if ((i - siz) - start < end - i) { |
296 | 65.8k | zend_sort(start, (i - start)/siz - 1, siz, cmp, swp); |
297 | 65.8k | base = i; |
298 | 65.8k | nmemb = (end - i)/siz; |
299 | 99.0k | } else { |
300 | 99.0k | zend_sort(i, (end - i)/siz, siz, cmp, swp); |
301 | 99.0k | nmemb = (i - start)/siz - 1; |
302 | 99.0k | } |
303 | 164k | } |
304 | 365k | } |
305 | 200k | } |
306 | | /* }}} */ |