@@ -22,6 +22,7 @@ const int32_t CompareOptionsIgnoreNonSpace = 0x2;
22
22
const int32_t CompareOptionsIgnoreSymbols = 0x4 ;
23
23
const int32_t CompareOptionsIgnoreKanaType = 0x8 ;
24
24
const int32_t CompareOptionsIgnoreWidth = 0x10 ;
25
+ const int32_t CompareOptionsMask = 0x1f ;
25
26
// const int32_t CompareOptionsStringSort = 0x20000000;
26
27
// ICU's default is to use "StringSort", i.e. nonalphanumeric symbols come before alphanumeric.
27
28
// When StringSort is not specified (.NET's default), the sort order will be different between
@@ -41,21 +42,11 @@ typedef struct { int32_t key; UCollator* UCollator; } TCollatorMap;
41
42
*/
42
43
struct SortHandle
43
44
{
44
- UCollator * regular ;
45
45
pthread_mutex_t collatorsLockObject ;
46
- void * collatorsPerOptionRoot ;
46
+ UCollator * collatorsPerOption [ CompareOptionsMask + 1 ] ;
47
47
};
48
48
49
- typedef struct { UChar * items ; size_t capacity ; size_t size ; } UCharList ;
50
-
51
- static int TreeComparer (const void * left , const void * right )
52
- {
53
- const TCollatorMap * leftMap = left ;
54
- const TCollatorMap * rightMap = right ;
55
- if (leftMap -> key < rightMap -> key ) return -1 ;
56
- if (leftMap -> key > rightMap -> key ) return 1 ;
57
- return 0 ;
58
- }
49
+ typedef struct { UChar * items ; size_t size ; } UCharList ;
59
50
60
51
// Hiragana character range
61
52
const UChar hiraganaStart = 0x3041 ;
@@ -137,24 +128,6 @@ static int IsHalfFullHigherSymbol(UChar character)
137
128
|| (0xff61 <= character && character <= 0xff65 );
138
129
}
139
130
140
- static int AddItem (UCharList * list , const UChar item )
141
- {
142
- size_t size = list -> size ++ ;
143
- if (size >= list -> capacity )
144
- {
145
- list -> capacity *= 2 ;
146
- UChar * ptr = (UChar * )realloc (list -> items , list -> capacity * sizeof (UChar * ));
147
- if (ptr == NULL )
148
- {
149
- return FALSE;
150
- }
151
- list -> items = ptr ;
152
- }
153
-
154
- list -> items [size ] = item ;
155
- return TRUE;
156
- }
157
-
158
131
/*
159
132
Gets a string of custom collation rules, if necessary.
160
133
@@ -184,19 +157,19 @@ static UCharList* GetCustomRules(int32_t options, UColAttributeValue strength, i
184
157
}
185
158
186
159
// If we need to create customRules, the KanaType custom rule will be 88 kana characters * 4 = 352 chars long
187
- // and the Width custom rule will be at least 215 halfwidth characters * 4 = 860 chars long.
188
- // Use 512 as the starting size, so the customRules won't have to grow if we are just
189
- // doing the KanaType custom rule.
190
- customRules -> capacity = 512 ;
191
- customRules -> items = calloc (customRules -> capacity , sizeof (UChar ));
160
+ // and the Width custom rule will be at most 212 halfwidth characters * 5 = 1060 chars long.
161
+ int capacity =
162
+ ((needsIgnoreKanaTypeCustomRule || needsNotIgnoreKanaTypeCustomRule ) ? 4 * (hiraganaEnd - hiraganaStart + 1 ) : 0 ) +
163
+ ((needsIgnoreWidthCustomRule || needsNotIgnoreWidthCustomRule ) ? 5 * g_HalfFullCharsLength : 0 );
164
+
165
+ UChar * items ;
166
+ customRules -> items = items = malloc (capacity * sizeof (UChar ));
192
167
if (customRules -> items == NULL )
193
168
{
194
169
free (customRules );
195
170
return NULL ;
196
171
}
197
172
198
- customRules -> size = 0 ;
199
-
200
173
if (needsIgnoreKanaTypeCustomRule || needsNotIgnoreKanaTypeCustomRule )
201
174
{
202
175
UChar compareChar = needsIgnoreKanaTypeCustomRule ? '=' : '<' ;
@@ -206,15 +179,11 @@ static UCharList* GetCustomRules(int32_t options, UColAttributeValue strength, i
206
179
// Hiragana is the range 3041 to 3096 & 309D & 309E
207
180
if (hiraganaChar <= 0x3096 || hiraganaChar >= 0x309D ) // characters between 3096 and 309D are not mapped to katakana
208
181
{
209
- if (!(AddItem (customRules , '&' ) &&
210
- AddItem (customRules , hiraganaChar ) &&
211
- AddItem (customRules , compareChar ) &&
212
- AddItem (customRules , hiraganaChar + hiraganaToKatakanaOffset )))
213
- {
214
- free (customRules -> items );
215
- free (customRules );
216
- return NULL ;
217
- }
182
+ assert (items - customRules -> items <= capacity - 4 );
183
+ * (items ++ ) = '&' ;
184
+ * (items ++ ) = hiraganaChar ;
185
+ * (items ++ ) = compareChar ;
186
+ * (items ++ ) = hiraganaChar + hiraganaToKatakanaOffset ;
218
187
}
219
188
}
220
189
}
@@ -237,20 +206,21 @@ static UCharList* GetCustomRules(int32_t options, UColAttributeValue strength, i
237
206
// this character is a symbol, and if so skip it
238
207
if (!(isIgnoreSymbols && needsNotIgnoreWidthCustomRule && (needsEscape || IsHalfFullHigherSymbol (higherChar ))))
239
208
{
240
- if (!(AddItem (customRules , '&' ) &&
241
- (!needsEscape || AddItem (customRules , '\\' )) &&
242
- AddItem (customRules , lowerChar ) &&
243
- AddItem (customRules , compareChar ) &&
244
- AddItem (customRules , higherChar )))
209
+ assert (items - customRules -> items <= capacity - 5 );
210
+ * (items ++ ) = '&' ;
211
+ if (needsEscape )
245
212
{
246
- free (customRules -> items );
247
- free (customRules );
248
- return NULL ;
213
+ * (items ++ ) = '\\' ;
249
214
}
215
+ * (items ++ ) = lowerChar ;
216
+ * (items ++ ) = compareChar ;
217
+ * (items ++ ) = higherChar ;
250
218
}
251
219
}
252
220
}
253
221
222
+ customRules -> size = items - customRules -> items ;
223
+
254
224
return customRules ;
255
225
}
256
226
@@ -280,7 +250,7 @@ UCollator* CloneCollatorWithOptions(const UCollator* pCollator, int32_t options,
280
250
281
251
UCollator * pClonedCollator ;
282
252
UCharList * customRules = GetCustomRules (options , strength , isIgnoreSymbols );
283
- if (customRules == NULL )
253
+ if (customRules == NULL || customRules -> size == 0 )
284
254
{
285
255
pClonedCollator = ucol_safeClone (pCollator , NULL , NULL , pErr );
286
256
}
@@ -305,8 +275,8 @@ UCollator* CloneCollatorWithOptions(const UCollator* pCollator, int32_t options,
305
275
306
276
pClonedCollator = ucol_openRules (completeRules , completeRulesLength , UCOL_DEFAULT , strength , NULL , pErr );
307
277
free (completeRules );
308
- free (customRules );
309
278
}
279
+ free (customRules );
310
280
311
281
if (isIgnoreSymbols )
312
282
{
@@ -371,9 +341,9 @@ void CreateSortHandle(SortHandle** ppSortHandle)
371
341
return ;
372
342
}
373
343
374
- (* ppSortHandle )-> collatorsPerOptionRoot = NULL ;
375
- int result = pthread_mutex_init (& (* ppSortHandle )-> collatorsLockObject , NULL );
344
+ memset (* ppSortHandle , 0 , sizeof (SortHandle ));
376
345
346
+ int result = pthread_mutex_init (& (* ppSortHandle )-> collatorsLockObject , NULL );
377
347
if (result != 0 )
378
348
{
379
349
assert (FALSE && "Unexpected pthread_mutex_init return value." );
@@ -392,7 +362,7 @@ ResultCode GlobalizationNative_GetSortHandle(const char* lpLocaleName, SortHandl
392
362
393
363
UErrorCode err = U_ZERO_ERROR ;
394
364
395
- (* ppSortHandle )-> regular = ucol_open (lpLocaleName , & err );
365
+ (* ppSortHandle )-> collatorsPerOption [ 0 ] = ucol_open (lpLocaleName , & err );
396
366
397
367
if (U_FAILURE (err ))
398
368
{
@@ -406,15 +376,13 @@ ResultCode GlobalizationNative_GetSortHandle(const char* lpLocaleName, SortHandl
406
376
407
377
void GlobalizationNative_CloseSortHandle (SortHandle * pSortHandle )
408
378
{
409
- ucol_close (pSortHandle -> regular );
410
- pSortHandle -> regular = NULL ;
411
-
412
- while (pSortHandle -> collatorsPerOptionRoot != NULL )
379
+ for (int i = 0 ; i <= CompareOptionsMask ; i ++ )
413
380
{
414
- TCollatorMap * data = * (TCollatorMap * * )pSortHandle -> collatorsPerOptionRoot ;
415
- tdelete (data , & pSortHandle -> collatorsPerOptionRoot , TreeComparer );
416
- ucol_close (data -> UCollator );
417
- free (data );
381
+ if (pSortHandle -> collatorsPerOption [i ] != NULL )
382
+ {
383
+ ucol_close (pSortHandle -> collatorsPerOption [i ]);
384
+ pSortHandle -> collatorsPerOption [i ] = NULL ;
385
+ }
418
386
}
419
387
420
388
pthread_mutex_destroy (& pSortHandle -> collatorsLockObject );
@@ -427,7 +395,7 @@ const UCollator* GetCollatorFromSortHandle(SortHandle* pSortHandle, int32_t opti
427
395
UCollator * pCollator ;
428
396
if (options == 0 )
429
397
{
430
- pCollator = pSortHandle -> regular ;
398
+ pCollator = pSortHandle -> collatorsPerOption [ 0 ] ;
431
399
}
432
400
else
433
401
{
@@ -437,22 +405,12 @@ const UCollator* GetCollatorFromSortHandle(SortHandle* pSortHandle, int32_t opti
437
405
assert (FALSE && "Unexpected pthread_mutex_lock return value." );
438
406
}
439
407
440
- TCollatorMap * map = (TCollatorMap * )malloc (sizeof (TCollatorMap ));
441
- map -> key = options ;
442
- // tfind on glibc is significantly faster than tsearch and we expect
443
- // to hit the cache here often so it's benefitial to prefer lookup time
444
- // over addition time
445
- void * entry = tfind (map , & pSortHandle -> collatorsPerOptionRoot , TreeComparer );
446
- if (entry == NULL )
447
- {
448
- pCollator = CloneCollatorWithOptions (pSortHandle -> regular , options , pErr );
449
- map -> UCollator = pCollator ;
450
- tsearch (map , & pSortHandle -> collatorsPerOptionRoot , TreeComparer );
451
- }
452
- else
408
+ options &= CompareOptionsMask ;
409
+ pCollator = pSortHandle -> collatorsPerOption [options ];
410
+ if (pCollator == NULL )
453
411
{
454
- free ( map );
455
- pCollator = ( * ( TCollatorMap * * ) entry ) -> UCollator ;
412
+ pCollator = CloneCollatorWithOptions ( pSortHandle -> collatorsPerOption [ 0 ], options , pErr );
413
+ pSortHandle -> collatorsPerOption [ options ] = pCollator ;
456
414
}
457
415
458
416
pthread_mutex_unlock (& pSortHandle -> collatorsLockObject );
0 commit comments