intl/icu/source/common/uarrsort.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /*
     2 *******************************************************************************
     3 *
     4 *   Copyright (C) 2003-2013, International Business Machines
     5 *   Corporation and others.  All Rights Reserved.
     6 *
     7 *******************************************************************************
     8 *   file name:  uarrsort.c
     9 *   encoding:   US-ASCII
    10 *   tab size:   8 (not used)
    11 *   indentation:4
    12 *
    13 *   created on: 2003aug04
    14 *   created by: Markus W. Scherer
    15 *
    16 *   Internal function for sorting arrays.
    17 */
    19 #include "unicode/utypes.h"
    20 #include "cmemory.h"
    21 #include "uarrsort.h"
    23 enum {
    24     /**
    25      * "from Knuth"
    26      *
    27      * A binary search over 8 items performs 4 comparisons:
    28      * log2(8)=3 to subdivide, +1 to check for equality.
    29      * A linear search over 8 items on average also performs 4 comparisons.
    30      */
    31     MIN_QSORT=9,
    32     STACK_ITEM_SIZE=200
    33 };
    35 /* UComparator convenience implementations ---------------------------------- */
    37 U_CAPI int32_t U_EXPORT2
    38 uprv_uint16Comparator(const void *context, const void *left, const void *right) {
    39     return (int32_t)*(const uint16_t *)left - (int32_t)*(const uint16_t *)right;
    40 }
    42 U_CAPI int32_t U_EXPORT2
    43 uprv_int32Comparator(const void *context, const void *left, const void *right) {
    44     return *(const int32_t *)left - *(const int32_t *)right;
    45 }
    47 U_CAPI int32_t U_EXPORT2
    48 uprv_uint32Comparator(const void *context, const void *left, const void *right) {
    49     uint32_t l=*(const uint32_t *)left, r=*(const uint32_t *)right;
    51     /* compare directly because (l-r) would overflow the int32_t result */
    52     if(l<r) {
    53         return -1;
    54     } else if(l==r) {
    55         return 0;
    56     } else /* l>r */ {
    57         return 1;
    58     }
    59 }
    61 /* Insertion sort using binary search --------------------------------------- */
    63 U_CAPI int32_t U_EXPORT2
    64 uprv_stableBinarySearch(char *array, int32_t limit, void *item, int32_t itemSize,
    65                         UComparator *cmp, const void *context) {
    66     int32_t start=0;
    67     UBool found=FALSE;
    69     /* Binary search until we get down to a tiny sub-array. */
    70     while((limit-start)>=MIN_QSORT) {
    71         int32_t i=(start+limit)/2;
    72         int32_t diff=cmp(context, item, array+i*itemSize);
    73         if(diff==0) {
    74             /*
    75              * Found the item. We look for the *last* occurrence of such
    76              * an item, for stable sorting.
    77              * If we knew that there will be only few equal items,
    78              * we could break now and enter the linear search.
    79              * However, if there are many equal items, then it should be
    80              * faster to continue with the binary search.
    81              * It seems likely that we either have all unique items
    82              * (where found will never become TRUE in the insertion sort)
    83              * or potentially many duplicates.
    84              */
    85             found=TRUE;
    86             start=i+1;
    87         } else if(diff<0) {
    88             limit=i;
    89         } else {
    90             start=i;
    91         }
    92     }
    94     /* Linear search over the remaining tiny sub-array. */
    95     while(start<limit) {
    96         int32_t diff=cmp(context, item, array+start*itemSize);
    97         if(diff==0) {
    98             found=TRUE;
    99         } else if(diff<0) {
   100             break;
   101         }
   102         ++start;
   103     }
   104     return found ? (start-1) : ~start;
   105 }
   107 static void
   108 doInsertionSort(char *array, int32_t length, int32_t itemSize,
   109                 UComparator *cmp, const void *context, void *pv) {
   110     int32_t j;
   112     for(j=1; j<length; ++j) {
   113         char *item=array+j*itemSize;
   114         int32_t insertionPoint=uprv_stableBinarySearch(array, j, item, itemSize, cmp, context);
   115         if(insertionPoint<0) {
   116             insertionPoint=~insertionPoint;
   117         } else {
   118             ++insertionPoint;  /* one past the last equal item */
   119         }
   120         if(insertionPoint<j) {
   121             char *dest=array+insertionPoint*itemSize;
   122             uprv_memcpy(pv, item, itemSize);  /* v=array[j] */
   123             uprv_memmove(dest+itemSize, dest, (j-insertionPoint)*itemSize);
   124             uprv_memcpy(dest, pv, itemSize);  /* array[insertionPoint]=v */
   125         }
   126     }
   127 }
   129 static void
   130 insertionSort(char *array, int32_t length, int32_t itemSize,
   131               UComparator *cmp, const void *context, UErrorCode *pErrorCode) {
   132     UAlignedMemory v[STACK_ITEM_SIZE/sizeof(UAlignedMemory)+1];
   133     void *pv;
   135     /* allocate an intermediate item variable (v) */
   136     if(itemSize<=STACK_ITEM_SIZE) {
   137         pv=v;
   138     } else {
   139         pv=uprv_malloc(itemSize);
   140         if(pv==NULL) {
   141             *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
   142             return;
   143         }
   144     }
   146     doInsertionSort(array, length, itemSize, cmp, context, pv);
   148     if(pv!=v) {
   149         uprv_free(pv);
   150     }
   151 }
   153 /* QuickSort ---------------------------------------------------------------- */
   155 /*
   156  * This implementation is semi-recursive:
   157  * It recurses for the smaller sub-array to shorten the recursion depth,
   158  * and loops for the larger sub-array.
   159  *
   160  * Loosely after QuickSort algorithms in
   161  * Niklaus Wirth
   162  * Algorithmen und Datenstrukturen mit Modula-2
   163  * B.G. Teubner Stuttgart
   164  * 4. Auflage 1986
   165  * ISBN 3-519-02260-5
   166  */
   167 static void
   168 subQuickSort(char *array, int32_t start, int32_t limit, int32_t itemSize,
   169              UComparator *cmp, const void *context,
   170              void *px, void *pw) {
   171     int32_t left, right;
   173     /* start and left are inclusive, limit and right are exclusive */
   174     do {
   175         if((start+MIN_QSORT)>=limit) {
   176             doInsertionSort(array+start*itemSize, limit-start, itemSize, cmp, context, px);
   177             break;
   178         }
   180         left=start;
   181         right=limit;
   183         /* x=array[middle] */
   184         uprv_memcpy(px, array+((start+limit)/2)*itemSize, itemSize);
   186         do {
   187             while(/* array[left]<x */
   188                   cmp(context, array+left*itemSize, px)<0
   189             ) {
   190                 ++left;
   191             }
   192             while(/* x<array[right-1] */
   193                   cmp(context, px, array+(right-1)*itemSize)<0
   194             ) {
   195                 --right;
   196             }
   198             /* swap array[left] and array[right-1] via w; ++left; --right */
   199             if(left<right) {
   200                 --right;
   202                 if(left<right) {
   203                     uprv_memcpy(pw, array+left*itemSize, itemSize);
   204                     uprv_memcpy(array+left*itemSize, array+right*itemSize, itemSize);
   205                     uprv_memcpy(array+right*itemSize, pw, itemSize);
   206                 }
   208                 ++left;
   209             }
   210         } while(left<right);
   212         /* sort sub-arrays */
   213         if((right-start)<(limit-left)) {
   214             /* sort [start..right[ */
   215             if(start<(right-1)) {
   216                 subQuickSort(array, start, right, itemSize, cmp, context, px, pw);
   217             }
   219             /* sort [left..limit[ */
   220             start=left;
   221         } else {
   222             /* sort [left..limit[ */
   223             if(left<(limit-1)) {
   224                 subQuickSort(array, left, limit, itemSize, cmp, context, px, pw);
   225             }
   227             /* sort [start..right[ */
   228             limit=right;
   229         }
   230     } while(start<(limit-1));
   231 }
   233 static void
   234 quickSort(char *array, int32_t length, int32_t itemSize,
   235             UComparator *cmp, const void *context, UErrorCode *pErrorCode) {
   236     UAlignedMemory xw[(2*STACK_ITEM_SIZE)/sizeof(UAlignedMemory)+1];
   237     void *p;
   239     /* allocate two intermediate item variables (x and w) */
   240     if(itemSize<=STACK_ITEM_SIZE) {
   241         p=xw;
   242     } else {
   243         p=uprv_malloc(2*itemSize);
   244         if(p==NULL) {
   245             *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
   246             return;
   247         }
   248     }
   250     subQuickSort(array, 0, length, itemSize,
   251                  cmp, context, p, (char *)p+itemSize);
   253     if(p!=xw) {
   254         uprv_free(p);
   255     }
   256 }
   258 /* uprv_sortArray() API ----------------------------------------------------- */
   260 /*
   261  * Check arguments, select an appropriate implementation,
   262  * cast the array to char * so that array+i*itemSize works.
   263  */
   264 U_CAPI void U_EXPORT2
   265 uprv_sortArray(void *array, int32_t length, int32_t itemSize,
   266                UComparator *cmp, const void *context,
   267                UBool sortStable, UErrorCode *pErrorCode) {
   268     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
   269         return;
   270     }
   271     if((length>0 && array==NULL) || length<0 || itemSize<=0 || cmp==NULL) {
   272         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
   273         return;
   274     }
   276     if(length<=1) {
   277         return;
   278     } else if(length<MIN_QSORT || sortStable) {
   279         insertionSort((char *)array, length, itemSize, cmp, context, pErrorCode);
   280     } else {
   281         quickSort((char *)array, length, itemSize, cmp, context, pErrorCode);
   282     }
   283 }

mercurial