1/*
2 **********************************************************************
3 *   Copyright (C) 2002-2008, International Business Machines
4 *   Corporation and others.  All Rights Reserved.
5 **********************************************************************
6 *  file name:  utrie2perf.cpp
7 *  encoding:   US-ASCII
8 *  tab size:   8 (not used)
9 *  indentation:4
10 *
11 *  created on: 2008sep07
12 *  created by: Markus W. Scherer
13 *
14 *  Performance test program for UTrie2.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include "unicode/uchar.h"
20#include "unicode/unorm.h"
21#include "unicode/uperf.h"
22#include "uoptions.h"
23
24#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
25
26#if 0
27// Left over from when icu/branches/markus/utf8 could use both old UTrie
28// and new UTrie2, switched with #if in unorm.cpp and ubidi_props.c.
29// Comparative benchmarks were done in that branch on revision r24630
30// and earlier.
31U_CAPI void U_EXPORT2
32unorm_initUTrie2(UErrorCode *pErrorCode);
33
34U_CAPI void U_EXPORT2
35ubidi_initUTrie2(UErrorCode *pErrorCode);
36#endif
37
38U_NAMESPACE_BEGIN
39
40class UnicodeSet;
41
42U_NAMESPACE_END
43
44// Test object.
45class UTrie2PerfTest : public UPerfTest {
46public:
47    UTrie2PerfTest(int32_t argc, const char *argv[], UErrorCode &status)
48            : UPerfTest(argc, argv, NULL, 0, "", status),
49              utf8(NULL), utf8Length(0), countInputCodePoints(0) {
50        if (U_SUCCESS(status)) {
51#if 0       // See comment at unorm_initUTrie2() forward declaration.
52            unorm_initUTrie2(&status);
53            ubidi_initUTrie2(&status);
54#endif
55            int32_t inputLength;
56            UPerfTest::getBuffer(inputLength, status);
57            if(U_SUCCESS(status) && inputLength>0) {
58                countInputCodePoints = u_countChar32(buffer, bufferLen);
59
60                // Preflight the UTF-8 length and allocate utf8.
61                u_strToUTF8(NULL, 0, &utf8Length, buffer, bufferLen, &status);
62                if(status==U_BUFFER_OVERFLOW_ERROR) {
63                    utf8=(char *)malloc(utf8Length);
64                    if(utf8!=NULL) {
65                        status=U_ZERO_ERROR;
66                        u_strToUTF8(utf8, utf8Length, NULL, buffer, bufferLen, &status);
67                    } else {
68                        status=U_MEMORY_ALLOCATION_ERROR;
69                    }
70                }
71
72                if(verbose) {
73                    printf("code points:%ld  len16:%ld  len8:%ld  "
74                           "B/cp:%.3g\n",
75                           (long)countInputCodePoints, (long)bufferLen, (long)utf8Length,
76                           (double)utf8Length/countInputCodePoints);
77                }
78            }
79        }
80    }
81
82    virtual UPerfFunction* runIndexedTest(int32_t index, UBool exec, const char* &name, char* par = NULL);
83
84    const UChar *getBuffer() const { return buffer; }
85    int32_t getBufferLen() const { return bufferLen; }
86
87    char *utf8;
88    int32_t utf8Length;
89
90    // Number of code points in the input text.
91    int32_t countInputCodePoints;
92};
93
94// Performance test function object.
95class Command : public UPerfFunction {
96protected:
97    Command(const UTrie2PerfTest &testcase) : testcase(testcase) {}
98
99public:
100    virtual ~Command() {}
101
102    // virtual void call(UErrorCode* pErrorCode) { ... }
103
104    virtual long getOperationsPerIteration() {
105        // Number of code points tested.
106        return testcase.countInputCodePoints;
107    }
108
109    // virtual long getEventsPerIteration();
110
111    const UTrie2PerfTest &testcase;
112    UNormalizationCheckResult qcResult;
113};
114
115class CheckFCD : public Command {
116protected:
117    CheckFCD(const UTrie2PerfTest &testcase) : Command(testcase) {}
118public:
119    static UPerfFunction* get(const UTrie2PerfTest &testcase) {
120        return new CheckFCD(testcase);
121    }
122    virtual void call(UErrorCode* pErrorCode) {
123        UErrorCode errorCode=U_ZERO_ERROR;
124        qcResult=unorm_quickCheck(testcase.getBuffer(), testcase.getBufferLen(),
125                                  UNORM_FCD, &errorCode);
126        if(U_FAILURE(errorCode)) {
127            fprintf(stderr, "error: unorm_quickCheck(UNORM_FCD) failed: %s\n",
128                    u_errorName(errorCode));
129        }
130    }
131};
132
133#if 0  // See comment at unorm_initUTrie2() forward declaration.
134
135class CheckFCDAlwaysGet : public Command {
136protected:
137    CheckFCDAlwaysGet(const UTrie2PerfTest &testcase) : Command(testcase) {}
138public:
139    static UPerfFunction* get(const UTrie2PerfTest &testcase) {
140        return new CheckFCDAlwaysGet(testcase);
141    }
142    virtual void call(UErrorCode* pErrorCode) {
143        UErrorCode errorCode=U_ZERO_ERROR;
144        qcResult=unorm_quickCheck(testcase.getBuffer(), testcase.getBufferLen(),
145                                  UNORM_FCD_ALWAYS_GET, &errorCode);
146        if(U_FAILURE(errorCode)) {
147            fprintf(stderr, "error: unorm_quickCheck(UNORM_FCD) failed: %s\n",
148                    u_errorName(errorCode));
149        }
150    }
151};
152
153U_CAPI UBool U_EXPORT2
154unorm_checkFCDUTF8(const uint8_t *src, int32_t srcLength, const UnicodeSet *nx);
155
156class CheckFCDUTF8 : public Command {
157protected:
158    CheckFCDUTF8(const UTrie2PerfTest &testcase) : Command(testcase) {}
159public:
160    static UPerfFunction* get(const UTrie2PerfTest &testcase) {
161        return new CheckFCDUTF8(testcase);
162    }
163    virtual void call(UErrorCode* pErrorCode) {
164        UBool isFCD=unorm_checkFCDUTF8((const uint8_t *)testcase.utf8, testcase.utf8Length, NULL);
165        if(isFCD>1) {
166            fprintf(stderr, "error: bogus result from unorm_checkFCDUTF8()\n");
167        }
168    }
169};
170
171#endif
172
173class ToNFC : public Command {
174protected:
175    ToNFC(const UTrie2PerfTest &testcase) : Command(testcase) {
176        UErrorCode errorCode=U_ZERO_ERROR;
177        destCapacity=unorm_normalize(testcase.getBuffer(), testcase.getBufferLen(),
178                                     UNORM_NFC, 0,
179                                     NULL, 0,
180                                     &errorCode);
181        dest=new UChar[destCapacity];
182    }
183    ~ToNFC() {
184        delete [] dest;
185    }
186public:
187    static UPerfFunction* get(const UTrie2PerfTest &testcase) {
188        return new ToNFC(testcase);
189    }
190    virtual void call(UErrorCode* pErrorCode) {
191        UErrorCode errorCode=U_ZERO_ERROR;
192        int32_t destLength=unorm_normalize(testcase.getBuffer(), testcase.getBufferLen(),
193                                           UNORM_NFC, 0,
194                                           dest, destCapacity,
195                                           &errorCode);
196        if(U_FAILURE(errorCode) || destLength!=destCapacity) {
197            fprintf(stderr, "error: unorm_normalize(UNORM_NFC) failed: %s\n",
198                    u_errorName(errorCode));
199        }
200    }
201
202private:
203    UChar *dest;
204    int32_t destCapacity;
205};
206
207class GetBiDiClass : public Command {
208protected:
209    GetBiDiClass(const UTrie2PerfTest &testcase) : Command(testcase) {}
210public:
211    static UPerfFunction* get(const UTrie2PerfTest &testcase) {
212        return new GetBiDiClass(testcase);
213    }
214    virtual void call(UErrorCode* pErrorCode) {
215        const UChar *buffer=testcase.getBuffer();
216        int32_t length=testcase.getBufferLen();
217        UChar32 c;
218        int32_t i;
219        uint32_t bitSet=0;
220        for(i=0; i<length;) {
221            U16_NEXT(buffer, i, length, c);
222            bitSet|=(uint32_t)1<<u_charDirection(c);
223        }
224        if(length>0 && bitSet==0) {
225            fprintf(stderr, "error: GetBiDiClass() did not collect bits\n");
226        }
227    }
228};
229
230UPerfFunction* UTrie2PerfTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* par) {
231    switch (index) {
232        case 0: name = "CheckFCD";              if (exec) return CheckFCD::get(*this); break;
233        case 1: name = "ToNFC";                 if (exec) return ToNFC::get(*this); break;
234        case 2: name = "GetBiDiClass";          if (exec) return GetBiDiClass::get(*this); break;
235#if 0  // See comment at unorm_initUTrie2() forward declaration.
236        case 3: name = "CheckFCDAlwaysGet";     if (exec) return CheckFCDAlwaysGet::get(*this); break;
237        case 4: name = "CheckFCDUTF8";          if (exec) return CheckFCDUTF8::get(*this); break;
238#endif
239        default: name = ""; break;
240    }
241    return NULL;
242}
243
244int main(int argc, const char *argv[]) {
245    UErrorCode status = U_ZERO_ERROR;
246    UTrie2PerfTest test(argc, argv, status);
247
248	if (U_FAILURE(status)){
249        printf("The error is %s\n", u_errorName(status));
250        test.usage();
251        return status;
252    }
253
254    if (test.run() == FALSE){
255        fprintf(stderr, "FAILED: Tests could not be run please check the "
256			            "arguments.\n");
257        return -1;
258    }
259
260    return 0;
261}
262