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