1 /***********************************************************************
2 * © 2016 and later: Unicode, Inc. and others.
3 * License & terms of use: http://www.unicode.org/copyright.html#License
5 ***********************************************************************
6 ***********************************************************************
8 * Copyright (C) 2001-2016 IBM, Inc. All Rights Reserved.
10 ***********************************************************************/
18 #include "unicode/uperf.h"
20 #include "unicode/coll.h"
21 #include <unicode/ucoleitr.h>
23 #if !U_PLATFORM_HAS_WIN32_API
24 #define DWORD uint32_t
28 /* To store an array of string<UNIT> in continue space.
29 Since string<UNIT> itself is treated as an array of UNIT, this
30 class will ease our memory management for an array of string<UNIT>.
33 //template<typename UNIT>
34 #define COMPATCT_ARRAY(CompactArrays, UNIT) \
35 struct CompactArrays{\
36 CompactArrays(const CompactArrays & );\
37 CompactArrays & operator=(const CompactArrays & );\
38 int32_t count;/*total number of the strings*/ \
39 int32_t * index;/*relative offset in data*/ \
40 UNIT * data; /*the real space to hold strings*/ \
42 ~CompactArrays(){free(index);free(data);} \
43 CompactArrays():data(NULL), index(NULL), count(0){ \
44 index = (int32_t *) realloc(index, sizeof(int32_t)); \
47 void append_one(int32_t theLen){ /*include terminal NULL*/ \
49 index = (int32_t *) realloc(index, sizeof(int32_t) * (count + 1)); \
50 index[count] = index[count - 1] + theLen; \
51 data = (UNIT *) realloc(data, sizeof(UNIT) * index[count]); \
53 UNIT * last(){return data + index[count - 1];} \
54 UNIT * dataOf(int32_t i){return data + index[i];} \
55 int32_t lengthOf(int i){return index[i+1] - index[i] - 1; } /*exclude terminating NULL*/ \
58 //typedef CompactArrays<UChar> CA_uchar;
59 //typedef CompactArrays<char> CA_char;
60 //typedef CompactArrays<uint8_t> CA_uint8;
61 //typedef CompactArrays<WCHAR> CA_win_wchar;
63 COMPATCT_ARRAY(CA_uchar
, UChar
)
64 COMPATCT_ARRAY(CA_char
, char)
65 COMPATCT_ARRAY(CA_uint8
, uint8_t)
66 COMPATCT_ARRAY(CA_win_wchar
, WCHAR
)
70 static DWORD win_langid
; // for qsort callback function
71 static UCollator
* col
; // for qsort callback function
77 int32_t posix_data_len
;
82 DWORD
DataIndex::win_langid
;
83 UCollator
* DataIndex::col
;
87 class CmdKeyGen
: public UPerfFunction
{
88 typedef void (CmdKeyGen::* Func
)(int32_t);
89 enum{MAX_KEY_LENGTH
= 5000};
96 union { // to save sapce
97 uint8_t icu_key
[MAX_KEY_LENGTH
];
98 char posix_key
[MAX_KEY_LENGTH
];
99 WCHAR win_key
[MAX_KEY_LENGTH
];
102 CmdKeyGen(UErrorCode
, UCollator
* col
,DWORD win_langid
, int32_t count
, DataIndex
* data
,Func fn
,int32_t)
103 :col(col
),win_langid(win_langid
), count(count
), data(data
), fn(fn
){}
105 virtual long getOperationsPerIteration(){return count
;}
107 virtual void call(UErrorCode
* status
){
108 for(int32_t i
= 0; i
< count
; i
++){
113 void icu_key_null(int32_t i
){
114 ucol_getSortKey(col
, data
[i
].icu_data
, -1, icu_key
, MAX_KEY_LENGTH
);
117 void icu_key_len(int32_t i
){
118 ucol_getSortKey(col
, data
[i
].icu_data
, data
[i
].icu_data_len
, icu_key
, MAX_KEY_LENGTH
);
121 #if U_PLATFORM_HAS_WIN32_API
122 // pre-generated in CollPerfTest::prepareData(), need not to check error here
123 void win_key_null(int32_t i
){
124 //LCMAP_SORTsk 0x00000400 // WC sort sk (normalize)
125 LCMapStringW(win_langid
, LCMAP_SORTKEY
, data
[i
].win_data
, -1, win_key
, MAX_KEY_LENGTH
);
128 void win_key_len(int32_t i
){
129 LCMapStringW(win_langid
, LCMAP_SORTKEY
, data
[i
].win_data
, data
[i
].win_data_len
, win_key
, MAX_KEY_LENGTH
);
133 void posix_key_null(int32_t i
){
134 strxfrm(posix_key
, data
[i
].posix_data
, MAX_KEY_LENGTH
);
139 class CmdIter
: public UPerfFunction
{
140 typedef void (CmdIter::* Func
)(UErrorCode
* , int32_t );
144 UCollationElements
*iter
;
147 CmdIter(UErrorCode
& status
, UCollator
* col
, int32_t count
, CA_uchar
*data
, Func fn
, int32_t,int32_t)
148 :count(count
), data(data
), fn(fn
){
150 UChar dummytext
[] = {0, 0};
151 iter
= ucol_openElements(col
, NULL
, 0, &status
);
152 ucol_setText(iter
, dummytext
, 1, &status
);
155 ucol_closeElements(iter
);
158 virtual long getOperationsPerIteration(){return exec_count
? exec_count
: 1;}
160 virtual void call(UErrorCode
* status
){
162 for(int32_t i
= 0; i
< count
; i
++){
163 (this->*fn
)(status
, i
);
167 void icu_forward_null(UErrorCode
* status
, int32_t i
){
168 ucol_setText(iter
, data
->dataOf(i
), -1, status
);
169 while (ucol_next(iter
, status
) != UCOL_NULLORDER
) exec_count
++;
172 void icu_forward_len(UErrorCode
* status
, int32_t i
){
173 ucol_setText(iter
, data
->dataOf(i
), data
->lengthOf(i
) , status
);
174 while (ucol_next(iter
, status
) != UCOL_NULLORDER
) exec_count
++;
177 void icu_backward_null(UErrorCode
* status
, int32_t i
){
178 ucol_setText(iter
, data
->dataOf(i
), -1, status
);
179 while (ucol_previous(iter
, status
) != UCOL_NULLORDER
) exec_count
++;
182 void icu_backward_len(UErrorCode
* status
, int32_t i
){
183 ucol_setText(iter
, data
->dataOf(i
), data
->lengthOf(i
) , status
);
184 while (ucol_previous(iter
, status
) != UCOL_NULLORDER
) exec_count
++;
188 class CmdIterAll
: public UPerfFunction
{
189 typedef void (CmdIterAll::* Func
)(UErrorCode
* status
);
193 UCollationElements
*iter
;
197 enum CALL
{forward_null
, forward_len
, backward_null
, backward_len
};
200 ucol_closeElements(iter
);
202 CmdIterAll(UErrorCode
& status
, UCollator
* col
, int32_t count
, UChar
* data
, CALL call
,int32_t,int32_t)
203 :count(count
),data(data
)
206 if (call
== forward_null
|| call
== backward_null
) {
207 iter
= ucol_openElements(col
, data
, -1, &status
);
209 iter
= ucol_openElements(col
, data
, count
, &status
);
212 if (call
== forward_null
|| call
== forward_len
){
213 fn
= &CmdIterAll::icu_forward_all
;
215 fn
= &CmdIterAll::icu_backward_all
;
218 virtual long getOperationsPerIteration(){return exec_count
? exec_count
: 1;}
220 virtual void call(UErrorCode
* status
){
224 void icu_forward_all(UErrorCode
* status
){
225 int strlen
= count
- 5;
228 ucol_setOffset(iter
, strindex
, status
);
230 if (ucol_next(iter
, status
) == UCOL_NULLORDER
) {
237 if (strindex
> strlen
) {
240 ucol_setOffset(iter
, strindex
, status
);
246 void icu_backward_all(UErrorCode
* status
){
250 ucol_setOffset(iter
, strindex
, status
);
252 if (ucol_previous(iter
, status
) == UCOL_NULLORDER
) {
259 if (strindex
> strlen
) {
262 ucol_setOffset(iter
, strindex
, status
);
270 struct CmdQsort
: public UPerfFunction
{
272 static int q_random(const void * a
, const void * b
){
273 uint8_t * key_a
= ((DataIndex
*)a
)->icu_key
;
274 uint8_t * key_b
= ((DataIndex
*)b
)->icu_key
;
278 while (*key_a
!= 0) {val_a
+= val_a
*37 + *key_a
++;}
279 while (*key_b
!= 0) {val_b
+= val_b
*37 + *key_b
++;}
280 return val_a
- val_b
;
284 DataIndex * da = (DataIndex *) a; \
285 DataIndex * db = (DataIndex *) b; \
288 static int icu_strcoll_null(const void *a
, const void *b
){
290 return ucol_strcoll(da
->col
, da
->icu_data
, -1, db
->icu_data
, -1) - UCOL_EQUAL
;
293 static int icu_strcoll_len(const void *a
, const void *b
){
295 return ucol_strcoll(da
->col
, da
->icu_data
, da
->icu_data_len
, db
->icu_data
, db
->icu_data_len
) - UCOL_EQUAL
;
298 static int icu_cmpkey (const void *a
, const void *b
){
300 return strcmp((char *) da
->icu_key
, (char *) db
->icu_key
);
303 #if U_PLATFORM_HAS_WIN32_API
304 static int win_cmp_null(const void *a
, const void *b
) {
308 //CSTR_GREATER_THAN 3
309 int t
= CompareStringW(da
->win_langid
, 0, da
->win_data
, -1, db
->win_data
, -1);
311 fprintf(stderr
, "CompareStringW error, error number %x\n", GetLastError());
314 return t
- CSTR_EQUAL
;
318 static int win_cmp_len(const void *a
, const void *b
) {
320 int t
= CompareStringW(da
->win_langid
, 0, da
->win_data
, da
->win_data_len
, db
->win_data
, db
->win_data_len
);
322 fprintf(stderr
, "CompareStringW error, error number %x\n", GetLastError());
325 return t
- CSTR_EQUAL
;
330 #define QFUNC(name, func, data) \
331 static int name (const void *a, const void *b){ \
333 return func(da->data, db->data); \
336 QFUNC(posix_strcoll_null
, strcoll
, posix_data
)
337 QFUNC(posix_cmpkey
, strcmp
, posix_key
)
338 #if U_PLATFORM_HAS_WIN32_API
339 QFUNC(win_cmpkey
, strcmp
, win_key
)
340 QFUNC(win_wcscmp
, wcscmp
, win_data
)
342 QFUNC(icu_strcmp
, u_strcmp
, icu_data
)
343 QFUNC(icu_cmpcpo
, u_strcmpCodePointOrder
, icu_data
)
346 static int32_t exec_count
; // potential muilt-thread problem
348 typedef int (* Func
)(const void *, const void *);
351 void * base
; //Start of target array.
352 int32_t num
; //Array size in elements.
353 int32_t width
; //Element size in bytes.
355 void * backup
; //copy source of base
357 CmdQsort(UErrorCode
& status
,void *theBase
, int32_t num
, int32_t width
, Func fn
, int32_t,int32_t)
358 :backup(theBase
),num(num
),width(width
),fn(fn
){
359 base
= malloc(num
* width
);
360 time_empty(100, &status
); // warm memory/cache
369 memcpy(base
, backup
, num
* width
);
372 double time_empty(int32_t n
, UErrorCode
* status
) {
374 utimer_getTime(&start
);
378 utimer_getTime(&stop
);
379 return utimer_getDeltaSeconds(&start
,&stop
); // ms
382 virtual void call(UErrorCode
* status
){
384 memcpy(base
, backup
, num
* width
);
385 qsort(base
, num
, width
, fn
);
387 virtual double time(int32_t n
, UErrorCode
* status
) {
388 double t1
= time_empty(n
,status
);
389 double t2
= UPerfFunction::time(n
, status
);
390 return t2
-t1
;// < 0 ? t2 : t2-t1;
393 virtual long getOperationsPerIteration(){ return exec_count
?exec_count
:1;}
395 int32_t CmdQsort::exec_count
;
398 class CmdBinSearch
: public UPerfFunction
{
400 typedef int (CmdBinSearch::* Func
)(int, int);
410 CmdBinSearch(UErrorCode
, UCollator
* col
,DWORD win_langid
,int32_t count
,DataIndex
* rnd
,DataIndex
* ord
,Func fn
)
411 :col(col
),win_langid(win_langid
), count(count
), rnd(rnd
), ord(ord
), fn(fn
),exec_count(0){}
414 virtual void call(UErrorCode
* status
){
416 for(int32_t i
= 0; i
< count
; i
++){ // search all data
420 virtual long getOperationsPerIteration(){ return exec_count
?exec_count
:1;}
422 void binary_search(int32_t random
) {
424 int high
= count
- 1;
429 guess
= (high
+ low
)/2;
430 if (last_guess
== guess
) break; // nothing to search
432 r
= (this->*fn
)(random
, guess
);
436 return; // found, search end.
446 int icu_strcoll_null(int32_t i
, int32_t j
){
447 return ucol_strcoll(col
, rnd
[i
].icu_data
, -1, ord
[j
].icu_data
,-1);
450 int icu_strcoll_len(int32_t i
, int32_t j
){
451 return ucol_strcoll(col
, rnd
[i
].icu_data
, rnd
[i
].icu_data_len
, ord
[j
].icu_data
, ord
[j
].icu_data_len
);
454 int icu_cmpkey(int32_t i
, int32_t j
) {
455 return strcmp( (char *) rnd
[i
].icu_key
, (char *) ord
[j
].icu_key
);
458 #if U_PLATFORM_HAS_WIN32_API
459 int win_cmp_null(int32_t i
, int32_t j
) {
460 int t
= CompareStringW(win_langid
, 0, rnd
[i
].win_data
, -1, ord
[j
].win_data
, -1);
462 fprintf(stderr
, "CompareStringW error, error number %x\n", GetLastError());
465 return t
- CSTR_EQUAL
;
469 int win_cmp_len(int32_t i
, int32_t j
) {
470 int t
= CompareStringW(win_langid
, 0, rnd
[i
].win_data
, rnd
[i
].win_data_len
, ord
[j
].win_data
, ord
[j
].win_data_len
);
472 fprintf(stderr
, "CompareStringW error, error number %x\n", GetLastError());
475 return t
- CSTR_EQUAL
;
480 #define BFUNC(name, func, data) \
481 int name(int32_t i, int32_t j) { \
482 return func(rnd[i].data, ord[j].data); \
485 BFUNC(posix_strcoll_null
, strcoll
, posix_data
)
486 BFUNC(posix_cmpkey
, strcmp
, posix_key
)
487 BFUNC(win_cmpkey
, strcmp
, win_key
)
488 BFUNC(win_wcscmp
, wcscmp
, win_data
)
489 BFUNC(icu_strcmp
, u_strcmp
, icu_data
)
490 BFUNC(icu_cmpcpo
, u_strcmpCodePointOrder
, icu_data
)
493 class CollPerfTest
: public UPerfTest
{
498 UChar
* icu_data_all
;
499 int32_t icu_data_all_len
;
504 CA_char
* posix_data
;
506 CA_win_wchar
* win_data
;
509 DataIndex
* rnd_index
; // random by icu key
510 DataIndex
* ord_win_data
;
511 DataIndex
* ord_win_key
;
512 DataIndex
* ord_posix_data
;
513 DataIndex
* ord_posix_key
;
514 DataIndex
* ord_icu_data
;
515 DataIndex
* ord_icu_key
;
516 DataIndex
* ord_win_wcscmp
;
517 DataIndex
* ord_icu_strcmp
;
518 DataIndex
* ord_icu_cmpcpo
;
520 virtual ~CollPerfTest(){
522 delete [] icu_data_all
;
530 delete[] ord_win_data
;
531 delete[] ord_win_key
;
532 delete[] ord_posix_data
;
533 delete[] ord_posix_key
;
534 delete[] ord_icu_data
;
535 delete[] ord_icu_key
;
536 delete[] ord_win_wcscmp
;
537 delete[] ord_icu_strcmp
;
538 delete[] ord_icu_cmpcpo
;
541 CollPerfTest(int32_t argc
, const char* argv
[], UErrorCode
& status
):UPerfTest(argc
, argv
, status
){
554 ord_posix_data
= NULL
;
558 ord_win_wcscmp
= NULL
;
559 ord_icu_strcmp
= NULL
;
560 ord_icu_cmpcpo
= NULL
;
562 if (U_FAILURE(status
)){
566 // Parse additional arguments
568 UOption options
[] = {
569 UOPTION_DEF("langid", 'i', UOPT_REQUIRES_ARG
), // Windows Language ID number.
570 UOPTION_DEF("rulefile", 'r', UOPT_REQUIRES_ARG
), // --rulefile <filename>
571 // Collation related arguments. All are optional.
572 // To simplify parsing, two choice arguments are disigned as NO_ARG.
573 // The default value is UPPER word in the comment
574 UOPTION_DEF("c_french", 'f', UOPT_NO_ARG
), // --french <on | OFF>
575 UOPTION_DEF("c_alternate", 'a', UOPT_NO_ARG
), // --alternate <NON_IGNORE | shifted>
576 UOPTION_DEF("c_casefirst", 'c', UOPT_REQUIRES_ARG
), // --casefirst <lower | upper | OFF>
577 UOPTION_DEF("c_caselevel", 'l', UOPT_NO_ARG
), // --caselevel <on | OFF>
578 UOPTION_DEF("c_normal", 'n', UOPT_NO_ARG
), // --normal <on | OFF>
579 UOPTION_DEF("c_strength", 's', UOPT_REQUIRES_ARG
), // --strength <1-5>
581 int32_t opt_len
= UPRV_LENGTHOF(options
);
582 enum {i
, r
,f
,a
,c
,l
,n
,s
}; // The buffer between the option items' order and their references
584 _remainingArgc
= u_parseArgs(_remainingArgc
, (char**)argv
, opt_len
, options
);
586 if (_remainingArgc
< 0){
587 status
= U_ILLEGAL_ARGUMENT_ERROR
;
592 locale
= "en_US"; // set default locale
595 #if U_PLATFORM_HAS_WIN32_API
596 if (options
[i
].doesOccur
) {
598 int tmp
= strtol(options
[i
].value
, &endp
, 0);
599 if (endp
== options
[i
].value
) {
600 status
= U_ILLEGAL_ARGUMENT_ERROR
;
603 win_langid
= MAKELCID(tmp
, SORT_DEFAULT
);
605 win_langid
= uloc_getLCID(locale
);
609 // Set up an ICU collator
610 if (options
[r
].doesOccur
) {
611 // TODO: implement it
613 col
= ucol_open(locale
, &status
);
614 if (U_FAILURE(status
)) {
619 if (options
[f
].doesOccur
) {
620 ucol_setAttribute(col
, UCOL_FRENCH_COLLATION
, UCOL_ON
, &status
);
622 ucol_setAttribute(col
, UCOL_FRENCH_COLLATION
, UCOL_OFF
, &status
);
625 if (options
[a
].doesOccur
) {
626 ucol_setAttribute(col
, UCOL_ALTERNATE_HANDLING
, UCOL_SHIFTED
, &status
);
629 if (options
[c
].doesOccur
) { // strcmp() has i18n encoding problem
630 if (strcmp("lower", options
[c
].value
) == 0){
631 ucol_setAttribute(col
, UCOL_CASE_FIRST
, UCOL_LOWER_FIRST
, &status
);
632 } else if (strcmp("upper", options
[c
].value
) == 0) {
633 ucol_setAttribute(col
, UCOL_CASE_FIRST
, UCOL_UPPER_FIRST
, &status
);
635 status
= U_ILLEGAL_ARGUMENT_ERROR
;
640 if (options
[l
].doesOccur
){
641 ucol_setAttribute(col
, UCOL_CASE_LEVEL
, UCOL_ON
, &status
);
644 if (options
[n
].doesOccur
){
645 ucol_setAttribute(col
, UCOL_NORMALIZATION_MODE
, UCOL_ON
, &status
);
648 if (options
[s
].doesOccur
) {
650 int tmp
= strtol(options
[l
].value
, &endp
, 0);
651 if (endp
== options
[l
].value
) {
652 status
= U_ILLEGAL_ARGUMENT_ERROR
;
656 case 1: ucol_setAttribute(col
, UCOL_STRENGTH
, UCOL_PRIMARY
, &status
); break;
657 case 2: ucol_setAttribute(col
, UCOL_STRENGTH
, UCOL_SECONDARY
, &status
); break;
658 case 3: ucol_setAttribute(col
, UCOL_STRENGTH
, UCOL_TERTIARY
, &status
); break;
659 case 4: ucol_setAttribute(col
, UCOL_STRENGTH
, UCOL_QUATERNARY
, &status
); break;
660 case 5: ucol_setAttribute(col
, UCOL_STRENGTH
, UCOL_IDENTICAL
, &status
); break;
661 default: status
= U_ILLEGAL_ARGUMENT_ERROR
; return;
667 //to avoid use the annoying 'id' in TESTCASE(id,test) macro or the like
668 #define TEST(testname, classname, arg1, arg2, arg3, arg4, arg5, arg6) \
672 UErrorCode status = U_ZERO_ERROR;\
673 UPerfFunction * t = new classname(status,arg1, arg2, arg3, arg4, arg5, arg6);\
674 if (U_FAILURE(status)) {\
687 virtual UPerfFunction* runIndexedTest( /*[in]*/int32_t index, /*[in]*/UBool exec, /*[out]*/const char* &name, /*[in]*/ char* par = NULL ){
690 #define TEST_KEYGEN(testname, func)\
691 TEST(testname, CmdKeyGen, col, win_langid, count, rnd_index, &CmdKeyGen::func, 0)
692 TEST_KEYGEN(TestIcu_KeyGen_null
, icu_key_null
);
693 TEST_KEYGEN(TestIcu_KeyGen_len
, icu_key_len
);
694 TEST_KEYGEN(TestPosix_KeyGen_null
, posix_key_null
);
695 #if U_PLATFORM_HAS_WIN32_API
696 TEST_KEYGEN(TestWin_KeyGen_null
, win_key_null
);
697 TEST_KEYGEN(TestWin_KeyGen_len
, win_key_len
);
700 #define TEST_ITER(testname, func)\
701 TEST(testname, CmdIter, col, count, icu_data, &CmdIter::func,0,0)
702 TEST_ITER(TestIcu_ForwardIter_null
, icu_forward_null
);
703 TEST_ITER(TestIcu_ForwardIter_len
, icu_forward_len
);
704 TEST_ITER(TestIcu_BackwardIter_null
, icu_backward_null
);
705 TEST_ITER(TestIcu_BackwardIter_len
, icu_backward_len
);
707 #define TEST_ITER_ALL(testname, func)\
708 TEST(testname, CmdIterAll, col, icu_data_all_len, icu_data_all, CmdIterAll::func,0,0)
709 TEST_ITER_ALL(TestIcu_ForwardIter_all_null
, forward_null
);
710 TEST_ITER_ALL(TestIcu_ForwardIter_all_len
, forward_len
);
711 TEST_ITER_ALL(TestIcu_BackwardIter_all_null
, backward_null
);
712 TEST_ITER_ALL(TestIcu_BackwardIter_all_len
, backward_len
);
714 #define TEST_QSORT(testname, func)\
715 TEST(testname, CmdQsort, rnd_index, count, sizeof(DataIndex), CmdQsort::func,0,0)
716 TEST_QSORT(TestIcu_qsort_strcoll_null
, icu_strcoll_null
);
717 TEST_QSORT(TestIcu_qsort_strcoll_len
, icu_strcoll_len
);
718 TEST_QSORT(TestIcu_qsort_usekey
, icu_cmpkey
);
719 TEST_QSORT(TestPosix_qsort_strcoll_null
, posix_strcoll_null
);
720 TEST_QSORT(TestPosix_qsort_usekey
, posix_cmpkey
);
721 #if U_PLATFORM_HAS_WIN32_API
722 TEST_QSORT(TestWin_qsort_CompareStringW_null
, win_cmp_null
);
723 TEST_QSORT(TestWin_qsort_CompareStringW_len
, win_cmp_len
);
724 TEST_QSORT(TestWin_qsort_usekey
, win_cmpkey
);
727 #define TEST_BIN(testname, func)\
728 TEST(testname, CmdBinSearch, col, win_langid, count, rnd_index, ord_icu_key, &CmdBinSearch::func)
729 TEST_BIN(TestIcu_BinarySearch_strcoll_null
, icu_strcoll_null
);
730 TEST_BIN(TestIcu_BinarySearch_strcoll_len
, icu_strcoll_len
);
731 TEST_BIN(TestIcu_BinarySearch_usekey
, icu_cmpkey
);
732 TEST_BIN(TestIcu_BinarySearch_strcmp
, icu_strcmp
);
733 TEST_BIN(TestIcu_BinarySearch_cmpCPO
, icu_cmpcpo
);
734 TEST_BIN(TestPosix_BinarySearch_strcoll_null
, posix_strcoll_null
);
735 TEST_BIN(TestPosix_BinarySearch_usekey
, posix_cmpkey
);
736 #if U_PLATFORM_HAS_WIN32_API
737 TEST_BIN(TestWin_BinarySearch_CompareStringW_null
, win_cmp_null
);
738 TEST_BIN(TestWin_BinarySearch_CompareStringW_len
, win_cmp_len
);
740 TEST_BIN(TestWin_BinarySearch_usekey
, win_cmpkey
);
741 TEST_BIN(TestWin_BinarySearch_wcscmp
, win_wcscmp
);
749 void prepareData(UErrorCode
& status
){
750 if(U_FAILURE(status
)) return;
751 if (icu_data
) return; // prepared
753 icu_data
= new CA_uchar();
755 // Following code is borrowed from UPerfTest::getLines();
756 const UChar
* line
=NULL
;
759 line
= ucbuf_readline(ucharBuf
,&len
,&status
);
760 if(line
== NULL
|| U_FAILURE(status
)){break;}
762 // Refer to the source code of ucbuf_readline()
763 // 1. 'len' includs the line terminal symbols
764 // 2. The length of the line terminal symbols is only one character
765 // 3. The Windows CR LF line terminal symbols will be converted to CR
768 continue; //skip empty line
770 icu_data
->append_one(len
);
771 memcpy(icu_data
->last(), line
, len
* sizeof(UChar
));
772 icu_data
->last()[len
-1] = NULL
;
775 if(U_FAILURE(status
)) return;
777 // UTF-16 -> UTF-8 conversion.
778 UConverter
*conv
= ucnv_open("utf-8", &status
); // just UTF-8 for now.
779 if (U_FAILURE(status
)) return;
781 count
= icu_data
->count
;
783 icu_data_all_len
= icu_data
->index
[count
]; // includes all NULLs
784 icu_data_all_len
-= count
; // excludes all NULLs
785 icu_data_all_len
+= 1; // the terminal NULL
786 icu_data_all
= new UChar
[icu_data_all_len
];
787 icu_data_all
[icu_data_all_len
- 1] = 0; //the terminal NULL
789 icu_key
= new CA_uint8
;
790 win_data
= new CA_win_wchar
;
791 win_key
= new CA_char
;
792 posix_data
= new CA_char
;
793 posix_key
= new CA_char
;
794 rnd_index
= new DataIndex
[count
];
795 DataIndex::win_langid
= win_langid
;
796 DataIndex::col
= col
;
799 UChar
* p
= icu_data_all
;
802 for (int i
=0; i
< count
; i
++) {
804 s
= sizeof(UChar
) * icu_data
->lengthOf(i
);
805 memcpy(p
, icu_data
->dataOf(i
), s
);
806 p
+= icu_data
->lengthOf(i
);
811 s
= ucol_getSortKey(col
, icu_data
->dataOf(i
), -1,NULL
, 0);
812 icu_key
->append_one(s
);
813 t
= ucol_getSortKey(col
, icu_data
->dataOf(i
), -1,icu_key
->last(), s
);
814 if (t
!= s
) {status
= U_INVALID_FORMAT_ERROR
;return;}
817 s
= ucnv_fromUChars(conv
,NULL
, 0, icu_data
->dataOf(i
), icu_data
->lengthOf(i
), &status
);
818 if (status
== U_BUFFER_OVERFLOW_ERROR
|| status
== U_ZERO_ERROR
){
819 status
= U_ZERO_ERROR
;
823 posix_data
->append_one(s
+ 1); // plus terminal NULL
824 t
= ucnv_fromUChars(conv
,posix_data
->last(), s
, icu_data
->dataOf(i
), icu_data
->lengthOf(i
), &status
);
825 if (U_FAILURE(status
)) return;
826 if ( t
!= s
){status
= U_INVALID_FORMAT_ERROR
;return;}
827 posix_data
->last()[s
] = 0;
830 s
= strxfrm(NULL
, posix_data
->dataOf(i
), 0);
831 if (s
== INT_MAX
){status
= U_INVALID_FORMAT_ERROR
;return;}
832 posix_key
->append_one(s
);
833 t
= strxfrm(posix_key
->last(), posix_data
->dataOf(i
), s
);
834 if (t
!= s
) {status
= U_INVALID_FORMAT_ERROR
;return;}
836 #if U_PLATFORM_HAS_WIN32_API
838 s
= icu_data
->lengthOf(i
) + 1; // plus terminal NULL
839 win_data
->append_one(s
);
840 memcpy(win_data
->last(), icu_data
->dataOf(i
), sizeof(WCHAR
) * s
);
843 s
= LCMapStringW(win_langid
, LCMAP_SORTKEY
, win_data
->dataOf(i
), win_data
->lengthOf(i
), NULL
,0);
844 if (s
== 0) {status
= U_INVALID_FORMAT_ERROR
;return;}
845 win_key
->append_one(s
);
846 t
= LCMapStringW(win_langid
, LCMAP_SORTKEY
, win_data
->dataOf(i
), win_data
->lengthOf(i
), (WCHAR
*)(win_key
->last()),s
);
847 if (t
!= s
) {status
= U_INVALID_FORMAT_ERROR
;return;}
851 // append_one() will make points shifting, should not merge following code into previous iteration
852 for (int i
=0; i
< count
; i
++) {
853 rnd_index
[i
].icu_key
= icu_key
->dataOf(i
);
854 rnd_index
[i
].icu_data
= icu_data
->dataOf(i
);
855 rnd_index
[i
].icu_data_len
= icu_data
->lengthOf(i
);
856 rnd_index
[i
].posix_key
= posix_key
->last();
857 rnd_index
[i
].posix_data
= posix_data
->dataOf(i
);
858 rnd_index
[i
].posix_data_len
= posix_data
->lengthOf(i
);
859 #if U_PLATFORM_HAS_WIN32_API
860 rnd_index
[i
].win_key
= win_key
->dataOf(i
);
861 rnd_index
[i
].win_data
= win_data
->dataOf(i
);
862 rnd_index
[i
].win_data_len
= win_data
->lengthOf(i
);
867 qsort(rnd_index
, count
, sizeof(DataIndex
), CmdQsort::q_random
);
869 #define SORT(data, func) \
870 data = new DataIndex[count];\
871 memcpy(data, rnd_index, count * sizeof(DataIndex));\
872 qsort(data, count, sizeof(DataIndex), CmdQsort::func)
874 SORT(ord_icu_data
, icu_strcoll_len
);
875 SORT(ord_icu_key
, icu_cmpkey
);
876 SORT(ord_posix_data
, posix_strcoll_null
);
877 SORT(ord_posix_key
, posix_cmpkey
);
878 #if U_PLATFORM_HAS_WIN32_API
879 SORT(ord_win_data
, win_cmp_len
);
880 SORT(ord_win_key
, win_cmpkey
);
881 SORT(ord_win_wcscmp
, win_wcscmp
);
883 SORT(ord_icu_strcmp
, icu_strcmp
);
884 SORT(ord_icu_cmpcpo
, icu_cmpcpo
);
889 int main(int argc
, const char *argv
[])
892 UErrorCode status
= U_ZERO_ERROR
;
893 CollPerfTest
test(argc
, argv
, status
);
895 if (U_FAILURE(status
)){
896 printf("The error is %s\n", u_errorName(status
));
897 //TODO: print usage here
901 if (test
.run() == FALSE
){
902 fprintf(stderr
, "FAILED: Tests could not be run please check the "