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