blob: 26ebe864c61584364d8c0737640765188b0d983e [file] [log] [blame]
Vojtech Fried3e031b72012-08-24 16:52:44 +08001/*
2 * taken from https://github.com/swenson/sort
3 * Kept as is for the moment to be able to apply upstream patches for that
4 * code, currently used only to speed up XPath node sorting, see xpath.c
5 */
6
7/*
8 * All code in this header, unless otherwise specified, is hereby licensed under the MIT Public License:
9
10Copyright (c) 2010 Christopher Swenson
11
12Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17*/
18
19#include <stdlib.h>
20#include <stdio.h>
21#include <string.h>
Rob Richards236ea1e2012-08-27 11:56:07 -040022#ifdef HAVE_STDINT_H
Vojtech Fried3e031b72012-08-24 16:52:44 +080023#include <stdint.h>
Rob Richards236ea1e2012-08-27 11:56:07 -040024#else
25#ifdef HAVE_INTTYPES_H
26#include <inttypes.h>
27#elif defined(WIN32)
28typedef __int64 int64_t;
29typedef unsigned __int64 uint64_t;
30#endif
31#endif
Vojtech Fried3e031b72012-08-24 16:52:44 +080032
33#ifndef MAX
34#define MAX(x,y) (((x) > (y) ? (x) : (y)))
35#endif
36#ifndef MIN
37#define MIN(x,y) (((x) < (y) ? (x) : (y)))
38#endif
39
40int compute_minrun(uint64_t);
41
42#ifndef CLZ
43#ifdef __GNUC__
44#define CLZ __builtin_clzll
45#else
46
47int clzll(uint64_t);
48
49/* adapted from Hacker's Delight */
50int clzll(uint64_t x) /* {{{ */
51{
52 int n;
53
54 if (x == 0) return(64);
55 n = 0;
56 if (x <= 0x00000000FFFFFFFFL) {n = n + 32; x = x << 32;}
57 if (x <= 0x0000FFFFFFFFFFFFL) {n = n + 16; x = x << 16;}
58 if (x <= 0x00FFFFFFFFFFFFFFL) {n = n + 8; x = x << 8;}
59 if (x <= 0x0FFFFFFFFFFFFFFFL) {n = n + 4; x = x << 4;}
60 if (x <= 0x3FFFFFFFFFFFFFFFL) {n = n + 2; x = x << 2;}
61 if (x <= 0x7FFFFFFFFFFFFFFFL) {n = n + 1;}
62 return n;
63}
64/* }}} */
65
66#define CLZ clzll
67#endif
68#endif
69
70int compute_minrun(const uint64_t size) /* {{{ */
71{
72 const int top_bit = 64 - CLZ(size);
73 const int shift = MAX(top_bit, 6) - 6;
74 const int minrun = size >> shift;
75 const uint64_t mask = (1ULL << shift) - 1;
76 if (mask & size) return minrun + 1;
77 return minrun;
78}
79/* }}} */
80
81#ifndef SORT_NAME
82#error "Must declare SORT_NAME"
83#endif
84
85#ifndef SORT_TYPE
86#error "Must declare SORT_TYPE"
87#endif
88
89#ifndef SORT_CMP
90#define SORT_CMP(x, y) ((x) < (y) ? -1 : ((x) == (y) ? 0 : 1))
91#endif
92
93
94#define SORT_SWAP(x,y) {SORT_TYPE __SORT_SWAP_t = (x); (x) = (y); (y) = __SORT_SWAP_t;}
95
96#define SORT_CONCAT(x, y) x ## _ ## y
97#define SORT_MAKE_STR1(x, y) SORT_CONCAT(x,y)
98#define SORT_MAKE_STR(x) SORT_MAKE_STR1(SORT_NAME,x)
99
100#define BINARY_INSERTION_FIND SORT_MAKE_STR(binary_insertion_find)
101#define BINARY_INSERTION_SORT_START SORT_MAKE_STR(binary_insertion_sort_start)
102#define BINARY_INSERTION_SORT SORT_MAKE_STR(binary_insertion_sort)
103#define REVERSE_ELEMENTS SORT_MAKE_STR(reverse_elements)
104#define COUNT_RUN SORT_MAKE_STR(count_run)
105#define CHECK_INVARIANT SORT_MAKE_STR(check_invariant)
106#define TIM_SORT SORT_MAKE_STR(tim_sort)
107#define TIM_SORT_RESIZE SORT_MAKE_STR(tim_sort_resize)
108#define TIM_SORT_MERGE SORT_MAKE_STR(tim_sort_merge)
109#define TIM_SORT_COLLAPSE SORT_MAKE_STR(tim_sort_collapse)
110
111#define TIM_SORT_RUN_T SORT_MAKE_STR(tim_sort_run_t)
112#define TEMP_STORAGE_T SORT_MAKE_STR(temp_storage_t)
113
114typedef struct {
115 int64_t start;
116 int64_t length;
117} TIM_SORT_RUN_T;
118
119void BINARY_INSERTION_SORT(SORT_TYPE *dst, const size_t size);
120void TIM_SORT(SORT_TYPE *dst, const size_t size);
121
122/* Function used to do a binary search for binary insertion sort */
123static int64_t BINARY_INSERTION_FIND(SORT_TYPE *dst, const SORT_TYPE x, const size_t size)
124{
125 int64_t l, c, r;
126 SORT_TYPE lx;
127 SORT_TYPE cx;
128 l = 0;
129 r = size - 1;
130 c = r >> 1;
131 lx = dst[l];
132
133 /* check for beginning conditions */
134 if (SORT_CMP(x, lx) < 0)
135 return 0;
136 else if (SORT_CMP(x, lx) == 0)
137 {
138 int64_t i = 1;
139 while (SORT_CMP(x, dst[i]) == 0) i++;
140 return i;
141 }
142
143 cx = dst[c];
144 while (1)
145 {
146 const int val = SORT_CMP(x, cx);
147 if (val < 0)
148 {
149 if (c - l <= 1) return c;
150 r = c;
151 }
152 else if (val > 0)
153 {
154 if (r - c <= 1) return c + 1;
155 l = c;
156 lx = cx;
157 }
158 else
159 {
160 do
161 {
162 cx = dst[++c];
163 } while (SORT_CMP(x, cx) == 0);
164 return c;
165 }
166 c = l + ((r - l) >> 1);
167 cx = dst[c];
168 }
169}
170
171/* Binary insertion sort, but knowing that the first "start" entries are sorted. Used in timsort. */
172static void BINARY_INSERTION_SORT_START(SORT_TYPE *dst, const size_t start, const size_t size)
173{
174 int64_t i;
175 for (i = start; i < size; i++)
176 {
177 int64_t j;
178 SORT_TYPE x;
179 int64_t location;
180 /* If this entry is already correct, just move along */
181 if (SORT_CMP(dst[i - 1], dst[i]) <= 0) continue;
182
183 /* Else we need to find the right place, shift everything over, and squeeze in */
184 x = dst[i];
185 location = BINARY_INSERTION_FIND(dst, x, i);
186 for (j = i - 1; j >= location; j--)
187 {
188 dst[j + 1] = dst[j];
189 }
190 dst[location] = x;
191 }
192}
193
194/* Binary insertion sort */
195void BINARY_INSERTION_SORT(SORT_TYPE *dst, const size_t size)
196{
197 BINARY_INSERTION_SORT_START(dst, 1, size);
198}
199
200/* timsort implementation, based on timsort.txt */
201
202static void REVERSE_ELEMENTS(SORT_TYPE *dst, int64_t start, int64_t end)
203{
204 while (1)
205 {
206 if (start >= end) return;
207 SORT_SWAP(dst[start], dst[end]);
208 start++;
209 end--;
210 }
211}
212
213static int64_t COUNT_RUN(SORT_TYPE *dst, const int64_t start, const size_t size)
214{
215 int64_t curr;
216 if (size - start == 1) return 1;
217 if (start >= size - 2)
218 {
219 if (SORT_CMP(dst[size - 2], dst[size - 1]) > 0)
220 SORT_SWAP(dst[size - 2], dst[size - 1]);
221 return 2;
222 }
223
224 curr = start + 2;
225
226 if (SORT_CMP(dst[start], dst[start + 1]) <= 0)
227 {
228 /* increasing run */
229 while (1)
230 {
231 if (curr == size - 1) break;
232 if (SORT_CMP(dst[curr - 1], dst[curr]) > 0) break;
233 curr++;
234 }
235 return curr - start;
236 }
237 else
238 {
239 /* decreasing run */
240 while (1)
241 {
242 if (curr == size - 1) break;
243 if (SORT_CMP(dst[curr - 1], dst[curr]) <= 0) break;
244 curr++;
245 }
246 /* reverse in-place */
247 REVERSE_ELEMENTS(dst, start, curr - 1);
248 return curr - start;
249 }
250}
251
252#define PUSH_NEXT() do {\
253len = COUNT_RUN(dst, curr, size);\
254run = minrun;\
255if (run < minrun) run = minrun;\
256if (run > size - curr) run = size - curr;\
257if (run > len)\
258{\
259 BINARY_INSERTION_SORT_START(&dst[curr], len, run);\
260 len = run;\
261}\
262{\
263run_stack[stack_curr].start = curr;\
264run_stack[stack_curr].length = len;\
265stack_curr++;\
266}\
267curr += len;\
268if (curr == size)\
269{\
270 /* finish up */ \
271 while (stack_curr > 1) \
272 { \
273 TIM_SORT_MERGE(dst, run_stack, stack_curr, store); \
274 run_stack[stack_curr - 2].length += run_stack[stack_curr - 1].length; \
275 stack_curr--; \
276 } \
277 if (store->storage != NULL)\
278 {\
279 free(store->storage);\
280 store->storage = NULL;\
281 }\
282 return;\
283}\
284}\
285while (0)
286
287static int CHECK_INVARIANT(TIM_SORT_RUN_T *stack, const int stack_curr)
288{
289 int64_t A, B, C;
290 if (stack_curr < 2) return 1;
291 if (stack_curr == 2)
292 {
293 const int64_t A1 = stack[stack_curr - 2].length;
294 const int64_t B1 = stack[stack_curr - 1].length;
295 if (A1 <= B1) return 0;
296 return 1;
297 }
298 A = stack[stack_curr - 3].length;
299 B = stack[stack_curr - 2].length;
300 C = stack[stack_curr - 1].length;
301 if ((A <= B + C) || (B <= C)) return 0;
302 return 1;
303}
304
305typedef struct {
306 size_t alloc;
307 SORT_TYPE *storage;
308} TEMP_STORAGE_T;
309
310
311static void TIM_SORT_RESIZE(TEMP_STORAGE_T *store, const size_t new_size)
312{
313 if (store->alloc < new_size)
314 {
315 SORT_TYPE *tempstore = (SORT_TYPE *)realloc(store->storage, new_size * sizeof(SORT_TYPE));
316 if (tempstore == NULL)
317 {
318 fprintf(stderr, "Error allocating temporary storage for tim sort: need %lu bytes", sizeof(SORT_TYPE) * new_size);
319 exit(1);
320 }
321 store->storage = tempstore;
322 store->alloc = new_size;
323 }
324}
325
326static void TIM_SORT_MERGE(SORT_TYPE *dst, const TIM_SORT_RUN_T *stack, const int stack_curr, TEMP_STORAGE_T *store)
327{
328 const int64_t A = stack[stack_curr - 2].length;
329 const int64_t B = stack[stack_curr - 1].length;
330 const int64_t curr = stack[stack_curr - 2].start;
331 SORT_TYPE *storage;
332 int64_t i, j, k;
333
334 TIM_SORT_RESIZE(store, MIN(A, B));
335 storage = store->storage;
336
337 /* left merge */
338 if (A < B)
339 {
340 memcpy(storage, &dst[curr], A * sizeof(SORT_TYPE));
341 i = 0;
342 j = curr + A;
343
344 for (k = curr; k < curr + A + B; k++)
345 {
346 if ((i < A) && (j < curr + A + B))
347 {
348 if (SORT_CMP(storage[i], dst[j]) <= 0)
349 dst[k] = storage[i++];
350 else
351 dst[k] = dst[j++];
352 }
353 else if (i < A)
354 {
355 dst[k] = storage[i++];
356 }
357 else
358 dst[k] = dst[j++];
359 }
360 }
361 /* right merge */
362 else
363 {
364 memcpy(storage, &dst[curr + A], B * sizeof(SORT_TYPE));
365 i = B - 1;
366 j = curr + A - 1;
367
368 for (k = curr + A + B - 1; k >= curr; k--)
369 {
370 if ((i >= 0) && (j >= curr))
371 {
372 if (SORT_CMP(dst[j], storage[i]) > 0)
373 dst[k] = dst[j--];
374 else
375 dst[k] = storage[i--];
376 }
377 else if (i >= 0)
378 dst[k] = storage[i--];
379 else
380 dst[k] = dst[j--];
381 }
382 }
383}
384
385static int TIM_SORT_COLLAPSE(SORT_TYPE *dst, TIM_SORT_RUN_T *stack, int stack_curr, TEMP_STORAGE_T *store, const size_t size)
386{
387 while (1)
388 {
389 int64_t A, B, C;
390 /* if the stack only has one thing on it, we are done with the collapse */
391 if (stack_curr <= 1) break;
392 /* if this is the last merge, just do it */
393 if ((stack_curr == 2) && (stack[0].length + stack[1].length == size))
394 {
395 TIM_SORT_MERGE(dst, stack, stack_curr, store);
396 stack[0].length += stack[1].length;
397 stack_curr--;
398 break;
399 }
400 /* check if the invariant is off for a stack of 2 elements */
401 else if ((stack_curr == 2) && (stack[0].length <= stack[1].length))
402 {
403 TIM_SORT_MERGE(dst, stack, stack_curr, store);
404 stack[0].length += stack[1].length;
405 stack_curr--;
406 break;
407 }
408 else if (stack_curr == 2)
409 break;
410
411 A = stack[stack_curr - 3].length;
412 B = stack[stack_curr - 2].length;
413 C = stack[stack_curr - 1].length;
414
415 /* check first invariant */
416 if (A <= B + C)
417 {
418 if (A < C)
419 {
420 TIM_SORT_MERGE(dst, stack, stack_curr - 1, store);
421 stack[stack_curr - 3].length += stack[stack_curr - 2].length;
422 stack[stack_curr - 2] = stack[stack_curr - 1];
423 stack_curr--;
424 }
425 else
426 {
427 TIM_SORT_MERGE(dst, stack, stack_curr, store);
428 stack[stack_curr - 2].length += stack[stack_curr - 1].length;
429 stack_curr--;
430 }
431 }
432 /* check second invariant */
433 else if (B <= C)
434 {
435 TIM_SORT_MERGE(dst, stack, stack_curr, store);
436 stack[stack_curr - 2].length += stack[stack_curr - 1].length;
437 stack_curr--;
438 }
439 else
440 break;
441 }
442 return stack_curr;
443}
444
445void TIM_SORT(SORT_TYPE *dst, const size_t size)
446{
447 int minrun;
448 TEMP_STORAGE_T _store, *store;
449 TIM_SORT_RUN_T run_stack[128];
450 int stack_curr = 0;
451 int64_t len, run;
452 int64_t curr = 0;
453
454 if (size < 64)
455 {
456 BINARY_INSERTION_SORT(dst, size);
457 return;
458 }
459
460 /* compute the minimum run length */
461 minrun = compute_minrun(size);
462
463 /* temporary storage for merges */
464 store = &_store;
465 store->alloc = 0;
466 store->storage = NULL;
467
468 PUSH_NEXT();
469 PUSH_NEXT();
470 PUSH_NEXT();
471
472 while (1)
473 {
474 if (!CHECK_INVARIANT(run_stack, stack_curr))
475 {
476 stack_curr = TIM_SORT_COLLAPSE(dst, run_stack, stack_curr, store, size);
477 continue;
478 }
479 PUSH_NEXT();
480 }
481}
482
483#undef SORT_CONCAT
484#undef SORT_MAKE_STR1
485#undef SORT_MAKE_STR
486#undef SORT_NAME
487#undef SORT_TYPE
488#undef SORT_CMP
489#undef TEMP_STORAGE_T
490#undef TIM_SORT_RUN_T
491#undef PUSH_NEXT
492#undef SORT_SWAP
493#undef SORT_CONCAT
494#undef SORT_MAKE_STR1
495#undef SORT_MAKE_STR
496#undef BINARY_INSERTION_FIND
497#undef BINARY_INSERTION_SORT_START
498#undef BINARY_INSERTION_SORT
499#undef REVERSE_ELEMENTS
500#undef COUNT_RUN
501#undef TIM_SORT
502#undef TIM_SORT_RESIZE
503#undef TIM_SORT_COLLAPSE
504#undef TIM_SORT_RUN_T
505#undef TEMP_STORAGE_T