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