1f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/*
2f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)**********************************************************************
3f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   Copyright (C) 2007, International Business Machines
4f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   Corporation and others.  All Rights Reserved.
5f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)**********************************************************************
6f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   file name:  unisetperf.cpp
7f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   encoding:   US-ASCII
8f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   tab size:   8 (not used)
9f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   indentation:4
10f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*
11f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   created on: 2007jan31
12f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*   created by: Markus Scherer
13f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)*/
14f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
15f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include <stdio.h>
16f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include <stdlib.h>
17f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include <string.h>
18f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "unicode/uperf.h"
19f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "unicode/uniset.h"
20f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "unicode/unistr.h"
21f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "uoptions.h"
22f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
23f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
24f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
25f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// Command-line options specific to unisetperf.
26f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// Options do not have abbreviations: Force readable command lines.
27f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// (Using U+0001 for abbreviation characters.)
28f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)enum {
29f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    SET_PATTERN,
30f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    FAST_TYPE,
31f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UNISETPERF_OPTIONS_COUNT
32f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)};
33f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
34f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static UOption options[UNISETPERF_OPTIONS_COUNT]={
35f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UOPTION_DEF("pattern", '\x01', UOPT_REQUIRES_ARG),
36f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UOPTION_DEF("type",    '\x01', UOPT_REQUIRES_ARG)
37f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)};
38f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
39f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static const char *const unisetperf_usage =
40f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    "\t--pattern   UnicodeSet pattern for instantiation.\n"
41f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    "\t            Default: [:ID_Continue:]\n"
42f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    "\t--type      Type of UnicodeSet: slow fast\n"
43f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    "\t            Default: slow\n";
44f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
45f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// Test object with setup data.
46f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)class UnicodeSetPerformanceTest : public UPerfTest {
47f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)public:
48f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UnicodeSetPerformanceTest(int32_t argc, const char *argv[], UErrorCode &status)
49f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            : UPerfTest(argc, argv, options, LENGTHOF(options), unisetperf_usage, status),
50f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)              utf8(NULL), utf8Length(0), countInputCodePoints(0), spanCount(0) {
51f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if (U_SUCCESS(status)) {
52f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            UnicodeString pattern=UnicodeString(options[SET_PATTERN].value, -1, US_INV).unescape();
53f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            set.applyPattern(pattern, status);
54f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            prefrozen=set;
55f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(0==strcmp(options[FAST_TYPE].value, "fast")) {
56f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                set.freeze();
57f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
58f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
59f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            int32_t inputLength;
60f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            UPerfTest::getBuffer(inputLength, status);
61f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(U_SUCCESS(status) && inputLength>0) {
62f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                countInputCodePoints = u_countChar32(buffer, bufferLen);
63f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
64f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                countSpans();
65f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
66f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                // Preflight the UTF-8 length and allocate utf8.
67f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                u_strToUTF8(NULL, 0, &utf8Length, buffer, bufferLen, &status);
68f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if(status==U_BUFFER_OVERFLOW_ERROR) {
69f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    utf8=(char *)malloc(utf8Length);
70f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    if(utf8!=NULL) {
71f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        status=U_ZERO_ERROR;
72f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        u_strToUTF8(utf8, utf8Length, NULL, buffer, bufferLen, &status);
73f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    } else {
74f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                        status=U_MEMORY_ALLOCATION_ERROR;
75f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    }
76f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
77f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
78f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if(verbose) {
79f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    printf("code points:%ld  len16:%ld  len8:%ld  spans:%ld  "
80f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                           "cp/span:%.3g  UChar/span:%.3g  B/span:%.3g  B/cp:%.3g\n",
81f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                           (long)countInputCodePoints, (long)bufferLen, (long)utf8Length, (long)spanCount,
82f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                           (double)countInputCodePoints/spanCount, (double)bufferLen/spanCount, (double)utf8Length/spanCount,
83f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                           (double)utf8Length/countInputCodePoints);
84f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
85f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
86f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
87f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
88f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
89f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    virtual UPerfFunction* runIndexedTest(int32_t index, UBool exec, const char* &name, char* par = NULL);
90f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
91f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // Count spans of characters that are in the set,
92f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // and spans of characters that are not in the set.
93f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // If the very first character is in the set, then one additional
94f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // not-span is counted.
95f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    void countSpans() {
96f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        const UChar *s=getBuffer();
97f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t length=getBufferLen();
98f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t i=0;
99f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UBool tf=FALSE;
100f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        while(i<length) {
101f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            i=span(s, length, i, tf);
102f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            tf=(UBool)(!tf);
103f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ++spanCount;
104f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
105f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
106f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t span(const UChar *s, int32_t length, int32_t start, UBool tf) const {
107f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UChar32 c;
108f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t prev;
109f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        while((prev=start)<length) {
110f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            U16_NEXT(s, start, length, c);
111f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(tf!=set.contains(c)) {
112f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                break;
113f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
114f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
115f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return prev;
116f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
117f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
118f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const UChar *getBuffer() const { return buffer; }
119f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t getBufferLen() const { return bufferLen; }
120f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
121f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    char *utf8;
122f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t utf8Length;
123f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
124f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // Number of code points in the input text.
125f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t countInputCodePoints;
126f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    int32_t spanCount;
127f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
128f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UnicodeSet set;
129f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UnicodeSet prefrozen;
130f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)};
131f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
132f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// Performance test function object.
133f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)class Command : public UPerfFunction {
134f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)protected:
135f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    Command(const UnicodeSetPerformanceTest &testcase) : testcase(testcase) {}
136f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
137f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)public:
138f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    virtual ~Command() {}
139f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
140f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // virtual void call(UErrorCode* pErrorCode) { ... }
141f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
142f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    virtual long getOperationsPerIteration() {
143f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // Number of code points tested:
144f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // Input code points, plus one for the end of each span except the last span.
145f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return testcase.countInputCodePoints+testcase.spanCount-1;
146f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
147f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
148f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    virtual long getEventsPerIteration() {
149f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return testcase.spanCount;
150f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
151f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
152f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    const UnicodeSetPerformanceTest &testcase;
153f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)};
154f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
155f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)class Contains : public Command {
156f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)protected:
157f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    Contains(const UnicodeSetPerformanceTest &testcase) : Command(testcase) {
158f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // Verify that the frozen set is equal to the unfrozen one.
159f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UnicodeSet set;
160f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UChar32 c;
161f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
162f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        for(c=0; c<=0x10ffff; ++c) {
163f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(testcase.set.contains(c)) {
164f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                set.add(c);
165f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
166f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
167f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(set!=testcase.set) {
168f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            fprintf(stderr, "error: frozen set != original!\n");
169f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
170f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
171f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)public:
172f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    static UPerfFunction* get(const UnicodeSetPerformanceTest &testcase) {
173f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return new Contains(testcase);
174f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
175f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    virtual void call(UErrorCode* pErrorCode) {
176f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        const UnicodeSet &set=testcase.set;
177f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        const UChar *s=testcase.getBuffer();
178f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t length=testcase.getBufferLen();
179f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t count=0;
180f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t i=0;
181f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UBool tf=FALSE;
182f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        while(i<length) {
183f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            i+=span(set, s+i, length-i, tf);
184f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            tf=(UBool)(!tf);
185f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ++count;
186f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
187f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(count!=testcase.spanCount) {
188f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            fprintf(stderr, "error: Contains() count=%ld != %ld=UnicodeSetPerformanceTest.spanCount\n",
189f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    (long)count, (long)testcase.spanCount);
190f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
191f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
192f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    static int32_t span(const UnicodeSet &set, const UChar *s, int32_t length, UBool tf) {
193f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UChar32 c;
194f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t start=0, prev;
195f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        while((prev=start)<length) {
196f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            U16_NEXT(s, start, length, c);
197f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(tf!=set.contains(c)) {
198f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                break;
199f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
200f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
201f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return prev;
202f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
203f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)};
204f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
205f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)class SpanUTF16 : public Command {
206f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)protected:
207f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    SpanUTF16(const UnicodeSetPerformanceTest &testcase) : Command(testcase) {
208f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // Verify that the frozen set is equal to the unfrozen one.
209f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UnicodeSet set;
210f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UChar utf16[2];
211f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UChar32 c, c2;
212f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
213f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        for(c=0; c<=0xffff; ++c) {
214f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            utf16[0]=(UChar)c;
215f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(testcase.set.span(utf16, 1, USET_SPAN_CONTAINED)>0) {
216f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                set.add(c);
217f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
218f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
219f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        for(c=0xd800; c<=0xdbff; ++c) {
220f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            utf16[0]=(UChar)c;
221f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            for(c2=0xdc00; c2<=0xdfff; ++c2) {
222f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                utf16[1]=(UChar)c2;
223f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if(testcase.set.span(utf16, 2, USET_SPAN_CONTAINED)>0) {
224f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    set.add(U16_GET_SUPPLEMENTARY(c, c2));
225f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
226f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
227f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
228f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
229f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(set!=testcase.set) {
230f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            fprintf(stderr, "error: frozen set != original!\n");
231f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
232f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
233f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)public:
234f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    static UPerfFunction* get(const UnicodeSetPerformanceTest &testcase) {
235f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return new SpanUTF16(testcase);
236f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
237f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    virtual void call(UErrorCode* pErrorCode) {
238f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        const UnicodeSet &set=testcase.set;
239f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        const UChar *s=testcase.getBuffer();
240f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t length=testcase.getBufferLen();
241f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t count=0;
242f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t i=0;
243f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UBool tf=FALSE;
244f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        while(i<length) {
245f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            i+=set.span(s+i, length-i, (USetSpanCondition)tf);
246f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            tf=(UBool)(!tf);
247f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ++count;
248f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
249f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(count!=testcase.spanCount) {
250f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            fprintf(stderr, "error: SpanUTF16() count=%ld != %ld=UnicodeSetPerformanceTest.spanCount\n",
251f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    (long)count, (long)testcase.spanCount);
252f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
253f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
254f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)};
255f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
256f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)class SpanBackUTF16 : public Command {
257f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)protected:
258f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    SpanBackUTF16(const UnicodeSetPerformanceTest &testcase) : Command(testcase) {
259f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // Verify that the frozen set is equal to the unfrozen one.
260f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UnicodeSet set;
261f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UChar utf16[2];
262f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UChar32 c, c2;
263f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
264f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        for(c=0; c<=0xffff; ++c) {
265f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            utf16[0]=(UChar)c;
266f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(testcase.set.spanBack(utf16, 1, USET_SPAN_CONTAINED)==0) {
267f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                set.add(c);
268f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
269f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
270f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        for(c=0xd800; c<=0xdbff; ++c) {
271f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            utf16[0]=(UChar)c;
272f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            for(c2=0xdc00; c2<=0xdfff; ++c2) {
273f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                utf16[1]=(UChar)c2;
274f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                if(testcase.set.spanBack(utf16, 2, USET_SPAN_CONTAINED)==0) {
275f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    set.add(U16_GET_SUPPLEMENTARY(c, c2));
276f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                }
277f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
278f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
279f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
280f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(set!=testcase.set) {
281f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            fprintf(stderr, "error: frozen set != original!\n");
282f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
283f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
284f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)public:
285f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    static UPerfFunction* get(const UnicodeSetPerformanceTest &testcase) {
286f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return new SpanBackUTF16(testcase);
287f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
288f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    virtual void call(UErrorCode* pErrorCode) {
289f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        const UnicodeSet &set=testcase.set;
290f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        const UChar *s=testcase.getBuffer();
291f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t length=testcase.getBufferLen();
292f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t count=0;
293f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /*
294f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)         * Get the same spans as with span() where we always start with a not-contained span.
295f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)         * If testcase.spanCount is an odd number, then the last span() was not-contained.
296f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)         * The last spanBack() must be not-contained to match the first span().
297f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)         */
298f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UBool tf=(UBool)((testcase.spanCount&1)==0);
299f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        while(length>0 || !tf) {
300f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            length=set.spanBack(s, length, (USetSpanCondition)tf);
301f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            tf=(UBool)(!tf);
302f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ++count;
303f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
304f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(count!=testcase.spanCount) {
305f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            fprintf(stderr, "error: SpanBackUTF16() count=%ld != %ld=UnicodeSetPerformanceTest.spanCount\n",
306f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    (long)count, (long)testcase.spanCount);
307f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
308f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
309f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)};
310f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
311f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)class SpanUTF8 : public Command {
312f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)protected:
313f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    SpanUTF8(const UnicodeSetPerformanceTest &testcase) : Command(testcase) {
314f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // Verify that the frozen set is equal to the unfrozen one.
315f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UnicodeSet set;
316f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        char utf8[4];
317f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UChar32 c;
318f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t length;
319f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
320f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        for(c=0; c<=0x10ffff; ++c) {
321f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(c==0xd800) {
322f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                c=0xe000;
323f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
324f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            length=0;
325f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            U8_APPEND_UNSAFE(utf8, length, c);
326f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(testcase.set.spanUTF8(utf8, length, USET_SPAN_CONTAINED)>0) {
327f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                set.add(c);
328f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
329f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
330f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(set!=testcase.set) {
331f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            fprintf(stderr, "error: frozen set != original!\n");
332f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
333f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
334f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)public:
335f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    static UPerfFunction* get(const UnicodeSetPerformanceTest &testcase) {
336f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return new SpanUTF8(testcase);
337f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
338f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    virtual void call(UErrorCode* pErrorCode) {
339f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        const UnicodeSet &set=testcase.set;
340f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        const char *s=testcase.utf8;
341f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t length=testcase.utf8Length;
342f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t count=0;
343f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t i=0;
344f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UBool tf=FALSE;
345f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        while(i<length) {
346f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            i+=set.spanUTF8(s+i, length-i, (USetSpanCondition)tf);
347f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            tf=(UBool)(!tf);
348f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ++count;
349f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
350f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(count!=testcase.spanCount) {
351f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            fprintf(stderr, "error: SpanUTF8() count=%ld != %ld=UnicodeSetPerformanceTest.spanCount\n",
352f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    (long)count, (long)testcase.spanCount);
353f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
354f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
355f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)};
356f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
357f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)class SpanBackUTF8 : public Command {
358f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)protected:
359f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    SpanBackUTF8(const UnicodeSetPerformanceTest &testcase) : Command(testcase) {
360f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        // Verify that the frozen set is equal to the unfrozen one.
361f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UnicodeSet set;
362f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        char utf8[4];
363f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UChar32 c;
364f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t length;
365f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
366f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        for(c=0; c<=0x10ffff; ++c) {
367f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(c==0xd800) {
368f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                c=0xe000;
369f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
370f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            length=0;
371f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            U8_APPEND_UNSAFE(utf8, length, c);
372f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            if(testcase.set.spanBackUTF8(utf8, length, USET_SPAN_CONTAINED)==0) {
373f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                set.add(c);
374f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            }
375f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
376f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(set!=testcase.set) {
377f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            fprintf(stderr, "error: frozen set != original!\n");
378f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
379f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
380f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)public:
381f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    static UPerfFunction* get(const UnicodeSetPerformanceTest &testcase) {
382f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return new SpanBackUTF8(testcase);
383f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
384f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    virtual void call(UErrorCode* pErrorCode) {
385f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        const UnicodeSet &set=testcase.set;
386f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        const char *s=testcase.utf8;
387f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t length=testcase.utf8Length;
388f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        int32_t count=0;
389f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        /*
390f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)         * Get the same spans as with span() where we always start with a not-contained span.
391f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)         * If testcase.spanCount is an odd number, then the last span() was not-contained.
392f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)         * The last spanBack() must be not-contained to match the first span().
393f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)         */
394f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        UBool tf=(UBool)((testcase.spanCount&1)==0);
395f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        while(length>0 || !tf) {
396f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            length=set.spanBackUTF8(s, length, (USetSpanCondition)tf);
397f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            tf=(UBool)(!tf);
398f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            ++count;
399f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
400f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        if(count!=testcase.spanCount) {
401f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)            fprintf(stderr, "error: SpanBackUTF8() count=%ld != %ld=UnicodeSetPerformanceTest.spanCount\n",
402f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)                    (long)count, (long)testcase.spanCount);
403f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        }
404f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
405f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)};
406f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
407f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)UPerfFunction* UnicodeSetPerformanceTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* par) {
408f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    switch (index) {
409f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        case 0: name = "Contains";     if (exec) return Contains::get(*this); break;
410f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        case 1: name = "SpanUTF16";    if (exec) return SpanUTF16::get(*this); break;
411f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        case 2: name = "SpanBackUTF16";if (exec) return SpanBackUTF16::get(*this); break;
412f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        case 3: name = "SpanUTF8";     if (exec) return SpanUTF8::get(*this); break;
413f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        case 4: name = "SpanBackUTF8"; if (exec) return SpanBackUTF8::get(*this); break;
414f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        default: name = ""; break;
415f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
416f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return NULL;
417f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
418f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
419f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)int main(int argc, const char *argv[])
420f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){
421f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    // Default values for command-line options.
422f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    options[SET_PATTERN].value = "[:ID_Continue:]";
423f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    options[FAST_TYPE].value = "slow";
424f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
425f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UErrorCode status = U_ZERO_ERROR;
426f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    UnicodeSetPerformanceTest test(argc, argv, status);
427f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
428f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)	if (U_FAILURE(status)){
429f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        printf("The error is %s\n", u_errorName(status));
430f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        test.usage();
431f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return status;
432f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
433f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
434f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    if (test.run() == FALSE){
435f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        fprintf(stderr, "FAILED: Tests could not be run, please check the "
436f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)			            "arguments.\n");
437f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)        return 1;
438f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    }
439f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)
440f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)    return 0;
441f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}
442