]> git.saurik.com Git - apple/icu.git/blob - icuSources/test/perf/collperf/collperf.cpp
ICU-57132.0.1.tar.gz
[apple/icu.git] / icuSources / test / perf / collperf / collperf.cpp
1 /********************************************************************
2 * COPYRIGHT:
3 * Copyright (C) 2001-2016 IBM, Inc. All Rights Reserved.
4 *
5 ********************************************************************/
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <locale.h>
10 #include <limits.h>
11 #include <string.h>
12 #include "cmemory.h"
13 #include "unicode/uperf.h"
14 #include "uoptions.h"
15 #include "unicode/coll.h"
16 #include <unicode/ucoleitr.h>
17
18 #if !U_PLATFORM_HAS_WIN32_API
19 #define DWORD uint32_t
20 #define WCHAR wchar_t
21 #endif
22
23 /* To store an array of string<UNIT> in continue space.
24 Since string<UNIT> itself is treated as an array of UNIT, this
25 class will ease our memory management for an array of string<UNIT>.
26 */
27
28 //template<typename UNIT>
29 #define COMPATCT_ARRAY(CompactArrays, UNIT) \
30 struct CompactArrays{\
31 CompactArrays(const CompactArrays & );\
32 CompactArrays & operator=(const CompactArrays & );\
33 int32_t count;/*total number of the strings*/ \
34 int32_t * index;/*relative offset in data*/ \
35 UNIT * data; /*the real space to hold strings*/ \
36 \
37 ~CompactArrays(){free(index);free(data);} \
38 CompactArrays():data(NULL), index(NULL), count(0){ \
39 index = (int32_t *) realloc(index, sizeof(int32_t)); \
40 index[0] = 0; \
41 } \
42 void append_one(int32_t theLen){ /*include terminal NULL*/ \
43 count++; \
44 index = (int32_t *) realloc(index, sizeof(int32_t) * (count + 1)); \
45 index[count] = index[count - 1] + theLen; \
46 data = (UNIT *) realloc(data, sizeof(UNIT) * index[count]); \
47 } \
48 UNIT * last(){return data + index[count - 1];} \
49 UNIT * dataOf(int32_t i){return data + index[i];} \
50 int32_t lengthOf(int i){return index[i+1] - index[i] - 1; } /*exclude terminating NULL*/ \
51 };
52
53 //typedef CompactArrays<UChar> CA_uchar;
54 //typedef CompactArrays<char> CA_char;
55 //typedef CompactArrays<uint8_t> CA_uint8;
56 //typedef CompactArrays<WCHAR> CA_win_wchar;
57
58 COMPATCT_ARRAY(CA_uchar, UChar)
59 COMPATCT_ARRAY(CA_char, char)
60 COMPATCT_ARRAY(CA_uint8, uint8_t)
61 COMPATCT_ARRAY(CA_win_wchar, WCHAR)
62
63
64 struct DataIndex {
65 static DWORD win_langid; // for qsort callback function
66 static UCollator * col; // for qsort callback function
67 uint8_t * icu_key;
68 UChar * icu_data;
69 int32_t icu_data_len;
70 char* posix_key;
71 char* posix_data;
72 int32_t posix_data_len;
73 char* win_key;
74 WCHAR * win_data;
75 int32_t win_data_len;
76 };
77 DWORD DataIndex::win_langid;
78 UCollator * DataIndex::col;
79
80
81
82 class CmdKeyGen : public UPerfFunction {
83 typedef void (CmdKeyGen::* Func)(int32_t);
84 enum{MAX_KEY_LENGTH = 5000};
85 UCollator * col;
86 DWORD win_langid;
87 int32_t count;
88 DataIndex * data;
89 Func fn;
90
91 union { // to save sapce
92 uint8_t icu_key[MAX_KEY_LENGTH];
93 char posix_key[MAX_KEY_LENGTH];
94 WCHAR win_key[MAX_KEY_LENGTH];
95 };
96 public:
97 CmdKeyGen(UErrorCode, UCollator * col,DWORD win_langid, int32_t count, DataIndex * data,Func fn,int32_t)
98 :col(col),win_langid(win_langid), count(count), data(data), fn(fn){}
99
100 virtual long getOperationsPerIteration(){return count;}
101
102 virtual void call(UErrorCode* status){
103 for(int32_t i = 0; i< count; i++){
104 (this->*fn)(i);
105 }
106 }
107
108 void icu_key_null(int32_t i){
109 ucol_getSortKey(col, data[i].icu_data, -1, icu_key, MAX_KEY_LENGTH);
110 }
111
112 void icu_key_len(int32_t i){
113 ucol_getSortKey(col, data[i].icu_data, data[i].icu_data_len, icu_key, MAX_KEY_LENGTH);
114 }
115
116 #if U_PLATFORM_HAS_WIN32_API
117 // pre-generated in CollPerfTest::prepareData(), need not to check error here
118 void win_key_null(int32_t i){
119 //LCMAP_SORTsk 0x00000400 // WC sort sk (normalize)
120 LCMapStringW(win_langid, LCMAP_SORTKEY, data[i].win_data, -1, win_key, MAX_KEY_LENGTH);
121 }
122
123 void win_key_len(int32_t i){
124 LCMapStringW(win_langid, LCMAP_SORTKEY, data[i].win_data, data[i].win_data_len, win_key, MAX_KEY_LENGTH);
125 }
126 #endif
127
128 void posix_key_null(int32_t i){
129 strxfrm(posix_key, data[i].posix_data, MAX_KEY_LENGTH);
130 }
131 };
132
133
134 class CmdIter : public UPerfFunction {
135 typedef void (CmdIter::* Func)(UErrorCode* , int32_t );
136 int32_t count;
137 CA_uchar * data;
138 Func fn;
139 UCollationElements *iter;
140 int32_t exec_count;
141 public:
142 CmdIter(UErrorCode & status, UCollator * col, int32_t count, CA_uchar *data, Func fn, int32_t,int32_t)
143 :count(count), data(data), fn(fn){
144 exec_count = 0;
145 UChar dummytext[] = {0, 0};
146 iter = ucol_openElements(col, NULL, 0, &status);
147 ucol_setText(iter, dummytext, 1, &status);
148 }
149 ~CmdIter(){
150 ucol_closeElements(iter);
151 }
152
153 virtual long getOperationsPerIteration(){return exec_count ? exec_count : 1;}
154
155 virtual void call(UErrorCode* status){
156 exec_count = 0;
157 for(int32_t i = 0; i< count; i++){
158 (this->*fn)(status, i);
159 }
160 }
161
162 void icu_forward_null(UErrorCode* status, int32_t i){
163 ucol_setText(iter, data->dataOf(i), -1, status);
164 while (ucol_next(iter, status) != UCOL_NULLORDER) exec_count++;
165 }
166
167 void icu_forward_len(UErrorCode* status, int32_t i){
168 ucol_setText(iter, data->dataOf(i), data->lengthOf(i) , status);
169 while (ucol_next(iter, status) != UCOL_NULLORDER) exec_count++;
170 }
171
172 void icu_backward_null(UErrorCode* status, int32_t i){
173 ucol_setText(iter, data->dataOf(i), -1, status);
174 while (ucol_previous(iter, status) != UCOL_NULLORDER) exec_count++;
175 }
176
177 void icu_backward_len(UErrorCode* status, int32_t i){
178 ucol_setText(iter, data->dataOf(i), data->lengthOf(i) , status);
179 while (ucol_previous(iter, status) != UCOL_NULLORDER) exec_count++;
180 }
181 };
182
183 class CmdIterAll : public UPerfFunction {
184 typedef void (CmdIterAll::* Func)(UErrorCode* status);
185 int32_t count;
186 UChar * data;
187 Func fn;
188 UCollationElements *iter;
189 int32_t exec_count;
190
191 public:
192 enum CALL {forward_null, forward_len, backward_null, backward_len};
193
194 ~CmdIterAll(){
195 ucol_closeElements(iter);
196 }
197 CmdIterAll(UErrorCode & status, UCollator * col, int32_t count, UChar * data, CALL call,int32_t,int32_t)
198 :count(count),data(data)
199 {
200 exec_count = 0;
201 if (call == forward_null || call == backward_null) {
202 iter = ucol_openElements(col, data, -1, &status);
203 } else {
204 iter = ucol_openElements(col, data, count, &status);
205 }
206
207 if (call == forward_null || call == forward_len){
208 fn = &CmdIterAll::icu_forward_all;
209 } else {
210 fn = &CmdIterAll::icu_backward_all;
211 }
212 }
213 virtual long getOperationsPerIteration(){return exec_count ? exec_count : 1;}
214
215 virtual void call(UErrorCode* status){
216 (this->*fn)(status);
217 }
218
219 void icu_forward_all(UErrorCode* status){
220 int strlen = count - 5;
221 int count5 = 5;
222 int strindex = 0;
223 ucol_setOffset(iter, strindex, status);
224 while (TRUE) {
225 if (ucol_next(iter, status) == UCOL_NULLORDER) {
226 break;
227 }
228 exec_count++;
229 count5 --;
230 if (count5 == 0) {
231 strindex += 10;
232 if (strindex > strlen) {
233 break;
234 }
235 ucol_setOffset(iter, strindex, status);
236 count5 = 5;
237 }
238 }
239 }
240
241 void icu_backward_all(UErrorCode* status){
242 int strlen = count;
243 int count5 = 5;
244 int strindex = 5;
245 ucol_setOffset(iter, strindex, status);
246 while (TRUE) {
247 if (ucol_previous(iter, status) == UCOL_NULLORDER) {
248 break;
249 }
250 exec_count++;
251 count5 --;
252 if (count5 == 0) {
253 strindex += 10;
254 if (strindex > strlen) {
255 break;
256 }
257 ucol_setOffset(iter, strindex, status);
258 count5 = 5;
259 }
260 }
261 }
262
263 };
264
265 struct CmdQsort : public UPerfFunction{
266
267 static int q_random(const void * a, const void * b){
268 uint8_t * key_a = ((DataIndex *)a)->icu_key;
269 uint8_t * key_b = ((DataIndex *)b)->icu_key;
270
271 int val_a = 0;
272 int val_b = 0;
273 while (*key_a != 0) {val_a += val_a*37 + *key_a++;}
274 while (*key_b != 0) {val_b += val_b*37 + *key_b++;}
275 return val_a - val_b;
276 }
277
278 #define QCAST() \
279 DataIndex * da = (DataIndex *) a; \
280 DataIndex * db = (DataIndex *) b; \
281 ++exec_count
282
283 static int icu_strcoll_null(const void *a, const void *b){
284 QCAST();
285 return ucol_strcoll(da->col, da->icu_data, -1, db->icu_data, -1) - UCOL_EQUAL;
286 }
287
288 static int icu_strcoll_len(const void *a, const void *b){
289 QCAST();
290 return ucol_strcoll(da->col, da->icu_data, da->icu_data_len, db->icu_data, db->icu_data_len) - UCOL_EQUAL;
291 }
292
293 static int icu_cmpkey (const void *a, const void *b){
294 QCAST();
295 return strcmp((char *) da->icu_key, (char *) db->icu_key);
296 }
297
298 #if U_PLATFORM_HAS_WIN32_API
299 static int win_cmp_null(const void *a, const void *b) {
300 QCAST();
301 //CSTR_LESS_THAN 1
302 //CSTR_EQUAL 2
303 //CSTR_GREATER_THAN 3
304 int t = CompareStringW(da->win_langid, 0, da->win_data, -1, db->win_data, -1);
305 if (t == 0){
306 fprintf(stderr, "CompareStringW error, error number %x\n", GetLastError());
307 exit(-1);
308 } else{
309 return t - CSTR_EQUAL;
310 }
311 }
312
313 static int win_cmp_len(const void *a, const void *b) {
314 QCAST();
315 int t = CompareStringW(da->win_langid, 0, da->win_data, da->win_data_len, db->win_data, db->win_data_len);
316 if (t == 0){
317 fprintf(stderr, "CompareStringW error, error number %x\n", GetLastError());
318 exit(-1);
319 } else{
320 return t - CSTR_EQUAL;
321 }
322 }
323 #endif
324
325 #define QFUNC(name, func, data) \
326 static int name (const void *a, const void *b){ \
327 QCAST(); \
328 return func(da->data, db->data); \
329 }
330
331 QFUNC(posix_strcoll_null, strcoll, posix_data)
332 QFUNC(posix_cmpkey, strcmp, posix_key)
333 #if U_PLATFORM_HAS_WIN32_API
334 QFUNC(win_cmpkey, strcmp, win_key)
335 QFUNC(win_wcscmp, wcscmp, win_data)
336 #endif
337 QFUNC(icu_strcmp, u_strcmp, icu_data)
338 QFUNC(icu_cmpcpo, u_strcmpCodePointOrder, icu_data)
339
340 private:
341 static int32_t exec_count; // potential muilt-thread problem
342
343 typedef int (* Func)(const void *, const void *);
344
345 Func fn;
346 void * base; //Start of target array.
347 int32_t num; //Array size in elements.
348 int32_t width; //Element size in bytes.
349
350 void * backup; //copy source of base
351 public:
352 CmdQsort(UErrorCode & status,void *theBase, int32_t num, int32_t width, Func fn, int32_t,int32_t)
353 :backup(theBase),num(num),width(width),fn(fn){
354 base = malloc(num * width);
355 time_empty(100, &status); // warm memory/cache
356 }
357
358 ~CmdQsort(){
359 free(base);
360 }
361
362 void empty_call(){
363 exec_count = 0;
364 memcpy(base, backup, num * width);
365 }
366
367 double time_empty(int32_t n, UErrorCode* status) {
368 UTimer start, stop;
369 utimer_getTime(&start);
370 while (n-- > 0) {
371 empty_call();
372 }
373 utimer_getTime(&stop);
374 return utimer_getDeltaSeconds(&start,&stop); // ms
375 }
376
377 virtual void call(UErrorCode* status){
378 exec_count = 0;
379 memcpy(base, backup, num * width);
380 qsort(base, num, width, fn);
381 }
382 virtual double time(int32_t n, UErrorCode* status) {
383 double t1 = time_empty(n,status);
384 double t2 = UPerfFunction::time(n, status);
385 return t2-t1;// < 0 ? t2 : t2-t1;
386 }
387
388 virtual long getOperationsPerIteration(){ return exec_count?exec_count:1;}
389 };
390 int32_t CmdQsort::exec_count;
391
392
393 class CmdBinSearch : public UPerfFunction{
394 public:
395 typedef int (CmdBinSearch::* Func)(int, int);
396
397 UCollator * col;
398 DWORD win_langid;
399 int32_t count;
400 DataIndex * rnd;
401 DataIndex * ord;
402 Func fn;
403 int32_t exec_count;
404
405 CmdBinSearch(UErrorCode, UCollator * col,DWORD win_langid,int32_t count,DataIndex * rnd,DataIndex * ord,Func fn)
406 :col(col),win_langid(win_langid), count(count), rnd(rnd), ord(ord), fn(fn),exec_count(0){}
407
408
409 virtual void call(UErrorCode* status){
410 exec_count = 0;
411 for(int32_t i = 0; i< count; i++){ // search all data
412 binary_search(i);
413 }
414 }
415 virtual long getOperationsPerIteration(){ return exec_count?exec_count:1;}
416
417 void binary_search(int32_t random) {
418 int low = 0;
419 int high = count - 1;
420 int guess;
421 int last_guess = -1;
422 int r;
423 while (TRUE) {
424 guess = (high + low)/2;
425 if (last_guess == guess) break; // nothing to search
426
427 r = (this->*fn)(random, guess);
428 exec_count++;
429
430 if (r == 0)
431 return; // found, search end.
432 if (r < 0) {
433 high = guess;
434 } else {
435 low = guess;
436 }
437 last_guess = guess;
438 }
439 }
440
441 int icu_strcoll_null(int32_t i, int32_t j){
442 return ucol_strcoll(col, rnd[i].icu_data, -1, ord[j].icu_data,-1);
443 }
444
445 int icu_strcoll_len(int32_t i, int32_t j){
446 return ucol_strcoll(col, rnd[i].icu_data, rnd[i].icu_data_len, ord[j].icu_data, ord[j].icu_data_len);
447 }
448
449 int icu_cmpkey(int32_t i, int32_t j) {
450 return strcmp( (char *) rnd[i].icu_key, (char *) ord[j].icu_key );
451 }
452
453 #if U_PLATFORM_HAS_WIN32_API
454 int win_cmp_null(int32_t i, int32_t j) {
455 int t = CompareStringW(win_langid, 0, rnd[i].win_data, -1, ord[j].win_data, -1);
456 if (t == 0){
457 fprintf(stderr, "CompareStringW error, error number %x\n", GetLastError());
458 exit(-1);
459 } else{
460 return t - CSTR_EQUAL;
461 }
462 }
463
464 int win_cmp_len(int32_t i, int32_t j) {
465 int t = CompareStringW(win_langid, 0, rnd[i].win_data, rnd[i].win_data_len, ord[j].win_data, ord[j].win_data_len);
466 if (t == 0){
467 fprintf(stderr, "CompareStringW error, error number %x\n", GetLastError());
468 exit(-1);
469 } else{
470 return t - CSTR_EQUAL;
471 }
472 }
473 #endif
474
475 #define BFUNC(name, func, data) \
476 int name(int32_t i, int32_t j) { \
477 return func(rnd[i].data, ord[j].data); \
478 }
479
480 BFUNC(posix_strcoll_null, strcoll, posix_data)
481 BFUNC(posix_cmpkey, strcmp, posix_key)
482 BFUNC(win_cmpkey, strcmp, win_key)
483 BFUNC(win_wcscmp, wcscmp, win_data)
484 BFUNC(icu_strcmp, u_strcmp, icu_data)
485 BFUNC(icu_cmpcpo, u_strcmpCodePointOrder, icu_data)
486 };
487
488 class CollPerfTest : public UPerfTest {
489 public:
490 UCollator * col;
491 DWORD win_langid;
492
493 UChar * icu_data_all;
494 int32_t icu_data_all_len;
495
496 int32_t count;
497 CA_uchar * icu_data;
498 CA_uint8 * icu_key;
499 CA_char * posix_data;
500 CA_char * posix_key;
501 CA_win_wchar * win_data;
502 CA_char * win_key;
503
504 DataIndex * rnd_index; // random by icu key
505 DataIndex * ord_win_data;
506 DataIndex * ord_win_key;
507 DataIndex * ord_posix_data;
508 DataIndex * ord_posix_key;
509 DataIndex * ord_icu_data;
510 DataIndex * ord_icu_key;
511 DataIndex * ord_win_wcscmp;
512 DataIndex * ord_icu_strcmp;
513 DataIndex * ord_icu_cmpcpo;
514
515 virtual ~CollPerfTest(){
516 ucol_close(col);
517 delete [] icu_data_all;
518 delete icu_data;
519 delete icu_key;
520 delete posix_data;
521 delete posix_key;
522 delete win_data;
523 delete win_key;
524 delete[] rnd_index;
525 delete[] ord_win_data;
526 delete[] ord_win_key;
527 delete[] ord_posix_data;
528 delete[] ord_posix_key;
529 delete[] ord_icu_data;
530 delete[] ord_icu_key;
531 delete[] ord_win_wcscmp;
532 delete[] ord_icu_strcmp;
533 delete[] ord_icu_cmpcpo;
534 }
535
536 CollPerfTest(int32_t argc, const char* argv[], UErrorCode& status):UPerfTest(argc, argv, status){
537 col = NULL;
538 icu_data_all = NULL;
539 icu_data = NULL;
540 icu_key = NULL;
541 posix_data = NULL;
542 posix_key = NULL;
543 win_data =NULL;
544 win_key = NULL;
545
546 rnd_index = NULL;
547 ord_win_data= NULL;
548 ord_win_key= NULL;
549 ord_posix_data= NULL;
550 ord_posix_key= NULL;
551 ord_icu_data= NULL;
552 ord_icu_key= NULL;
553 ord_win_wcscmp = NULL;
554 ord_icu_strcmp = NULL;
555 ord_icu_cmpcpo = NULL;
556
557 if (U_FAILURE(status)){
558 return;
559 }
560
561 // Parse additional arguments
562
563 UOption options[] = {
564 UOPTION_DEF("langid", 'i', UOPT_REQUIRES_ARG), // Windows Language ID number.
565 UOPTION_DEF("rulefile", 'r', UOPT_REQUIRES_ARG), // --rulefile <filename>
566 // Collation related arguments. All are optional.
567 // To simplify parsing, two choice arguments are disigned as NO_ARG.
568 // The default value is UPPER word in the comment
569 UOPTION_DEF("c_french", 'f', UOPT_NO_ARG), // --french <on | OFF>
570 UOPTION_DEF("c_alternate", 'a', UOPT_NO_ARG), // --alternate <NON_IGNORE | shifted>
571 UOPTION_DEF("c_casefirst", 'c', UOPT_REQUIRES_ARG), // --casefirst <lower | upper | OFF>
572 UOPTION_DEF("c_caselevel", 'l', UOPT_NO_ARG), // --caselevel <on | OFF>
573 UOPTION_DEF("c_normal", 'n', UOPT_NO_ARG), // --normal <on | OFF>
574 UOPTION_DEF("c_strength", 's', UOPT_REQUIRES_ARG), // --strength <1-5>
575 };
576 int32_t opt_len = UPRV_LENGTHOF(options);
577 enum {i, r,f,a,c,l,n,s}; // The buffer between the option items' order and their references
578
579 _remainingArgc = u_parseArgs(_remainingArgc, (char**)argv, opt_len, options);
580
581 if (_remainingArgc < 0){
582 status = U_ILLEGAL_ARGUMENT_ERROR;
583 return;
584 }
585
586 if (locale == NULL){
587 locale = "en_US"; // set default locale
588 }
589
590 #if U_PLATFORM_HAS_WIN32_API
591 if (options[i].doesOccur) {
592 char *endp;
593 int tmp = strtol(options[i].value, &endp, 0);
594 if (endp == options[i].value) {
595 status = U_ILLEGAL_ARGUMENT_ERROR;
596 return;
597 }
598 win_langid = MAKELCID(tmp, SORT_DEFAULT);
599 } else {
600 win_langid = uloc_getLCID(locale);
601 }
602 #endif
603
604 // Set up an ICU collator
605 if (options[r].doesOccur) {
606 // TODO: implement it
607 } else {
608 col = ucol_open(locale, &status);
609 if (U_FAILURE(status)) {
610 return;
611 }
612 }
613
614 if (options[f].doesOccur) {
615 ucol_setAttribute(col, UCOL_FRENCH_COLLATION, UCOL_ON, &status);
616 } else {
617 ucol_setAttribute(col, UCOL_FRENCH_COLLATION, UCOL_OFF, &status);
618 }
619
620 if (options[a].doesOccur) {
621 ucol_setAttribute(col, UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, &status);
622 }
623
624 if (options[c].doesOccur) { // strcmp() has i18n encoding problem
625 if (strcmp("lower", options[c].value) == 0){
626 ucol_setAttribute(col, UCOL_CASE_FIRST, UCOL_LOWER_FIRST, &status);
627 } else if (strcmp("upper", options[c].value) == 0) {
628 ucol_setAttribute(col, UCOL_CASE_FIRST, UCOL_UPPER_FIRST, &status);
629 } else {
630 status = U_ILLEGAL_ARGUMENT_ERROR;
631 return;
632 }
633 }
634
635 if (options[l].doesOccur){
636 ucol_setAttribute(col, UCOL_CASE_LEVEL, UCOL_ON, &status);
637 }
638
639 if (options[n].doesOccur){
640 ucol_setAttribute(col, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
641 }
642
643 if (options[s].doesOccur) {
644 char *endp;
645 int tmp = strtol(options[l].value, &endp, 0);
646 if (endp == options[l].value) {
647 status = U_ILLEGAL_ARGUMENT_ERROR;
648 return;
649 }
650 switch (tmp) {
651 case 1: ucol_setAttribute(col, UCOL_STRENGTH, UCOL_PRIMARY, &status); break;
652 case 2: ucol_setAttribute(col, UCOL_STRENGTH, UCOL_SECONDARY, &status); break;
653 case 3: ucol_setAttribute(col, UCOL_STRENGTH, UCOL_TERTIARY, &status); break;
654 case 4: ucol_setAttribute(col, UCOL_STRENGTH, UCOL_QUATERNARY, &status); break;
655 case 5: ucol_setAttribute(col, UCOL_STRENGTH, UCOL_IDENTICAL, &status); break;
656 default: status = U_ILLEGAL_ARGUMENT_ERROR; return;
657 }
658 }
659 prepareData(status);
660 }
661
662 //to avoid use the annoying 'id' in TESTCASE(id,test) macro or the like
663 #define TEST(testname, classname, arg1, arg2, arg3, arg4, arg5, arg6) \
664 if(temp == index) {\
665 name = #testname;\
666 if (exec) {\
667 UErrorCode status = U_ZERO_ERROR;\
668 UPerfFunction * t = new classname(status,arg1, arg2, arg3, arg4, arg5, arg6);\
669 if (U_FAILURE(status)) {\
670 delete t;\
671 return NULL;\
672 } else {\
673 return t;\
674 }\
675 } else {\
676 return NULL;\
677 }\
678 }\
679 temp++\
680
681
682 virtual UPerfFunction* runIndexedTest( /*[in]*/int32_t index, /*[in]*/UBool exec, /*[out]*/const char* &name, /*[in]*/ char* par = NULL ){
683 int temp = 0;
684
685 #define TEST_KEYGEN(testname, func)\
686 TEST(testname, CmdKeyGen, col, win_langid, count, rnd_index, &CmdKeyGen::func, 0)
687 TEST_KEYGEN(TestIcu_KeyGen_null, icu_key_null);
688 TEST_KEYGEN(TestIcu_KeyGen_len, icu_key_len);
689 TEST_KEYGEN(TestPosix_KeyGen_null, posix_key_null);
690 #if U_PLATFORM_HAS_WIN32_API
691 TEST_KEYGEN(TestWin_KeyGen_null, win_key_null);
692 TEST_KEYGEN(TestWin_KeyGen_len, win_key_len);
693 #endif
694
695 #define TEST_ITER(testname, func)\
696 TEST(testname, CmdIter, col, count, icu_data, &CmdIter::func,0,0)
697 TEST_ITER(TestIcu_ForwardIter_null, icu_forward_null);
698 TEST_ITER(TestIcu_ForwardIter_len, icu_forward_len);
699 TEST_ITER(TestIcu_BackwardIter_null, icu_backward_null);
700 TEST_ITER(TestIcu_BackwardIter_len, icu_backward_len);
701
702 #define TEST_ITER_ALL(testname, func)\
703 TEST(testname, CmdIterAll, col, icu_data_all_len, icu_data_all, CmdIterAll::func,0,0)
704 TEST_ITER_ALL(TestIcu_ForwardIter_all_null, forward_null);
705 TEST_ITER_ALL(TestIcu_ForwardIter_all_len, forward_len);
706 TEST_ITER_ALL(TestIcu_BackwardIter_all_null, backward_null);
707 TEST_ITER_ALL(TestIcu_BackwardIter_all_len, backward_len);
708
709 #define TEST_QSORT(testname, func)\
710 TEST(testname, CmdQsort, rnd_index, count, sizeof(DataIndex), CmdQsort::func,0,0)
711 TEST_QSORT(TestIcu_qsort_strcoll_null, icu_strcoll_null);
712 TEST_QSORT(TestIcu_qsort_strcoll_len, icu_strcoll_len);
713 TEST_QSORT(TestIcu_qsort_usekey, icu_cmpkey);
714 TEST_QSORT(TestPosix_qsort_strcoll_null, posix_strcoll_null);
715 TEST_QSORT(TestPosix_qsort_usekey, posix_cmpkey);
716 #if U_PLATFORM_HAS_WIN32_API
717 TEST_QSORT(TestWin_qsort_CompareStringW_null, win_cmp_null);
718 TEST_QSORT(TestWin_qsort_CompareStringW_len, win_cmp_len);
719 TEST_QSORT(TestWin_qsort_usekey, win_cmpkey);
720 #endif
721
722 #define TEST_BIN(testname, func)\
723 TEST(testname, CmdBinSearch, col, win_langid, count, rnd_index, ord_icu_key, &CmdBinSearch::func)
724 TEST_BIN(TestIcu_BinarySearch_strcoll_null, icu_strcoll_null);
725 TEST_BIN(TestIcu_BinarySearch_strcoll_len, icu_strcoll_len);
726 TEST_BIN(TestIcu_BinarySearch_usekey, icu_cmpkey);
727 TEST_BIN(TestIcu_BinarySearch_strcmp, icu_strcmp);
728 TEST_BIN(TestIcu_BinarySearch_cmpCPO, icu_cmpcpo);
729 TEST_BIN(TestPosix_BinarySearch_strcoll_null, posix_strcoll_null);
730 TEST_BIN(TestPosix_BinarySearch_usekey, posix_cmpkey);
731 #if U_PLATFORM_HAS_WIN32_API
732 TEST_BIN(TestWin_BinarySearch_CompareStringW_null, win_cmp_null);
733 TEST_BIN(TestWin_BinarySearch_CompareStringW_len, win_cmp_len);
734 #endif
735 TEST_BIN(TestWin_BinarySearch_usekey, win_cmpkey);
736 TEST_BIN(TestWin_BinarySearch_wcscmp, win_wcscmp);
737
738 name="";
739 return NULL;
740 }
741
742
743
744 void prepareData(UErrorCode& status){
745 if(U_FAILURE(status)) return;
746 if (icu_data) return; // prepared
747
748 icu_data = new CA_uchar();
749
750 // Following code is borrowed from UPerfTest::getLines();
751 const UChar* line=NULL;
752 int32_t len =0;
753 for (;;) {
754 line = ucbuf_readline(ucharBuf,&len,&status);
755 if(line == NULL || U_FAILURE(status)){break;}
756
757 // Refer to the source code of ucbuf_readline()
758 // 1. 'len' includs the line terminal symbols
759 // 2. The length of the line terminal symbols is only one character
760 // 3. The Windows CR LF line terminal symbols will be converted to CR
761
762 if (len == 1) {
763 continue; //skip empty line
764 } else {
765 icu_data->append_one(len);
766 memcpy(icu_data->last(), line, len * sizeof(UChar));
767 icu_data->last()[len -1] = NULL;
768 }
769 }
770 if(U_FAILURE(status)) return;
771
772 // UTF-16 -> UTF-8 conversion.
773 UConverter *conv = ucnv_open("utf-8", &status); // just UTF-8 for now.
774 if (U_FAILURE(status)) return;
775
776 count = icu_data->count;
777
778 icu_data_all_len = icu_data->index[count]; // includes all NULLs
779 icu_data_all_len -= count; // excludes all NULLs
780 icu_data_all_len += 1; // the terminal NULL
781 icu_data_all = new UChar[icu_data_all_len];
782 icu_data_all[icu_data_all_len - 1] = 0; //the terminal NULL
783
784 icu_key = new CA_uint8;
785 win_data = new CA_win_wchar;
786 win_key = new CA_char;
787 posix_data = new CA_char;
788 posix_key = new CA_char;
789 rnd_index = new DataIndex[count];
790 DataIndex::win_langid = win_langid;
791 DataIndex::col = col;
792
793
794 UChar * p = icu_data_all;
795 int32_t s;
796 int32_t t;
797 for (int i=0; i < count; i++) {
798 // ICU all data
799 s = sizeof(UChar) * icu_data->lengthOf(i);
800 memcpy(p, icu_data->dataOf(i), s);
801 p += icu_data->lengthOf(i);
802
803 // ICU data
804
805 // ICU key
806 s = ucol_getSortKey(col, icu_data->dataOf(i), -1,NULL, 0);
807 icu_key->append_one(s);
808 t = ucol_getSortKey(col, icu_data->dataOf(i), -1,icu_key->last(), s);
809 if (t != s) {status = U_INVALID_FORMAT_ERROR;return;}
810
811 // POSIX data
812 s = ucnv_fromUChars(conv,NULL, 0, icu_data->dataOf(i), icu_data->lengthOf(i), &status);
813 if (status == U_BUFFER_OVERFLOW_ERROR || status == U_ZERO_ERROR){
814 status = U_ZERO_ERROR;
815 } else {
816 return;
817 }
818 posix_data->append_one(s + 1); // plus terminal NULL
819 t = ucnv_fromUChars(conv,posix_data->last(), s, icu_data->dataOf(i), icu_data->lengthOf(i), &status);
820 if (U_FAILURE(status)) return;
821 if ( t != s){status = U_INVALID_FORMAT_ERROR;return;}
822 posix_data->last()[s] = 0;
823
824 // POSIX key
825 s = strxfrm(NULL, posix_data->dataOf(i), 0);
826 if (s == INT_MAX){status = U_INVALID_FORMAT_ERROR;return;}
827 posix_key->append_one(s);
828 t = strxfrm(posix_key->last(), posix_data->dataOf(i), s);
829 if (t != s) {status = U_INVALID_FORMAT_ERROR;return;}
830
831 #if U_PLATFORM_HAS_WIN32_API
832 // Win data
833 s = icu_data->lengthOf(i) + 1; // plus terminal NULL
834 win_data->append_one(s);
835 memcpy(win_data->last(), icu_data->dataOf(i), sizeof(WCHAR) * s);
836
837 // Win key
838 s = LCMapStringW(win_langid, LCMAP_SORTKEY, win_data->dataOf(i), win_data->lengthOf(i), NULL,0);
839 if (s == 0) {status = U_INVALID_FORMAT_ERROR;return;}
840 win_key->append_one(s);
841 t = LCMapStringW(win_langid, LCMAP_SORTKEY, win_data->dataOf(i), win_data->lengthOf(i), (WCHAR *)(win_key->last()),s);
842 if (t != s) {status = U_INVALID_FORMAT_ERROR;return;}
843 #endif
844 };
845
846 // append_one() will make points shifting, should not merge following code into previous iteration
847 for (int i=0; i < count; i++) {
848 rnd_index[i].icu_key = icu_key->dataOf(i);
849 rnd_index[i].icu_data = icu_data->dataOf(i);
850 rnd_index[i].icu_data_len = icu_data->lengthOf(i);
851 rnd_index[i].posix_key = posix_key->last();
852 rnd_index[i].posix_data = posix_data->dataOf(i);
853 rnd_index[i].posix_data_len = posix_data->lengthOf(i);
854 #if U_PLATFORM_HAS_WIN32_API
855 rnd_index[i].win_key = win_key->dataOf(i);
856 rnd_index[i].win_data = win_data->dataOf(i);
857 rnd_index[i].win_data_len = win_data->lengthOf(i);
858 #endif
859 };
860
861 ucnv_close(conv);
862 qsort(rnd_index, count, sizeof(DataIndex), CmdQsort::q_random);
863
864 #define SORT(data, func) \
865 data = new DataIndex[count];\
866 memcpy(data, rnd_index, count * sizeof(DataIndex));\
867 qsort(data, count, sizeof(DataIndex), CmdQsort::func)
868
869 SORT(ord_icu_data, icu_strcoll_len);
870 SORT(ord_icu_key, icu_cmpkey);
871 SORT(ord_posix_data, posix_strcoll_null);
872 SORT(ord_posix_key, posix_cmpkey);
873 #if U_PLATFORM_HAS_WIN32_API
874 SORT(ord_win_data, win_cmp_len);
875 SORT(ord_win_key, win_cmpkey);
876 SORT(ord_win_wcscmp, win_wcscmp);
877 #endif
878 SORT(ord_icu_strcmp, icu_strcmp);
879 SORT(ord_icu_cmpcpo, icu_cmpcpo);
880 }
881 };
882
883
884 int main(int argc, const char *argv[])
885 {
886
887 UErrorCode status = U_ZERO_ERROR;
888 CollPerfTest test(argc, argv, status);
889
890 if (U_FAILURE(status)){
891 printf("The error is %s\n", u_errorName(status));
892 //TODO: print usage here
893 return status;
894 }
895
896 if (test.run() == FALSE){
897 fprintf(stderr, "FAILED: Tests could not be run please check the "
898 "arguments.\n");
899 return -1;
900 }
901 return 0;
902 }
903