~ubuntu-branches/ubuntu/gutsy/icu/gutsy

« back to all changes in this revision

Viewing changes to source/i18n/caniter.cpp

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2005-05-21 22:44:31 UTC
  • mfrom: (2.1.1 warty)
  • Revision ID: package-import@ubuntu.com-20050521224431-r7rktfhnu1n4tf1g
Tags: 2.1-2.1
Rename icu-doc to icu21-doc. icu-doc is built by the icu28 package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 *******************************************************************************
3
 
 * Copyright (C) 1996-2000, International Business Machines Corporation and    *
4
 
 * others. All Rights Reserved.                                                *
5
 
 *******************************************************************************
6
 
 *
7
 
 * $Source: /usr/cvs/icu/icu/source/i18n/caniter.cpp,v $ 
8
 
 * $Date: 2002/02/27 21:47:04 $ 
9
 
 * $Revision: 1.2 $
10
 
 *
11
 
 *****************************************************************************************
 
2
 *****************************************************************************
 
3
 * Copyright (C) 1996-2002, International Business Machines Corporation and  *
 
4
 * others. All Rights Reserved.                                              *
 
5
 *****************************************************************************
12
6
 */
13
7
 
14
8
#include "hash.h"
15
 
#include "unicode/caniter.h"
 
9
#include "uset.h"
 
10
#include "unormimp.h"
 
11
#include "caniter.h"
 
12
#include "cmemory.h"
 
13
#include "unicode/ustring.h"
16
14
 
17
15
/**
18
16
 * This class allows one to iterate through all the strings that are canonically equivalent to a given
47
45
 *@author M. Davis
48
46
 *@draft
49
47
 */
50
 
 
51
 
//#include <stdio.h>
52
 
 
53
 
 
54
 
//CanonicalIterator::SAFE_START = NULL;
55
 
//CanonicalIterator::AT_START = NULL;
56
 
 
57
 
static UnicodeSet *SAFE_START = NULL; // = new UnicodeSet();
58
 
//private static CharMap AT_START = new CharMap();
59
 
static Hashtable *AT_START = NULL;
60
 
 
61
48
#if 0
62
49
static UBool PROGRESS = FALSE;
63
50
 
 
51
#include <stdio.h>
64
52
#include "unicode/translit.h"
65
53
 
66
54
UErrorCode status = U_ZERO_ERROR;
67
55
 
68
 
// Just for testing - remove, not thread safe. 
 
56
// Just for testing - remove, not thread safe.
69
57
static const char* UToS(const UnicodeString &source) {
70
58
  static char buffer[256];
71
59
  buffer[source.extract(0, source.length(), buffer)] = 0;
80
68
  return result;
81
69
}
82
70
#endif
83
 
 
84
71
// public
85
72
 
 
73
// TODO: add boilerplate methods.
 
74
 
86
75
/**
87
76
 *@param source string to get results for
88
77
 */
89
 
CanonicalIterator::CanonicalIterator(UnicodeString source, UErrorCode status) :
 
78
CanonicalIterator::CanonicalIterator(UnicodeString sourceStr, UErrorCode &status) :
90
79
    pieces(NULL),
 
80
    pieces_length(0),
91
81
    pieces_lengths(NULL),
92
 
    current(NULL)
 
82
    current(NULL),
 
83
    current_length(0)
93
84
{
94
 
  initStaticData(status);
95
 
    setSource(source, status);
 
85
    if(U_SUCCESS(status)) {
 
86
      setSource(sourceStr, status);
 
87
    }
96
88
}
97
89
 
98
90
CanonicalIterator::~CanonicalIterator() {
110
102
    delete[] pieces;
111
103
    pieces = NULL;
112
104
    if(pieces_lengths != NULL) {
113
 
      delete[] pieces_lengths;
 
105
      uprv_free(pieces_lengths);
114
106
    }
115
107
    pieces_lengths = NULL;
116
108
    if(current != NULL) {
117
 
      delete[] current;
 
109
      uprv_free(current);
118
110
    }
119
111
    current = NULL;
120
112
  }
131
123
 * Resets the iterator so that one can start again from the beginning.
132
124
 */
133
125
void CanonicalIterator::reset() {
134
 
    done = false;
 
126
    done = FALSE;
135
127
    for (int i = 0; i < current_length; ++i) {
136
128
        current[i] = 0;
137
129
    }
142
134
 * the iteration is done.
143
135
 */
144
136
UnicodeString CanonicalIterator::next() {
145
 
  int32_t i = 0;
146
 
    if (done) return "";
147
 
    
 
137
    int32_t i = 0;
 
138
    if (done)
 
139
        return "";
 
140
 
148
141
    // construct return value
149
 
    
 
142
 
150
143
    buffer.truncate(0); //buffer.setLength(0); // delete old contents
151
144
    for (i = 0; i < pieces_length; ++i) {
152
145
        buffer.append(pieces[i][current[i]]);
153
146
    }
154
147
    //String result = buffer.toString(); // not needed
155
 
    
 
148
 
156
149
    // find next value for next time
157
 
    
 
150
 
158
151
    for (i = current_length - 1; ; --i) {
159
152
        if (i < 0) {
160
153
            done = TRUE;
171
164
 *@param set the source string to iterate against. This allows the same iterator to be used
172
165
 * while changing the source string, saving object creation.
173
166
 */
174
 
void CanonicalIterator::setSource(UnicodeString newSource, UErrorCode status) {
 
167
void CanonicalIterator::setSource(const UnicodeString &newSource, UErrorCode &status) {
 
168
    if(U_FAILURE(status)) {
 
169
      return;
 
170
    }
175
171
    Normalizer::normalize(newSource, UNORM_NFD, 0, source, status);
176
172
    done = FALSE;
177
 
    
 
173
 
178
174
    cleanPieces();
179
175
 
 
176
    // catch degenerate case
 
177
    if (newSource.length() == 0) {
 
178
        pieces_length = 1;
 
179
        pieces = new UnicodeString*[1];
 
180
        current_length = 1;
 
181
        current = (int32_t*)uprv_malloc(1 * sizeof(int32_t));
 
182
        current[0] = 0;
 
183
        pieces[0] = new UnicodeString[1];
 
184
        pieces[0][0] = UnicodeString("");
 
185
        pieces_lengths = (int32_t*)uprv_malloc(1 * sizeof(int32_t));
 
186
        pieces_lengths[0] = 1;
 
187
        return;
 
188
    }
 
189
 
 
190
 
180
191
    UnicodeString *list = new UnicodeString[source.length()];
181
192
    int32_t list_length = 0;
182
193
    UChar32 cp = 0;
183
194
    int32_t start = 0;
184
 
    int32_t i = 1;
 
195
    // i should initialy be the number of code units at the 
 
196
    // start of the string
 
197
    int32_t i = UTF16_CHAR_LENGTH(source.char32At(0));
 
198
    //int32_t i = 1;
185
199
    // find the segments
186
200
    // This code iterates through the source string and 
187
201
    // extracts segments that end up on a codepoint that
189
203
    // on the NFD form - see above).
190
204
    for (; i < source.length(); i += UTF16_CHAR_LENGTH(cp)) {
191
205
        cp = source.char32At(i);
192
 
        if (SAFE_START->contains(cp)) {
193
 
            source.extract(start, i, list[list_length++]); // add up to i
 
206
        if (unorm_isCanonSafeStart(cp)) {
 
207
            source.extract(start, i-start, list[list_length++]); // add up to i
194
208
            start = i;
195
209
        }
196
210
    }
197
 
    source.extract(start, i, list[list_length++]); // add last one
198
 
 
199
 
    
 
211
    source.extract(start, i-start, list[list_length++]); // add last one
 
212
 
 
213
 
200
214
    // allocate the arrays, and find the strings that are CE to each segment
201
215
    pieces = new UnicodeString*[list_length];
202
216
    pieces_length = list_length;
203
 
    pieces_lengths = new int32_t[list_length];
 
217
    pieces_lengths = (int32_t*)uprv_malloc(list_length * sizeof(int32_t));
204
218
 
205
 
    current = new int32_t[list_length];
206
219
    current_length = list_length;
 
220
    current = (int32_t*)uprv_malloc(list_length * sizeof(int32_t));
207
221
    for (i = 0; i < current_length; i++) {
208
222
      current[i] = 0;
209
223
    }
218
232
}
219
233
 
220
234
/**
221
 
 * Dumb recursive implementation of permutation. 
 
235
 * Dumb recursive implementation of permutation.
222
236
 * TODO: optimize
223
237
 * @param source the string to find permutations for
224
238
 * @return the results in a set.
225
239
 */
226
 
Hashtable *CanonicalIterator::permute(UnicodeString &source, UErrorCode status) {
 
240
void CanonicalIterator::permute(UnicodeString &source, UBool skipZeros, Hashtable *result, UErrorCode &status) {
 
241
    if(U_FAILURE(status)) {
 
242
      return;
 
243
    }
227
244
    //if (PROGRESS) printf("Permute: %s\n", UToS(Tr(source)));
228
245
    int32_t i = 0;
229
246
 
230
 
    Hashtable *result = new Hashtable(FALSE, status);
231
 
    result->setValueDeleter(uhash_deleteUnicodeString);
232
 
    
233
247
    // optimization:
234
248
    // if zero or one character, just return a set with it
235
249
    // we check for length < 2 to keep from counting code points all the time
236
 
    //if (source.length() <= 2 && UTF16_CHAR_LENGTH(source.char32At(0)) <= 1) {
237
 
    if (source.length() < 2 || (source.length() == 2 && UTF16_CHAR_LENGTH(source.char32At(0)) > 1)) {
 
250
    if (source.length() <= 2 && source.countChar32() <= 1) {
238
251
      UnicodeString *toPut = new UnicodeString(source);
239
 
      result->put(source, toPut, status); 
240
 
      return result;
 
252
      result->put(source, toPut, status);
 
253
      return;
241
254
    }
242
 
    
 
255
 
243
256
    // otherwise iterate through the string, and recursively permute all the other characters
244
257
    UChar32 cp;
 
258
    Hashtable *subpermute = new Hashtable(FALSE, status);
 
259
    if (U_SUCCESS(status)) {
 
260
        subpermute->setValueDeleter(uhash_deleteUnicodeString);
 
261
    }
 
262
 
245
263
    for (i = 0; i < source.length(); i += UTF16_CHAR_LENGTH(cp)) {
246
264
        cp = source.char32At(i);
247
265
        const UHashElement *ne = NULL;
248
266
        int32_t el = -1;
249
267
        UnicodeString subPermuteString = source;
250
 
        
 
268
 
 
269
        // optimization:
 
270
        // if the character is canonical combining class zero,
 
271
        // don't permute it
 
272
        if (skipZeros && i != 0 && u_getCombiningClass(cp) == 0) {
 
273
            //System.out.println("Skipping " + Utility.hex(UTF16.valueOf(source, i)));
 
274
            continue;
 
275
        }
 
276
 
 
277
        subpermute->removeAll();
 
278
 
251
279
        // see what the permutations of the characters before and after this one are
252
280
        //Hashtable *subpermute = permute(source.substring(0,i) + source.substring(i + UTF16.getCharCount(cp)));
253
 
        Hashtable *subpermute = permute(subPermuteString.replace(i, UTF16_CHAR_LENGTH(cp), NULL, 0), status);
 
281
        permute(subPermuteString.replace(i, UTF16_CHAR_LENGTH(cp), NULL, 0), skipZeros, subpermute, status);
254
282
        // The upper replace is destructive. The question is do we have to make a copy, or we don't care about the contents 
255
283
        // of source at this point.
256
 
        
 
284
 
257
285
        // prefix this character to all of them
258
286
        ne = subpermute->nextElement(el);
259
287
        while (ne != NULL) {
264
292
            result->put(*chStr, chStr, status);
265
293
            ne = subpermute->nextElement(el);
266
294
        }
267
 
        delete subpermute;
268
 
    }
269
 
    return result;
270
 
}
271
 
 
272
 
static UBool U_CALLCONV
273
 
_enumCategoryRangeSAFE_STARTsetup(const void *context, UChar32 start, UChar32 limit, UCharCategory type) {
274
 
  int32_t cc = 0;
275
 
  // TODO: use a switch that will automatically add all the unassigned, lead surrogates, tail surrogates and privates
276
 
  //fprintf(stdout, "SAFE_START:%08X - %08X, %i\n", start, limit, type);
277
 
  if(type > 0) {
278
 
    for(; start < limit; start++) {
279
 
      cc = u_getCombiningClass(start);
280
 
      if(cc == 0) {
281
 
        int32_t lowerLimit = start;
282
 
        while(cc == 0 && start <= limit) {
283
 
          cc = u_getCombiningClass(++start);
284
 
        }
285
 
        SAFE_START->add(lowerLimit, start-1);
286
 
      }
287
 
    }
288
 
  } else {
289
 
    SAFE_START->add(start, limit-1);
290
 
  }
291
 
  return TRUE;
292
 
}
293
 
 
294
 
static UBool U_CALLCONV
295
 
_enumCategoryRangeAT_STARTsetup(const void *context, UChar32 start, UChar32 limit, UCharCategory type) {
296
 
  UErrorCode status = *(UErrorCode *)context;
297
 
  int32_t cc = 0;
298
 
  //fprintf(stdout, "AT_START:%08X - %08X, %i\n", start, limit, type);
299
 
  UChar32 cp = 0;
300
 
  if(type > 0) {
301
 
    for(cp = start; cp < limit; cp++) {
302
 
        UnicodeString istr(cp);
303
 
        UnicodeString decomp;
304
 
        Normalizer::normalize(istr, UNORM_NFD, 0, decomp, status);
305
 
        if (decomp==istr) continue;
306
 
    
307
 
        // add each character in the decomposition to canBeIn      
308
 
        UChar32 component = 0;
309
 
        int32_t i = 0;
310
 
        for (i = 0; i < decomp.length(); i += UTF16_CHAR_LENGTH(component)) {
311
 
            component = decomp.char32At(i);
312
 
            if (i == 0) {
313
 
              UnicodeSet *isIn = (UnicodeSet *)AT_START->get(component);
314
 
              if(isIn == NULL) {
315
 
                isIn = new UnicodeSet();
316
 
              }
317
 
              isIn->add(cp);
318
 
              AT_START->put(component, isIn, status);
319
 
            } else if (u_getCombiningClass(component) == 0) {
320
 
                SAFE_START->remove(component);
321
 
            }
322
 
        }
323
 
    }
324
 
  }
325
 
  return TRUE;
326
 
}
327
 
 
328
 
void CanonicalIterator::initStaticData(UErrorCode status) {
329
 
  if(SAFE_START == NULL && AT_START == NULL) {
330
 
    SAFE_START = new UnicodeSet();
331
 
    // TODO: have value deleter for UnicodeSets
332
 
    AT_START = new Hashtable(FALSE, status);
333
 
 
334
 
    UChar32 cp = 0;
335
 
    //if (PROGRESS) printf("Getting Safe Start");
336
 
 
337
 
    // TODO: use u_enumCharType() instead
338
 
    // the fastest with current, public apis is to 
339
 
    // enumerate with u_enumCharType() for all categories !=0 and then 
340
 
    // getCombiningClass(start..limit-1) that cuts it down by a factor of about 11...
341
 
    u_enumCharTypes(_enumCategoryRangeSAFE_STARTsetup, 0);
342
 
  
343
 
    //if (PROGRESS) printf("Getting Containment\n");
344
 
    u_enumCharTypes(_enumCategoryRangeAT_STARTsetup, &status);
345
 
  }
346
 
}
347
 
 
348
 
/**
349
 
 *@return the set of "safe starts", characters that are class zero AND are never non-initial in a decomposition.
350
 
 */
351
 
UnicodeSet *CanonicalIterator::getSafeStart(UErrorCode status) {
352
 
  initStaticData(status);
353
 
    return  SAFE_START;
354
 
}
355
 
 
356
 
/**
357
 
 *@return the set of characters whose decompositions start with the given character
358
 
 */
359
 
UnicodeSet *CanonicalIterator::getStarts(UChar32 cp, UErrorCode status) {
360
 
  initStaticData(status);
361
 
  UnicodeSet *result = (UnicodeSet *)AT_START->get(cp);
362
 
  return result;
 
295
    }
 
296
    delete subpermute;
 
297
    //return result;
363
298
}
364
299
 
365
300
// privates
366
 
    
 
301
 
367
302
// we have a segment, in NFD. Find all the strings that are canonically equivalent to it.
368
 
UnicodeString* CanonicalIterator::getEquivalents(UnicodeString segment, int32_t &result_len, UErrorCode status) { //private String[] getEquivalents(String segment) 
 
303
UnicodeString* CanonicalIterator::getEquivalents(const UnicodeString &segment, int32_t &result_len, UErrorCode &status) {
 
304
    //private String[] getEquivalents(String segment)
 
305
 
369
306
    Hashtable *result = new Hashtable(FALSE, status);
370
 
    Hashtable *basic = getEquivalents2(segment, status);
371
 
    
 
307
    if (U_SUCCESS(status)) {
 
308
        result->setValueDeleter(uhash_deleteUnicodeString);
 
309
    }
 
310
    UChar USeg[256];
 
311
    int32_t segLen = segment.extract(USeg, 256, status);
 
312
    Hashtable *basic = getEquivalents2(USeg, segLen, status);
 
313
    //Hashtable *basic = getEquivalents2(segment, segLen, status);
 
314
 
372
315
    // now get all the permutations
373
316
    // add only the ones that are canonically equivalent
374
317
    // TODO: optimize by not permuting any class zero.
 
318
 
 
319
    Hashtable *permutations = new Hashtable(FALSE, status);
 
320
    if (U_SUCCESS(status)) {
 
321
        permutations->setValueDeleter(uhash_deleteUnicodeString);
 
322
    }
 
323
 
375
324
    const UHashElement *ne = NULL;
376
325
    int32_t el = -1;
377
326
    //Iterator it = basic.iterator();
378
327
    ne = basic->nextElement(el);
379
 
    //while (it.hasNext()) 
 
328
    //while (it.hasNext())
380
329
    while (ne != NULL) {
381
330
        //String item = (String) it.next();
382
331
        UnicodeString item = *((UnicodeString *)(ne->value.pointer));
383
 
        Hashtable *permutations = permute(item, status);
 
332
 
 
333
        permutations->removeAll();
 
334
        permute(item, SKIP_ZEROES, permutations, status);
384
335
        const UHashElement *ne2 = NULL;
385
336
        int32_t el2 = -1;
386
337
        //Iterator it2 = permutations.iterator();
387
338
        ne2 = permutations->nextElement(el2);
388
 
        //while (it2.hasNext()) 
 
339
        //while (it2.hasNext())
389
340
        while (ne2 != NULL) {
390
341
            //String possible = (String) it2.next();
391
 
            UnicodeString *possible = new UnicodeString(*((UnicodeString *)(ne2->value.pointer)));
 
342
            //UnicodeString *possible = new UnicodeString(*((UnicodeString *)(ne2->value.pointer)));
 
343
            UnicodeString possible(*((UnicodeString *)(ne2->value.pointer)));
392
344
            UnicodeString attempt;
393
 
            Normalizer::normalize(*possible, UNORM_NFD, 0, attempt, status);
 
345
            Normalizer::normalize(possible, UNORM_NFD, 0, attempt, status);
394
346
 
395
347
            // TODO: check if operator == is semanticaly the same as attempt.equals(segment)
396
348
            if (attempt==segment) {
397
349
                //if (PROGRESS) printf("Adding Permutation: %s\n", UToS(Tr(*possible)));
398
350
                // TODO: use the hashtable just to catch duplicates - store strings directly (somehow).
399
 
                result->put(*possible, possible, status); //add(possible);
 
351
                result->put(possible, new UnicodeString(possible), status); //add(possible);
400
352
            } else {
401
353
                //if (PROGRESS) printf("-Skipping Permutation: %s\n", UToS(Tr(*possible)));
402
354
            }
403
355
 
404
356
          ne2 = permutations->nextElement(el2);
405
357
        }
406
 
        delete permutations;
407
358
        ne = basic->nextElement(el);
408
359
    }
409
 
    
 
360
 
410
361
    // convert into a String[] to clean up storage
411
362
    //String[] finalResult = new String[result.size()];
412
363
    UnicodeString *finalResult = new UnicodeString[result->count()];
421
372
    }
422
373
 
423
374
 
 
375
    delete permutations;
 
376
    delete basic;
424
377
    delete result;
425
378
    return finalResult;
426
379
}
427
380
 
428
 
Hashtable *CanonicalIterator::getEquivalents2(UnicodeString segment, UErrorCode status) {
429
 
    //Set result = new TreeSet();
 
381
Hashtable *CanonicalIterator::getEquivalents2(const UChar *segment, int32_t segLen, UErrorCode &status) {
 
382
//Hashtable *CanonicalIterator::getEquivalents2(const UnicodeString &segment, int32_t segLen, UErrorCode &status) {
 
383
 
430
384
    Hashtable *result = new Hashtable(FALSE, status);
431
 
    result->setValueDeleter(uhash_deleteUnicodeString);
 
385
    if (U_SUCCESS(status)) {
 
386
        result->setValueDeleter(uhash_deleteUnicodeString);
 
387
    }
432
388
 
433
389
    //if (PROGRESS) printf("Adding: %s\n", UToS(Tr(segment)));
434
390
 
435
 
    //result.add(segment);
436
 
    result->put(segment, new UnicodeString(segment), status);
437
 
 
438
 
    //StringBuffer workingBuffer = new StringBuffer();
439
 
    UnicodeString workingBuffer;
440
 
 
441
 
    
 
391
    UnicodeString toPut(segment, segLen);
 
392
 
 
393
    result->put(toPut, new UnicodeString(toPut), status);
 
394
 
 
395
    USerializedSet starts;
 
396
 
442
397
    // cycle through all the characters
443
 
    UChar32 cp;
444
 
    int32_t i = 0, j = 0;
445
 
    for (i = 0; i < segment.length(); i += UTF16_CHAR_LENGTH(cp)) {
 
398
    UChar32 cp, limit = 0;
 
399
    int32_t i = 0, j;
 
400
    for (i = 0; i < segLen; i += UTF16_CHAR_LENGTH(cp)) {
446
401
        // see if any character is at the start of some decomposition
447
 
        cp = segment.char32At(i);
448
 
        UnicodeSet *starts = (UnicodeSet *)AT_START->get(cp);
449
 
        if (starts == NULL) continue;
450
 
        //UnicodeSetIterator usi = new UnicodeSetIterator(starts);
451
 
        int32_t setSize = starts->size();
 
402
        UTF_GET_CHAR(segment, 0, i, segLen, cp);
 
403
        if (!unorm_getCanonStartSet(cp, &starts)) {
 
404
          continue;
 
405
        }
452
406
        // if so, see which decompositions match 
453
 
        //while (TRUE) {
454
 
        for(j = 0; j < setSize; j++) {
455
 
            //UChar32 cp2 = usi.next();
456
 
            UChar32 cp2 = starts->charAt(j);
457
 
            //if (cp2 < 0) break; // done
458
 
            const Hashtable *remainder = extract(cp2, segment, i, workingBuffer, status);
 
407
        for(j = 0, cp = limit; cp < limit || uset_getSerializedRange(&starts, j++, &cp, &limit); ++cp) {
 
408
            //Hashtable *remainder = extract(cp, segment, segLen, i, status);
 
409
            Hashtable *remainder = extract(cp, segment, segLen, i, status);
459
410
            if (remainder == NULL) continue;
460
 
            
 
411
 
461
412
            // there were some matches, so add all the possibilities to the set.
462
 
            //UnicodeString prefix = segment.substring(0, i) + UTF16.valueOf(cp2);
463
 
            UnicodeString *prefix = new UnicodeString;
464
 
            segment.extract(0, i, *prefix);
465
 
            *prefix += cp2;
 
413
            UnicodeString prefix(segment, i);
 
414
            prefix += cp;
466
415
 
467
416
            const UHashElement *ne = NULL;
468
417
            int32_t el = -1;
469
 
            //Iterator it = remainder.iterator();
470
418
            ne = remainder->nextElement(el);
471
419
            while (ne != NULL) {
472
 
                //String item = (String) it.next();
473
420
                UnicodeString item = *((UnicodeString *)(ne->value.pointer));
474
 
                //result.add(prefix + item);
475
 
                *prefix += item;
476
 
                result->put(*prefix, prefix, status);
 
421
                UnicodeString *toAdd = new UnicodeString(prefix);
 
422
                *toAdd += item;
 
423
                result->put(*toAdd, toAdd, status);
477
424
 
478
 
                //if (PROGRESS) printf("Adding: %s\n", UToS(Tr(*prefix)));
 
425
                //if (PROGRESS) printf("Adding: %s\n", UToS(Tr(*toAdd)));
479
426
 
480
427
                ne = remainder->nextElement(el);
481
428
            }
491
438
 * (with canonical rearrangment!)
492
439
 * If so, take the remainder, and return the equivalents 
493
440
 */
494
 
const Hashtable *CanonicalIterator::extract(UChar32 comp, UnicodeString segment, int32_t segmentPos, UnicodeString buffer, UErrorCode status) {
 
441
Hashtable *CanonicalIterator::extract(UChar32 comp, const UChar *segment, int32_t segLen, int32_t segmentPos, UErrorCode &status) {
 
442
//Hashtable *CanonicalIterator::extract(UChar32 comp, const UnicodeString &segment, int32_t segLen, int32_t segmentPos, UErrorCode &status) {
495
443
    //if (PROGRESS) printf(" extract: %s, ", UToS(Tr(UnicodeString(comp))));
496
444
    //if (PROGRESS) printf("%s, %i\n", UToS(Tr(segment)), segmentPos);
497
445
 
498
 
    //String decomp = Normalizer.normalize(UTF16.valueOf(comp), Normalizer.DECOMP, 0);
499
 
    UnicodeString decomp;
500
 
    Normalizer::normalize(comp, UNORM_NFD, 0, decomp, status);
501
 
    
 
446
    const int32_t bufSize = 256;
 
447
    int32_t bufLen = 0;
 
448
    UChar temp[bufSize];
 
449
 
 
450
    const int32_t decompSize = 64;
 
451
    int32_t inputLen = 0;
 
452
    UChar decomp[decompSize];
 
453
 
 
454
    UTF_APPEND_CHAR(temp, inputLen, bufSize, comp);
 
455
    int32_t decompLen = unorm_getDecomposition(comp, FALSE, decomp, decompSize);
 
456
    if(decompLen < 0) {
 
457
        decompLen = -decompLen;
 
458
    }
 
459
 
 
460
    UChar *buff = temp+inputLen;
 
461
 
502
462
    // See if it matches the start of segment (at segmentPos)
503
463
    UBool ok = FALSE;
504
464
    UChar32 cp;
505
465
    int32_t decompPos = 0;
506
 
    UChar32 decompCp = decomp.char32At(0);
507
 
    decompPos += UTF16_CHAR_LENGTH(decompCp); // adjust position to skip first char
508
 
    //int decompClass = getClass(decompCp);
509
 
    buffer.truncate(0); // initialize working buffer, shared among callees
510
 
    
 
466
    UChar32 decompCp;
 
467
    UTF_NEXT_CHAR(decomp, decompPos, decompLen, decompCp);
 
468
 
511
469
    int32_t i = 0;
512
 
    for (i = segmentPos; i < segment.length(); i += UTF16_CHAR_LENGTH(cp)) {
513
 
        cp = segment.char32At(i);
 
470
    i = segmentPos;
 
471
    while(i < segLen) {
 
472
      UTF_NEXT_CHAR(segment, i, segLen, cp);
 
473
 
514
474
        if (cp == decompCp) { // if equal, eat another cp from decomp
515
475
 
516
476
            //if (PROGRESS) printf("  matches: %s\n", UToS(Tr(UnicodeString(cp))));
517
477
 
518
 
            if (decompPos == decomp.length()) { // done, have all decomp characters!
519
 
                //buffer.append(segment.substring(i + UTF16.getCharCount(cp))); // add remaining segment chars
520
 
              buffer.append(segment, i+UTF16_CHAR_LENGTH(cp), segment.length()-i-UTF16_CHAR_LENGTH(cp));
 
478
            if (decompPos == decompLen) { // done, have all decomp characters!
 
479
                //u_strcat(buff+bufLen, segment+i);
 
480
                memcpy(buff+bufLen, segment+i, (segLen-i)*sizeof(UChar));
 
481
                bufLen+=segLen-i;
 
482
 
521
483
                ok = TRUE;
522
484
                break;
523
485
            }
524
 
            decompCp = decomp.char32At(decompPos);
525
 
            decompPos += UTF16_CHAR_LENGTH(decompCp);
526
 
            //decompClass = getClass(decompCp);
 
486
            UTF_NEXT_CHAR(decomp, decompPos, decompLen, decompCp);
527
487
        } else {
528
488
            //if (PROGRESS) printf("  buffer: %s\n", UToS(Tr(UnicodeString(cp))));
529
489
 
530
490
            // brute force approach
531
491
 
532
 
          
533
 
            //UTF16.append(buffer, cp);
534
 
            buffer.append(cp);
 
492
          UTF_APPEND_CHAR(buff, bufLen, bufSize, cp);
535
493
 
536
494
            /* TODO: optimize
537
495
            // since we know that the classes are monotonically increasing, after zero
540
498
            // there are only a few cases that work: zero, less, same, greater
541
499
            // if both classes are the same, we fail
542
500
            // if the decomp class < the segment class, we fail
543
 
    
 
501
 
544
502
            segClass = getClass(cp);
545
503
            if (decompClass <= segClass) return null;
546
504
            */
550
508
 
551
509
    //if (PROGRESS) printf("Matches\n");
552
510
 
553
 
    if (buffer.length() == 0) {
 
511
    if (bufLen == 0) {
554
512
      Hashtable *result = new Hashtable(FALSE, status);
555
513
      result->setValueDeleter(uhash_deleteUnicodeString);
556
514
      result->put("", new UnicodeString(""), status);
557
515
      return result; // succeed, but no remainder
558
516
    }
559
517
 
560
 
    //String remainder = buffer.toString();
561
 
    UnicodeString remainder = buffer;
562
 
    
563
518
    // brute force approach
564
519
    // check to make sure result is canonically equivalent
565
 
    //String trial = Normalizer.normalize(UTF16.valueOf(comp) + remainder, Normalizer.DECOMP, 0);
566
 
    UnicodeString trial;
567
 
    UnicodeString temp = remainder;
568
 
    temp.insert(0, comp);
569
 
    Normalizer::normalize(temp, UNORM_NFD, 0, trial, status);
570
 
 
571
 
    //if (!segment.regionMatches(segmentPos, trial, 0, segment.length() - segmentPos)) return null;
572
 
    if (segment.indexOf(trial, 0, segment.length() - segmentPos, segmentPos, segment.length() - segmentPos)==-1) {
 
520
    int32_t tempLen = inputLen + bufLen;
 
521
 
 
522
    UChar trial[bufSize];
 
523
    unorm_decompose(trial, bufSize, temp, tempLen, FALSE, FALSE, &status);
 
524
 
 
525
    if(uprv_memcmp(segment+segmentPos, trial, (segLen - segmentPos)*sizeof(UChar)) != 0) {
573
526
      return NULL;
574
527
    }
575
 
    
576
 
    // get the remaining combinations
577
 
    return getEquivalents2(remainder, status);
 
528
 
 
529
    return getEquivalents2(buff, bufLen, status);
578
530
}
579
531
 
580
532