12e5b6d6dSopenharmony_ci// © 2016 and later: Unicode, Inc. and others. 22e5b6d6dSopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html 32e5b6d6dSopenharmony_ci/* 42e5b6d6dSopenharmony_ci******************************************************************************* 52e5b6d6dSopenharmony_ci* 62e5b6d6dSopenharmony_ci* Copyright (C) 2003-2013, International Business Machines 72e5b6d6dSopenharmony_ci* Corporation and others. All Rights Reserved. 82e5b6d6dSopenharmony_ci* 92e5b6d6dSopenharmony_ci******************************************************************************* 102e5b6d6dSopenharmony_ci* file name: uarrsort.c 112e5b6d6dSopenharmony_ci* encoding: UTF-8 122e5b6d6dSopenharmony_ci* tab size: 8 (not used) 132e5b6d6dSopenharmony_ci* indentation:4 142e5b6d6dSopenharmony_ci* 152e5b6d6dSopenharmony_ci* created on: 2003aug04 162e5b6d6dSopenharmony_ci* created by: Markus W. Scherer 172e5b6d6dSopenharmony_ci* 182e5b6d6dSopenharmony_ci* Internal function for sorting arrays. 192e5b6d6dSopenharmony_ci*/ 202e5b6d6dSopenharmony_ci 212e5b6d6dSopenharmony_ci#include <cstddef> 222e5b6d6dSopenharmony_ci 232e5b6d6dSopenharmony_ci#include "unicode/utypes.h" 242e5b6d6dSopenharmony_ci#include "cmemory.h" 252e5b6d6dSopenharmony_ci#include "uarrsort.h" 262e5b6d6dSopenharmony_ci 272e5b6d6dSopenharmony_cienum { 282e5b6d6dSopenharmony_ci /** 292e5b6d6dSopenharmony_ci * "from Knuth" 302e5b6d6dSopenharmony_ci * 312e5b6d6dSopenharmony_ci * A binary search over 8 items performs 4 comparisons: 322e5b6d6dSopenharmony_ci * log2(8)=3 to subdivide, +1 to check for equality. 332e5b6d6dSopenharmony_ci * A linear search over 8 items on average also performs 4 comparisons. 342e5b6d6dSopenharmony_ci */ 352e5b6d6dSopenharmony_ci MIN_QSORT=9, 362e5b6d6dSopenharmony_ci STACK_ITEM_SIZE=200 372e5b6d6dSopenharmony_ci}; 382e5b6d6dSopenharmony_ci 392e5b6d6dSopenharmony_cistatic constexpr int32_t sizeInMaxAlignTs(int32_t sizeInBytes) { 402e5b6d6dSopenharmony_ci return (sizeInBytes + sizeof(std::max_align_t) - 1) / sizeof(std::max_align_t); 412e5b6d6dSopenharmony_ci} 422e5b6d6dSopenharmony_ci 432e5b6d6dSopenharmony_ci/* UComparator convenience implementations ---------------------------------- */ 442e5b6d6dSopenharmony_ci 452e5b6d6dSopenharmony_ciU_CAPI int32_t U_EXPORT2 462e5b6d6dSopenharmony_ciuprv_uint16Comparator(const void *context, const void *left, const void *right) { 472e5b6d6dSopenharmony_ci (void)context; 482e5b6d6dSopenharmony_ci return (int32_t)*(const uint16_t *)left - (int32_t)*(const uint16_t *)right; 492e5b6d6dSopenharmony_ci} 502e5b6d6dSopenharmony_ci 512e5b6d6dSopenharmony_ciU_CAPI int32_t U_EXPORT2 522e5b6d6dSopenharmony_ciuprv_int32Comparator(const void *context, const void *left, const void *right) { 532e5b6d6dSopenharmony_ci (void)context; 542e5b6d6dSopenharmony_ci return *(const int32_t *)left - *(const int32_t *)right; 552e5b6d6dSopenharmony_ci} 562e5b6d6dSopenharmony_ci 572e5b6d6dSopenharmony_ciU_CAPI int32_t U_EXPORT2 582e5b6d6dSopenharmony_ciuprv_uint32Comparator(const void *context, const void *left, const void *right) { 592e5b6d6dSopenharmony_ci (void)context; 602e5b6d6dSopenharmony_ci uint32_t l=*(const uint32_t *)left, r=*(const uint32_t *)right; 612e5b6d6dSopenharmony_ci 622e5b6d6dSopenharmony_ci /* compare directly because (l-r) would overflow the int32_t result */ 632e5b6d6dSopenharmony_ci if(l<r) { 642e5b6d6dSopenharmony_ci return -1; 652e5b6d6dSopenharmony_ci } else if(l==r) { 662e5b6d6dSopenharmony_ci return 0; 672e5b6d6dSopenharmony_ci } else /* l>r */ { 682e5b6d6dSopenharmony_ci return 1; 692e5b6d6dSopenharmony_ci } 702e5b6d6dSopenharmony_ci} 712e5b6d6dSopenharmony_ci 722e5b6d6dSopenharmony_ci/* Insertion sort using binary search --------------------------------------- */ 732e5b6d6dSopenharmony_ci 742e5b6d6dSopenharmony_ciU_CAPI int32_t U_EXPORT2 752e5b6d6dSopenharmony_ciuprv_stableBinarySearch(char *array, int32_t limit, void *item, int32_t itemSize, 762e5b6d6dSopenharmony_ci UComparator *cmp, const void *context) { 772e5b6d6dSopenharmony_ci int32_t start=0; 782e5b6d6dSopenharmony_ci UBool found=false; 792e5b6d6dSopenharmony_ci 802e5b6d6dSopenharmony_ci /* Binary search until we get down to a tiny sub-array. */ 812e5b6d6dSopenharmony_ci while((limit-start)>=MIN_QSORT) { 822e5b6d6dSopenharmony_ci int32_t i=(start+limit)/2; 832e5b6d6dSopenharmony_ci int32_t diff=cmp(context, item, array+i*itemSize); 842e5b6d6dSopenharmony_ci if(diff==0) { 852e5b6d6dSopenharmony_ci /* 862e5b6d6dSopenharmony_ci * Found the item. We look for the *last* occurrence of such 872e5b6d6dSopenharmony_ci * an item, for stable sorting. 882e5b6d6dSopenharmony_ci * If we knew that there will be only few equal items, 892e5b6d6dSopenharmony_ci * we could break now and enter the linear search. 902e5b6d6dSopenharmony_ci * However, if there are many equal items, then it should be 912e5b6d6dSopenharmony_ci * faster to continue with the binary search. 922e5b6d6dSopenharmony_ci * It seems likely that we either have all unique items 932e5b6d6dSopenharmony_ci * (where found will never become true in the insertion sort) 942e5b6d6dSopenharmony_ci * or potentially many duplicates. 952e5b6d6dSopenharmony_ci */ 962e5b6d6dSopenharmony_ci found=true; 972e5b6d6dSopenharmony_ci start=i+1; 982e5b6d6dSopenharmony_ci } else if(diff<0) { 992e5b6d6dSopenharmony_ci limit=i; 1002e5b6d6dSopenharmony_ci } else { 1012e5b6d6dSopenharmony_ci start=i; 1022e5b6d6dSopenharmony_ci } 1032e5b6d6dSopenharmony_ci } 1042e5b6d6dSopenharmony_ci 1052e5b6d6dSopenharmony_ci /* Linear search over the remaining tiny sub-array. */ 1062e5b6d6dSopenharmony_ci while(start<limit) { 1072e5b6d6dSopenharmony_ci int32_t diff=cmp(context, item, array+start*itemSize); 1082e5b6d6dSopenharmony_ci if(diff==0) { 1092e5b6d6dSopenharmony_ci found=true; 1102e5b6d6dSopenharmony_ci } else if(diff<0) { 1112e5b6d6dSopenharmony_ci break; 1122e5b6d6dSopenharmony_ci } 1132e5b6d6dSopenharmony_ci ++start; 1142e5b6d6dSopenharmony_ci } 1152e5b6d6dSopenharmony_ci return found ? (start-1) : ~start; 1162e5b6d6dSopenharmony_ci} 1172e5b6d6dSopenharmony_ci 1182e5b6d6dSopenharmony_cistatic void 1192e5b6d6dSopenharmony_cidoInsertionSort(char *array, int32_t length, int32_t itemSize, 1202e5b6d6dSopenharmony_ci UComparator *cmp, const void *context, void *pv) { 1212e5b6d6dSopenharmony_ci int32_t j; 1222e5b6d6dSopenharmony_ci 1232e5b6d6dSopenharmony_ci for(j=1; j<length; ++j) { 1242e5b6d6dSopenharmony_ci char *item=array+j*itemSize; 1252e5b6d6dSopenharmony_ci int32_t insertionPoint=uprv_stableBinarySearch(array, j, item, itemSize, cmp, context); 1262e5b6d6dSopenharmony_ci if(insertionPoint<0) { 1272e5b6d6dSopenharmony_ci insertionPoint=~insertionPoint; 1282e5b6d6dSopenharmony_ci } else { 1292e5b6d6dSopenharmony_ci ++insertionPoint; /* one past the last equal item */ 1302e5b6d6dSopenharmony_ci } 1312e5b6d6dSopenharmony_ci if(insertionPoint<j) { 1322e5b6d6dSopenharmony_ci char *dest=array+insertionPoint*itemSize; 1332e5b6d6dSopenharmony_ci uprv_memcpy(pv, item, itemSize); /* v=array[j] */ 1342e5b6d6dSopenharmony_ci uprv_memmove(dest+itemSize, dest, (j-insertionPoint)*(size_t)itemSize); 1352e5b6d6dSopenharmony_ci uprv_memcpy(dest, pv, itemSize); /* array[insertionPoint]=v */ 1362e5b6d6dSopenharmony_ci } 1372e5b6d6dSopenharmony_ci } 1382e5b6d6dSopenharmony_ci} 1392e5b6d6dSopenharmony_ci 1402e5b6d6dSopenharmony_cistatic void 1412e5b6d6dSopenharmony_ciinsertionSort(char *array, int32_t length, int32_t itemSize, 1422e5b6d6dSopenharmony_ci UComparator *cmp, const void *context, UErrorCode *pErrorCode) { 1432e5b6d6dSopenharmony_ci 1442e5b6d6dSopenharmony_ci icu::MaybeStackArray<std::max_align_t, sizeInMaxAlignTs(STACK_ITEM_SIZE)> v; 1452e5b6d6dSopenharmony_ci if (sizeInMaxAlignTs(itemSize) > v.getCapacity() && 1462e5b6d6dSopenharmony_ci v.resize(sizeInMaxAlignTs(itemSize)) == nullptr) { 1472e5b6d6dSopenharmony_ci *pErrorCode = U_MEMORY_ALLOCATION_ERROR; 1482e5b6d6dSopenharmony_ci return; 1492e5b6d6dSopenharmony_ci } 1502e5b6d6dSopenharmony_ci 1512e5b6d6dSopenharmony_ci doInsertionSort(array, length, itemSize, cmp, context, v.getAlias()); 1522e5b6d6dSopenharmony_ci} 1532e5b6d6dSopenharmony_ci 1542e5b6d6dSopenharmony_ci/* QuickSort ---------------------------------------------------------------- */ 1552e5b6d6dSopenharmony_ci 1562e5b6d6dSopenharmony_ci/* 1572e5b6d6dSopenharmony_ci * This implementation is semi-recursive: 1582e5b6d6dSopenharmony_ci * It recurses for the smaller sub-array to shorten the recursion depth, 1592e5b6d6dSopenharmony_ci * and loops for the larger sub-array. 1602e5b6d6dSopenharmony_ci * 1612e5b6d6dSopenharmony_ci * Loosely after QuickSort algorithms in 1622e5b6d6dSopenharmony_ci * Niklaus Wirth 1632e5b6d6dSopenharmony_ci * Algorithmen und Datenstrukturen mit Modula-2 1642e5b6d6dSopenharmony_ci * B.G. Teubner Stuttgart 1652e5b6d6dSopenharmony_ci * 4. Auflage 1986 1662e5b6d6dSopenharmony_ci * ISBN 3-519-02260-5 1672e5b6d6dSopenharmony_ci */ 1682e5b6d6dSopenharmony_cistatic void 1692e5b6d6dSopenharmony_cisubQuickSort(char *array, int32_t start, int32_t limit, int32_t itemSize, 1702e5b6d6dSopenharmony_ci UComparator *cmp, const void *context, 1712e5b6d6dSopenharmony_ci void *px, void *pw) { 1722e5b6d6dSopenharmony_ci int32_t left, right; 1732e5b6d6dSopenharmony_ci 1742e5b6d6dSopenharmony_ci /* start and left are inclusive, limit and right are exclusive */ 1752e5b6d6dSopenharmony_ci do { 1762e5b6d6dSopenharmony_ci if((start+MIN_QSORT)>=limit) { 1772e5b6d6dSopenharmony_ci doInsertionSort(array+start*itemSize, limit-start, itemSize, cmp, context, px); 1782e5b6d6dSopenharmony_ci break; 1792e5b6d6dSopenharmony_ci } 1802e5b6d6dSopenharmony_ci 1812e5b6d6dSopenharmony_ci left=start; 1822e5b6d6dSopenharmony_ci right=limit; 1832e5b6d6dSopenharmony_ci 1842e5b6d6dSopenharmony_ci /* x=array[middle] */ 1852e5b6d6dSopenharmony_ci uprv_memcpy(px, array+(size_t)((start+limit)/2)*itemSize, itemSize); 1862e5b6d6dSopenharmony_ci 1872e5b6d6dSopenharmony_ci do { 1882e5b6d6dSopenharmony_ci while(/* array[left]<x */ 1892e5b6d6dSopenharmony_ci cmp(context, array+left*itemSize, px)<0 1902e5b6d6dSopenharmony_ci ) { 1912e5b6d6dSopenharmony_ci ++left; 1922e5b6d6dSopenharmony_ci } 1932e5b6d6dSopenharmony_ci while(/* x<array[right-1] */ 1942e5b6d6dSopenharmony_ci cmp(context, px, array+(right-1)*itemSize)<0 1952e5b6d6dSopenharmony_ci ) { 1962e5b6d6dSopenharmony_ci --right; 1972e5b6d6dSopenharmony_ci } 1982e5b6d6dSopenharmony_ci 1992e5b6d6dSopenharmony_ci /* swap array[left] and array[right-1] via w; ++left; --right */ 2002e5b6d6dSopenharmony_ci if(left<right) { 2012e5b6d6dSopenharmony_ci --right; 2022e5b6d6dSopenharmony_ci 2032e5b6d6dSopenharmony_ci if(left<right) { 2042e5b6d6dSopenharmony_ci uprv_memcpy(pw, array+(size_t)left*itemSize, itemSize); 2052e5b6d6dSopenharmony_ci uprv_memcpy(array+(size_t)left*itemSize, array+(size_t)right*itemSize, itemSize); 2062e5b6d6dSopenharmony_ci uprv_memcpy(array+(size_t)right*itemSize, pw, itemSize); 2072e5b6d6dSopenharmony_ci } 2082e5b6d6dSopenharmony_ci 2092e5b6d6dSopenharmony_ci ++left; 2102e5b6d6dSopenharmony_ci } 2112e5b6d6dSopenharmony_ci } while(left<right); 2122e5b6d6dSopenharmony_ci 2132e5b6d6dSopenharmony_ci /* sort sub-arrays */ 2142e5b6d6dSopenharmony_ci if((right-start)<(limit-left)) { 2152e5b6d6dSopenharmony_ci /* sort [start..right[ */ 2162e5b6d6dSopenharmony_ci if(start<(right-1)) { 2172e5b6d6dSopenharmony_ci subQuickSort(array, start, right, itemSize, cmp, context, px, pw); 2182e5b6d6dSopenharmony_ci } 2192e5b6d6dSopenharmony_ci 2202e5b6d6dSopenharmony_ci /* sort [left..limit[ */ 2212e5b6d6dSopenharmony_ci start=left; 2222e5b6d6dSopenharmony_ci } else { 2232e5b6d6dSopenharmony_ci /* sort [left..limit[ */ 2242e5b6d6dSopenharmony_ci if(left<(limit-1)) { 2252e5b6d6dSopenharmony_ci subQuickSort(array, left, limit, itemSize, cmp, context, px, pw); 2262e5b6d6dSopenharmony_ci } 2272e5b6d6dSopenharmony_ci 2282e5b6d6dSopenharmony_ci /* sort [start..right[ */ 2292e5b6d6dSopenharmony_ci limit=right; 2302e5b6d6dSopenharmony_ci } 2312e5b6d6dSopenharmony_ci } while(start<(limit-1)); 2322e5b6d6dSopenharmony_ci} 2332e5b6d6dSopenharmony_ci 2342e5b6d6dSopenharmony_cistatic void 2352e5b6d6dSopenharmony_ciquickSort(char *array, int32_t length, int32_t itemSize, 2362e5b6d6dSopenharmony_ci UComparator *cmp, const void *context, UErrorCode *pErrorCode) { 2372e5b6d6dSopenharmony_ci /* allocate two intermediate item variables (x and w) */ 2382e5b6d6dSopenharmony_ci icu::MaybeStackArray<std::max_align_t, sizeInMaxAlignTs(STACK_ITEM_SIZE) * 2> xw; 2392e5b6d6dSopenharmony_ci if(sizeInMaxAlignTs(itemSize)*2 > xw.getCapacity() && 2402e5b6d6dSopenharmony_ci xw.resize(sizeInMaxAlignTs(itemSize) * 2) == nullptr) { 2412e5b6d6dSopenharmony_ci *pErrorCode=U_MEMORY_ALLOCATION_ERROR; 2422e5b6d6dSopenharmony_ci return; 2432e5b6d6dSopenharmony_ci } 2442e5b6d6dSopenharmony_ci 2452e5b6d6dSopenharmony_ci subQuickSort(array, 0, length, itemSize, cmp, context, 2462e5b6d6dSopenharmony_ci xw.getAlias(), xw.getAlias() + sizeInMaxAlignTs(itemSize)); 2472e5b6d6dSopenharmony_ci} 2482e5b6d6dSopenharmony_ci 2492e5b6d6dSopenharmony_ci/* uprv_sortArray() API ----------------------------------------------------- */ 2502e5b6d6dSopenharmony_ci 2512e5b6d6dSopenharmony_ci/* 2522e5b6d6dSopenharmony_ci * Check arguments, select an appropriate implementation, 2532e5b6d6dSopenharmony_ci * cast the array to char * so that array+i*itemSize works. 2542e5b6d6dSopenharmony_ci */ 2552e5b6d6dSopenharmony_ciU_CAPI void U_EXPORT2 2562e5b6d6dSopenharmony_ciuprv_sortArray(void *array, int32_t length, int32_t itemSize, 2572e5b6d6dSopenharmony_ci UComparator *cmp, const void *context, 2582e5b6d6dSopenharmony_ci UBool sortStable, UErrorCode *pErrorCode) { 2592e5b6d6dSopenharmony_ci if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 2602e5b6d6dSopenharmony_ci return; 2612e5b6d6dSopenharmony_ci } 2622e5b6d6dSopenharmony_ci if((length>0 && array==NULL) || length<0 || itemSize<=0 || cmp==NULL) { 2632e5b6d6dSopenharmony_ci *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 2642e5b6d6dSopenharmony_ci return; 2652e5b6d6dSopenharmony_ci } 2662e5b6d6dSopenharmony_ci 2672e5b6d6dSopenharmony_ci if(length<=1) { 2682e5b6d6dSopenharmony_ci return; 2692e5b6d6dSopenharmony_ci } else if(length<MIN_QSORT || sortStable) { 2702e5b6d6dSopenharmony_ci insertionSort((char *)array, length, itemSize, cmp, context, pErrorCode); 2712e5b6d6dSopenharmony_ci } else { 2722e5b6d6dSopenharmony_ci quickSort((char *)array, length, itemSize, cmp, context, pErrorCode); 2732e5b6d6dSopenharmony_ci } 2742e5b6d6dSopenharmony_ci} 275