// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright ( C ) 2003 - 2013 , International Business Machines
* Corporation and others . All Rights Reserved .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* file name : uarrsort . c
* encoding : UTF - 8
* tab size : 8 ( not used )
* indentation : 4
*
* created on : 2003 aug04
* created by : Markus W . Scherer
*
* Internal function for sorting arrays .
*/
#include <cstddef>
#include "unicode/utypes.h"
#include "cmemory.h"
#include "uarrsort.h"
enum {
/**
* " from Knuth "
*
* A binary search over 8 items performs 4 comparisons :
* log2 ( 8 ) = 3 to subdivide , + 1 to check for equality .
* A linear search over 8 items on average also performs 4 comparisons .
*/
MIN_QSORT=
9 ,
STACK_ITEM_SIZE=
200
};
static constexpr int32_t sizeInMaxAlignTs(int32_t sizeInBytes) {
return (sizeInBytes +
sizeof (std::max_align_t) -
1 ) /
sizeof (std::max_align_t);
}
/* UComparator convenience implementations ---------------------------------- */
U_CAPI int32_t U_EXPORT2
uprv_uint16Comparator(
const void *context,
const void *left,
const void *right) {
(
void )context;
return (int32_t)*(
const uint16_t *)left - (int32_t)*(
const uint16_t *)right;
}
U_CAPI int32_t U_EXPORT2
uprv_int32Comparator(
const void *context,
const void *left,
const void *right) {
(
void )context;
return *(
const int32_t *)left - *(
const int32_t *)right;
}
U_CAPI int32_t U_EXPORT2
uprv_uint32Comparator(
const void *context,
const void *left,
const void *right) {
(
void )context;
uint32_t l=*(
const uint32_t *)left, r=*(
const uint32_t *)right;
/* compare directly because (l-r) would overflow the int32_t result */
if (l<r) {
return -
1 ;
}
else if (l==r) {
return 0 ;
}
else /* l>r */ {
return 1 ;
}
}
/* Insertion sort using binary search --------------------------------------- */
U_CAPI int32_t U_EXPORT2
uprv_stableBinarySearch(
char *array, int32_t limit,
void *item, int32_t itemSize,
UComparator *cmp,
const void *context) {
int32_t start=
0 ;
UBool found=
false ;
/* Binary search until we get down to a tiny sub-array. */
while ((limit-start)>=MIN_QSORT) {
int32_t i=(start+limit)/
2 ;
int32_t diff=cmp(context, item, array+i*itemSize);
if (diff==
0 ) {
/*
* Found the item . We look for the * last * occurrence of such
* an item , for stable sorting .
* If we knew that there will be only few equal items ,
* we could break now and enter the linear search .
* However , if there are many equal items , then it should be
* faster to continue with the binary search .
* It seems likely that we either have all unique items
* ( where found will never become true in the insertion sort )
* or potentially many duplicates .
*/
found=true;
start=i+
1 ;
}
else if (diff<
0 ) {
limit=i;
}
else {
start=i;
}
}
/* Linear search over the remaining tiny sub-array. */
while (start<limit) {
int32_t diff=cmp(context, item, array+start*itemSize);
if (diff==
0 ) {
found=true;
}
else if (diff<
0 ) {
break ;
}
++start;
}
return found ? (start-
1 ) : ~start;
}
static void
doInsertionSort(
char *array, int32_t length, int32_t itemSize,
UComparator *cmp,
const void *context,
void *pv) {
int32_t j;
for (j=
1 ; j<length; ++j) {
char *item=array+j*itemSize;
int32_t insertionPoint=uprv_stableBinarySearch(array, j, item, itemSize, cmp, context)
;
if (insertionPoint<0 ) {
insertionPoint=~insertionPoint;
} else {
++insertionPoint; /* one past the last equal item */
}
if (insertionPoint<j) {
char *dest=array+insertionPoint*itemSize;
uprv_memcpy(pv, item, itemSize); /* v=array[j] */
uprv_memmove(dest+itemSize, dest, (j-insertionPoint)*(size_t)itemSize);
uprv_memcpy(dest, pv, itemSize); /* array[insertionPoint]=v */
}
}
}
static void
insertionSort(char *array, int32_t length, int32_t itemSize,
UComparator *cmp, const void *context, UErrorCode *pErrorCode) {
icu::MaybeStackArray<std::max_align_t, sizeInMaxAlignTs(STACK_ITEM_SIZE)> v;
if (sizeInMaxAlignTs(itemSize) > v.getCapacity() &&
v.resize(sizeInMaxAlignTs(itemSize)) == nullptr) {
*pErrorCode = U_MEMORY_ALLOCATION_ERROR;
return ;
}
doInsertionSort(array, length, itemSize, cmp, context, v.getAlias());
}
/* QuickSort ---------------------------------------------------------------- */
/*
* This implementation is semi - recursive :
* It recurses for the smaller sub - array to shorten the recursion depth ,
* and loops for the larger sub - array .
*
* Loosely after QuickSort algorithms in
* Niklaus Wirth
* Algorithmen und Datenstrukturen mit Modula - 2
* B . G . Teubner Stuttgart
* 4 . Auflage 1986
* ISBN 3 - 519 - 02260 - 5
*/
static void
subQuickSort(char *array, int32_t start, int32_t limit, int32_t itemSize,
UComparator *cmp, const void *context,
void *px, void *pw) {
int32_t left, right;
/* start and left are inclusive, limit and right are exclusive */
do {
if ((start+MIN_QSORT)>=limit) {
doInsertionSort(array+start*itemSize, limit-start, itemSize, cmp, context, px);
break ;
}
left=start;
right=limit;
/* x=array[middle] */
uprv_memcpy(px, array+(size_t)((start+limit)/2 )*itemSize, itemSize);
do {
while (/* array[left]<x */
cmp(context, array+left*itemSize, px)<0
) {
++left;
}
while (/* x<array[right-1] */
cmp(context, px, array+(right-1 )*itemSize)<0
) {
--right;
}
/* swap array[left] and array[right-1] via w; ++left; --right */
if (left<right) {
--right;
if (left<right) {
uprv_memcpy(pw, array+(size_t)left*itemSize, itemSize);
uprv_memcpy(array+(size_t)left*itemSize, array+(size_t)right*itemSize, itemSize);
uprv_memcpy(array+(size_t)right*itemSize, pw, itemSize);
}
++left;
}
} while (left<right);
/* sort sub-arrays */
if ((right-start)<(limit-left)) {
/* sort [start..right[ */
if (start<(right-1 )) {
subQuickSort(array, start, right, itemSize, cmp, context, px, pw);
}
/* sort [left..limit[ */
start=left;
} else {
/* sort [left..limit[ */
if (left<(limit-1 )) {
subQuickSort(array, left, limit, itemSize, cmp, context, px, pw);
}
/* sort [start..right[ */
limit=right;
}
} while (start<(limit-1 ));
}
static void
quickSort(char *array, int32_t length, int32_t itemSize,
UComparator *cmp, const void *context, UErrorCode *pErrorCode) {
/* allocate two intermediate item variables (x and w) */
icu::MaybeStackArray<std::max_align_t, sizeInMaxAlignTs(STACK_ITEM_SIZE) * 2 > xw;
if (sizeInMaxAlignTs(itemSize)*2 > xw.getCapacity() &&
xw.resize(sizeInMaxAlignTs(itemSize) * 2 ) == nullptr) {
*pErrorCode=U_MEMORY_ALLOCATION_ERROR;
return ;
}
subQuickSort(array, 0 , length, itemSize, cmp, context,
xw.getAlias(), xw.getAlias() + sizeInMaxAlignTs(itemSize));
}
/* uprv_sortArray() API ----------------------------------------------------- */
/*
* Check arguments , select an appropriate implementation ,
* cast the array to char * so that array + i * itemSize works .
*/
U_CAPI void U_EXPORT2
uprv_sortArray(void *array, int32_t length, int32_t itemSize,
UComparator *cmp, const void *context,
UBool sortStable, UErrorCode *pErrorCode) {
if (pErrorCode==nullptr || U_FAILURE(*pErrorCode)) {
return ;
}
if ((length>0 && array==nullptr) || length<0 || itemSize<=0 || cmp==nullptr) {
*pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
return ;
}
if (length<=1 ) {
return ;
} else if (length<MIN_QSORT || sortStable) {
insertionSort((char *)array, length, itemSize, cmp, context, pErrorCode);
} else {
quickSort((char *)array, length, itemSize, cmp, context, pErrorCode);
}
}
Messung V0.5 in Prozent C=87 H=83 G=84
¤ Dauer der Verarbeitung: 0.7 Sekunden
¤
*© Formatika GbR, Deutschland