• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 *******************************************************************************
3 * Copyright (C) 2010-2014, International Business Machines
4 * Corporation and others.  All Rights Reserved.
5 *******************************************************************************
6 * collationiterator.cpp
7 *
8 * created on: 2010oct27
9 * created by: Markus W. Scherer
10 */
11 
12 #include "utypeinfo.h"  // for 'typeid' to work
13 
14 #include "unicode/utypes.h"
15 
16 #if !UCONFIG_NO_COLLATION
17 
18 #include "unicode/ucharstrie.h"
19 #include "unicode/ustringtrie.h"
20 #include "charstr.h"
21 #include "cmemory.h"
22 #include "collation.h"
23 #include "collationdata.h"
24 #include "collationfcd.h"
25 #include "collationiterator.h"
26 #include "normalizer2impl.h"
27 #include "uassert.h"
28 #include "uvectr32.h"
29 
30 U_NAMESPACE_BEGIN
31 
~CEBuffer()32 CollationIterator::CEBuffer::~CEBuffer() {}
33 
34 UBool
ensureAppendCapacity(int32_t appCap,UErrorCode & errorCode)35 CollationIterator::CEBuffer::ensureAppendCapacity(int32_t appCap, UErrorCode &errorCode) {
36     int32_t capacity = buffer.getCapacity();
37     if((length + appCap) <= capacity) { return TRUE; }
38     if(U_FAILURE(errorCode)) { return FALSE; }
39     do {
40         if(capacity < 1000) {
41             capacity *= 4;
42         } else {
43             capacity *= 2;
44         }
45     } while(capacity < (length + appCap));
46     int64_t *p = buffer.resize(capacity, length);
47     if(p == NULL) {
48         errorCode = U_MEMORY_ALLOCATION_ERROR;
49         return FALSE;
50     }
51     return TRUE;
52 }
53 
54 // State of combining marks skipped in discontiguous contraction.
55 // We create a state object on first use and keep it around deactivated between uses.
56 class SkippedState : public UMemory {
57 public:
58     // Born active but empty.
SkippedState()59     SkippedState() : pos(0), skipLengthAtMatch(0) {}
clear()60     void clear() {
61         oldBuffer.remove();
62         pos = 0;
63         // The newBuffer is reset by setFirstSkipped().
64     }
65 
isEmpty() const66     UBool isEmpty() const { return oldBuffer.isEmpty(); }
67 
hasNext() const68     UBool hasNext() const { return pos < oldBuffer.length(); }
69 
70     // Requires hasNext().
next()71     UChar32 next() {
72         UChar32 c = oldBuffer.char32At(pos);
73         pos += U16_LENGTH(c);
74         return c;
75     }
76 
77     // Accounts for one more input code point read beyond the end of the marks buffer.
incBeyond()78     void incBeyond() {
79         U_ASSERT(!hasNext());
80         ++pos;
81     }
82 
83     // Goes backward through the skipped-marks buffer.
84     // Returns the number of code points read beyond the skipped marks
85     // that need to be backtracked through normal input.
backwardNumCodePoints(int32_t n)86     int32_t backwardNumCodePoints(int32_t n) {
87         int32_t length = oldBuffer.length();
88         int32_t beyond = pos - length;
89         if(beyond > 0) {
90             if(beyond >= n) {
91                 // Not back far enough to re-enter the oldBuffer.
92                 pos -= n;
93                 return n;
94             } else {
95                 // Back out all beyond-oldBuffer code points and re-enter the buffer.
96                 pos = oldBuffer.moveIndex32(length, beyond - n);
97                 return beyond;
98             }
99         } else {
100             // Go backwards from inside the oldBuffer.
101             pos = oldBuffer.moveIndex32(pos, -n);
102             return 0;
103         }
104     }
105 
setFirstSkipped(UChar32 c)106     void setFirstSkipped(UChar32 c) {
107         skipLengthAtMatch = 0;
108         newBuffer.setTo(c);
109     }
110 
skip(UChar32 c)111     void skip(UChar32 c) {
112         newBuffer.append(c);
113     }
114 
recordMatch()115     void recordMatch() { skipLengthAtMatch = newBuffer.length(); }
116 
117     // Replaces the characters we consumed with the newly skipped ones.
replaceMatch()118     void replaceMatch() {
119         // Note: UnicodeString.replace() pins pos to at most length().
120         oldBuffer.replace(0, pos, newBuffer, 0, skipLengthAtMatch);
121         pos = 0;
122     }
123 
saveTrieState(const UCharsTrie & trie)124     void saveTrieState(const UCharsTrie &trie) { trie.saveState(state); }
resetToTrieState(UCharsTrie & trie) const125     void resetToTrieState(UCharsTrie &trie) const { trie.resetToState(state); }
126 
127 private:
128     // Combining marks skipped in previous discontiguous-contraction matching.
129     // After that discontiguous contraction was completed, we start reading them from here.
130     UnicodeString oldBuffer;
131     // Combining marks newly skipped in current discontiguous-contraction matching.
132     // These might have been read from the normal text or from the oldBuffer.
133     UnicodeString newBuffer;
134     // Reading index in oldBuffer,
135     // or counter for how many code points have been read beyond oldBuffer (pos-oldBuffer.length()).
136     int32_t pos;
137     // newBuffer.length() at the time of the last matching character.
138     // When a partial match fails, we back out skipped and partial-matching input characters.
139     int32_t skipLengthAtMatch;
140     // We save the trie state before we attempt to match a character,
141     // so that we can skip it and try the next one.
142     UCharsTrie::State state;
143 };
144 
CollationIterator(const CollationIterator & other)145 CollationIterator::CollationIterator(const CollationIterator &other)
146         : UObject(other),
147           trie(other.trie),
148           data(other.data),
149           cesIndex(other.cesIndex),
150           skipped(NULL),
151           numCpFwd(other.numCpFwd),
152           isNumeric(other.isNumeric) {
153     UErrorCode errorCode = U_ZERO_ERROR;
154     int32_t length = other.ceBuffer.length;
155     if(length > 0 && ceBuffer.ensureAppendCapacity(length, errorCode)) {
156         for(int32_t i = 0; i < length; ++i) {
157             ceBuffer.set(i, other.ceBuffer.get(i));
158         }
159         ceBuffer.length = length;
160     } else {
161         cesIndex = 0;
162     }
163 }
164 
~CollationIterator()165 CollationIterator::~CollationIterator() {
166     delete skipped;
167 }
168 
169 UBool
operator ==(const CollationIterator & other) const170 CollationIterator::operator==(const CollationIterator &other) const {
171     // Subclasses: Call this method and then add more specific checks.
172     // Compare the iterator state but not the collation data (trie & data fields):
173     // Assume that the caller compares the data.
174     // Ignore skipped since that should be unused between calls to nextCE().
175     // (It only stays around to avoid another memory allocation.)
176     if(!(typeid(*this) == typeid(other) &&
177             ceBuffer.length == other.ceBuffer.length &&
178             cesIndex == other.cesIndex &&
179             numCpFwd == other.numCpFwd &&
180             isNumeric == other.isNumeric)) {
181         return FALSE;
182     }
183     for(int32_t i = 0; i < ceBuffer.length; ++i) {
184         if(ceBuffer.get(i) != other.ceBuffer.get(i)) { return FALSE; }
185     }
186     return TRUE;
187 }
188 
189 void
reset()190 CollationIterator::reset() {
191     cesIndex = ceBuffer.length = 0;
192     if(skipped != NULL) { skipped->clear(); }
193 }
194 
195 int32_t
fetchCEs(UErrorCode & errorCode)196 CollationIterator::fetchCEs(UErrorCode &errorCode) {
197     while(U_SUCCESS(errorCode) && nextCE(errorCode) != Collation::NO_CE) {
198         // No need to loop for each expansion CE.
199         cesIndex = ceBuffer.length;
200     }
201     return ceBuffer.length;
202 }
203 
204 uint32_t
handleNextCE32(UChar32 & c,UErrorCode & errorCode)205 CollationIterator::handleNextCE32(UChar32 &c, UErrorCode &errorCode) {
206     c = nextCodePoint(errorCode);
207     return (c < 0) ? Collation::FALLBACK_CE32 : data->getCE32(c);
208 }
209 
210 UChar
handleGetTrailSurrogate()211 CollationIterator::handleGetTrailSurrogate() {
212     return 0;
213 }
214 
215 UBool
foundNULTerminator()216 CollationIterator::foundNULTerminator() {
217     return FALSE;
218 }
219 
220 UBool
forbidSurrogateCodePoints() const221 CollationIterator::forbidSurrogateCodePoints() const {
222     return FALSE;
223 }
224 
225 uint32_t
getDataCE32(UChar32 c) const226 CollationIterator::getDataCE32(UChar32 c) const {
227     return data->getCE32(c);
228 }
229 
230 uint32_t
getCE32FromBuilderData(uint32_t,UErrorCode & errorCode)231 CollationIterator::getCE32FromBuilderData(uint32_t /*ce32*/, UErrorCode &errorCode) {
232     if(U_SUCCESS(errorCode)) { errorCode = U_INTERNAL_PROGRAM_ERROR; }
233     return 0;
234 }
235 
236 int64_t
nextCEFromCE32(const CollationData * d,UChar32 c,uint32_t ce32,UErrorCode & errorCode)237 CollationIterator::nextCEFromCE32(const CollationData *d, UChar32 c, uint32_t ce32,
238                                   UErrorCode &errorCode) {
239     --ceBuffer.length;  // Undo ceBuffer.incLength().
240     appendCEsFromCE32(d, c, ce32, TRUE, errorCode);
241     if(U_SUCCESS(errorCode)) {
242         return ceBuffer.get(cesIndex++);
243     } else {
244         return Collation::NO_CE_PRIMARY;
245     }
246 }
247 
248 void
appendCEsFromCE32(const CollationData * d,UChar32 c,uint32_t ce32,UBool forward,UErrorCode & errorCode)249 CollationIterator::appendCEsFromCE32(const CollationData *d, UChar32 c, uint32_t ce32,
250                                      UBool forward, UErrorCode &errorCode) {
251     while(Collation::isSpecialCE32(ce32)) {
252         switch(Collation::tagFromCE32(ce32)) {
253         case Collation::FALLBACK_TAG:
254         case Collation::RESERVED_TAG_3:
255             if(U_SUCCESS(errorCode)) { errorCode = U_INTERNAL_PROGRAM_ERROR; }
256             return;
257         case Collation::LONG_PRIMARY_TAG:
258             ceBuffer.append(Collation::ceFromLongPrimaryCE32(ce32), errorCode);
259             return;
260         case Collation::LONG_SECONDARY_TAG:
261             ceBuffer.append(Collation::ceFromLongSecondaryCE32(ce32), errorCode);
262             return;
263         case Collation::LATIN_EXPANSION_TAG:
264             if(ceBuffer.ensureAppendCapacity(2, errorCode)) {
265                 ceBuffer.set(ceBuffer.length, Collation::latinCE0FromCE32(ce32));
266                 ceBuffer.set(ceBuffer.length + 1, Collation::latinCE1FromCE32(ce32));
267                 ceBuffer.length += 2;
268             }
269             return;
270         case Collation::EXPANSION32_TAG: {
271             const uint32_t *ce32s = d->ce32s + Collation::indexFromCE32(ce32);
272             int32_t length = Collation::lengthFromCE32(ce32);
273             if(ceBuffer.ensureAppendCapacity(length, errorCode)) {
274                 do {
275                     ceBuffer.appendUnsafe(Collation::ceFromCE32(*ce32s++));
276                 } while(--length > 0);
277             }
278             return;
279         }
280         case Collation::EXPANSION_TAG: {
281             const int64_t *ces = d->ces + Collation::indexFromCE32(ce32);
282             int32_t length = Collation::lengthFromCE32(ce32);
283             if(ceBuffer.ensureAppendCapacity(length, errorCode)) {
284                 do {
285                     ceBuffer.appendUnsafe(*ces++);
286                 } while(--length > 0);
287             }
288             return;
289         }
290         case Collation::BUILDER_DATA_TAG:
291             ce32 = getCE32FromBuilderData(ce32, errorCode);
292             if(U_FAILURE(errorCode)) { return; }
293             if(ce32 == Collation::FALLBACK_CE32) {
294                 d = data->base;
295                 ce32 = d->getCE32(c);
296             }
297             break;
298         case Collation::PREFIX_TAG:
299             if(forward) { backwardNumCodePoints(1, errorCode); }
300             ce32 = getCE32FromPrefix(d, ce32, errorCode);
301             if(forward) { forwardNumCodePoints(1, errorCode); }
302             break;
303         case Collation::CONTRACTION_TAG: {
304             const UChar *p = d->contexts + Collation::indexFromCE32(ce32);
305             uint32_t defaultCE32 = CollationData::readCE32(p);  // Default if no suffix match.
306             if(!forward) {
307                 // Backward contractions are handled by previousCEUnsafe().
308                 // c has contractions but they were not found.
309                 ce32 = defaultCE32;
310                 break;
311             }
312             UChar32 nextCp;
313             if(skipped == NULL && numCpFwd < 0) {
314                 // Some portion of nextCE32FromContraction() pulled out here as an ASCII fast path,
315                 // avoiding the function call and the nextSkippedCodePoint() overhead.
316                 nextCp = nextCodePoint(errorCode);
317                 if(nextCp < 0) {
318                     // No more text.
319                     ce32 = defaultCE32;
320                     break;
321                 } else if((ce32 & Collation::CONTRACT_NEXT_CCC) != 0 &&
322                         !CollationFCD::mayHaveLccc(nextCp)) {
323                     // All contraction suffixes start with characters with lccc!=0
324                     // but the next code point has lccc==0.
325                     backwardNumCodePoints(1, errorCode);
326                     ce32 = defaultCE32;
327                     break;
328                 }
329             } else {
330                 nextCp = nextSkippedCodePoint(errorCode);
331                 if(nextCp < 0) {
332                     // No more text.
333                     ce32 = defaultCE32;
334                     break;
335                 } else if((ce32 & Collation::CONTRACT_NEXT_CCC) != 0 &&
336                         !CollationFCD::mayHaveLccc(nextCp)) {
337                     // All contraction suffixes start with characters with lccc!=0
338                     // but the next code point has lccc==0.
339                     backwardNumSkipped(1, errorCode);
340                     ce32 = defaultCE32;
341                     break;
342                 }
343             }
344             ce32 = nextCE32FromContraction(d, ce32, p + 2, defaultCE32, nextCp, errorCode);
345             if(ce32 == Collation::NO_CE32) {
346                 // CEs from a discontiguous contraction plus the skipped combining marks
347                 // have been appended already.
348                 return;
349             }
350             break;
351         }
352         case Collation::DIGIT_TAG:
353             if(isNumeric) {
354                 appendNumericCEs(ce32, forward, errorCode);
355                 return;
356             } else {
357                 // Fetch the non-numeric-collation CE32 and continue.
358                 ce32 = d->ce32s[Collation::indexFromCE32(ce32)];
359                 break;
360             }
361         case Collation::U0000_TAG:
362             U_ASSERT(c == 0);
363             if(forward && foundNULTerminator()) {
364                 // Handle NUL-termination. (Not needed in Java.)
365                 ceBuffer.append(Collation::NO_CE, errorCode);
366                 return;
367             } else {
368                 // Fetch the normal ce32 for U+0000 and continue.
369                 ce32 = d->ce32s[0];
370                 break;
371             }
372         case Collation::HANGUL_TAG: {
373             const uint32_t *jamoCE32s = d->jamoCE32s;
374             c -= Hangul::HANGUL_BASE;
375             UChar32 t = c % Hangul::JAMO_T_COUNT;
376             c /= Hangul::JAMO_T_COUNT;
377             UChar32 v = c % Hangul::JAMO_V_COUNT;
378             c /= Hangul::JAMO_V_COUNT;
379             if((ce32 & Collation::HANGUL_NO_SPECIAL_JAMO) != 0) {
380                 // None of the Jamo CE32s are isSpecialCE32().
381                 // Avoid recursive function calls and per-Jamo tests.
382                 if(ceBuffer.ensureAppendCapacity(t == 0 ? 2 : 3, errorCode)) {
383                     ceBuffer.set(ceBuffer.length, Collation::ceFromCE32(jamoCE32s[c]));
384                     ceBuffer.set(ceBuffer.length + 1, Collation::ceFromCE32(jamoCE32s[19 + v]));
385                     ceBuffer.length += 2;
386                     if(t != 0) {
387                         ceBuffer.appendUnsafe(Collation::ceFromCE32(jamoCE32s[39 + t]));
388                     }
389                 }
390                 return;
391             } else {
392                 // We should not need to compute each Jamo code point.
393                 // In particular, there should be no offset or implicit ce32.
394                 appendCEsFromCE32(d, U_SENTINEL, jamoCE32s[c], forward, errorCode);
395                 appendCEsFromCE32(d, U_SENTINEL, jamoCE32s[19 + v], forward, errorCode);
396                 if(t == 0) { return; }
397                 // offset 39 = 19 + 21 - 1:
398                 // 19 = JAMO_L_COUNT
399                 // 21 = JAMO_T_COUNT
400                 // -1 = omit t==0
401                 ce32 = jamoCE32s[39 + t];
402                 c = U_SENTINEL;
403                 break;
404             }
405         }
406         case Collation::LEAD_SURROGATE_TAG: {
407             U_ASSERT(forward);  // Backward iteration should never see lead surrogate code _unit_ data.
408             U_ASSERT(U16_IS_LEAD(c));
409             UChar trail;
410             if(U16_IS_TRAIL(trail = handleGetTrailSurrogate())) {
411                 c = U16_GET_SUPPLEMENTARY(c, trail);
412                 ce32 &= Collation::LEAD_TYPE_MASK;
413                 if(ce32 == Collation::LEAD_ALL_UNASSIGNED) {
414                     ce32 = Collation::UNASSIGNED_CE32;  // unassigned-implicit
415                 } else if(ce32 == Collation::LEAD_ALL_FALLBACK ||
416                         (ce32 = d->getCE32FromSupplementary(c)) == Collation::FALLBACK_CE32) {
417                     // fall back to the base data
418                     d = d->base;
419                     ce32 = d->getCE32FromSupplementary(c);
420                 }
421             } else {
422                 // c is an unpaired surrogate.
423                 ce32 = Collation::UNASSIGNED_CE32;
424             }
425             break;
426         }
427         case Collation::OFFSET_TAG:
428             U_ASSERT(c >= 0);
429             ceBuffer.append(d->getCEFromOffsetCE32(c, ce32), errorCode);
430             return;
431         case Collation::IMPLICIT_TAG:
432             U_ASSERT(c >= 0);
433             if(U_IS_SURROGATE(c) && forbidSurrogateCodePoints()) {
434                 ce32 = Collation::FFFD_CE32;
435                 break;
436             } else {
437                 ceBuffer.append(Collation::unassignedCEFromCodePoint(c), errorCode);
438                 return;
439             }
440         }
441     }
442     ceBuffer.append(Collation::ceFromSimpleCE32(ce32), errorCode);
443 }
444 
445 uint32_t
getCE32FromPrefix(const CollationData * d,uint32_t ce32,UErrorCode & errorCode)446 CollationIterator::getCE32FromPrefix(const CollationData *d, uint32_t ce32,
447                                      UErrorCode &errorCode) {
448     const UChar *p = d->contexts + Collation::indexFromCE32(ce32);
449     ce32 = CollationData::readCE32(p);  // Default if no prefix match.
450     p += 2;
451     // Number of code points read before the original code point.
452     int32_t lookBehind = 0;
453     UCharsTrie prefixes(p);
454     for(;;) {
455         UChar32 c = previousCodePoint(errorCode);
456         if(c < 0) { break; }
457         ++lookBehind;
458         UStringTrieResult match = prefixes.nextForCodePoint(c);
459         if(USTRINGTRIE_HAS_VALUE(match)) {
460             ce32 = (uint32_t)prefixes.getValue();
461         }
462         if(!USTRINGTRIE_HAS_NEXT(match)) { break; }
463     }
464     forwardNumCodePoints(lookBehind, errorCode);
465     return ce32;
466 }
467 
468 UChar32
nextSkippedCodePoint(UErrorCode & errorCode)469 CollationIterator::nextSkippedCodePoint(UErrorCode &errorCode) {
470     if(skipped != NULL && skipped->hasNext()) { return skipped->next(); }
471     if(numCpFwd == 0) { return U_SENTINEL; }
472     UChar32 c = nextCodePoint(errorCode);
473     if(skipped != NULL && !skipped->isEmpty() && c >= 0) { skipped->incBeyond(); }
474     if(numCpFwd > 0 && c >= 0) { --numCpFwd; }
475     return c;
476 }
477 
478 void
backwardNumSkipped(int32_t n,UErrorCode & errorCode)479 CollationIterator::backwardNumSkipped(int32_t n, UErrorCode &errorCode) {
480     if(skipped != NULL && !skipped->isEmpty()) {
481         n = skipped->backwardNumCodePoints(n);
482     }
483     backwardNumCodePoints(n, errorCode);
484     if(numCpFwd >= 0) { numCpFwd += n; }
485 }
486 
487 uint32_t
nextCE32FromContraction(const CollationData * d,uint32_t contractionCE32,const UChar * p,uint32_t ce32,UChar32 c,UErrorCode & errorCode)488 CollationIterator::nextCE32FromContraction(const CollationData *d, uint32_t contractionCE32,
489                                            const UChar *p, uint32_t ce32, UChar32 c,
490                                            UErrorCode &errorCode) {
491     // c: next code point after the original one
492 
493     // Number of code points read beyond the original code point.
494     // Needed for discontiguous contraction matching.
495     int32_t lookAhead = 1;
496     // Number of code points read since the last match (initially only c).
497     int32_t sinceMatch = 1;
498     // Normally we only need a contiguous match,
499     // and therefore need not remember the suffixes state from before a mismatch for retrying.
500     // If we are already processing skipped combining marks, then we do track the state.
501     UCharsTrie suffixes(p);
502     if(skipped != NULL && !skipped->isEmpty()) { skipped->saveTrieState(suffixes); }
503     UStringTrieResult match = suffixes.firstForCodePoint(c);
504     for(;;) {
505         UChar32 nextCp;
506         if(USTRINGTRIE_HAS_VALUE(match)) {
507             ce32 = (uint32_t)suffixes.getValue();
508             if(!USTRINGTRIE_HAS_NEXT(match) || (c = nextSkippedCodePoint(errorCode)) < 0) {
509                 return ce32;
510             }
511             if(skipped != NULL && !skipped->isEmpty()) { skipped->saveTrieState(suffixes); }
512             sinceMatch = 1;
513         } else if(match == USTRINGTRIE_NO_MATCH || (nextCp = nextSkippedCodePoint(errorCode)) < 0) {
514             // No match for c, or partial match (USTRINGTRIE_NO_VALUE) and no further text.
515             // Back up if necessary, and try a discontiguous contraction.
516             if((contractionCE32 & Collation::CONTRACT_TRAILING_CCC) != 0 &&
517                     // Discontiguous contraction matching extends an existing match.
518                     // If there is no match yet, then there is nothing to do.
519                     ((contractionCE32 & Collation::CONTRACT_SINGLE_CP_NO_MATCH) == 0 ||
520                         sinceMatch < lookAhead)) {
521                 // The last character of at least one suffix has lccc!=0,
522                 // allowing for discontiguous contractions.
523                 // UCA S2.1.1 only processes non-starters immediately following
524                 // "a match in the table" (sinceMatch=1).
525                 if(sinceMatch > 1) {
526                     // Return to the state after the last match.
527                     // (Return to sinceMatch=0 and re-fetch the first partially-matched character.)
528                     backwardNumSkipped(sinceMatch, errorCode);
529                     c = nextSkippedCodePoint(errorCode);
530                     lookAhead -= sinceMatch - 1;
531                     sinceMatch = 1;
532                 }
533                 if(d->getFCD16(c) > 0xff) {
534                     return nextCE32FromDiscontiguousContraction(
535                         d, suffixes, ce32, lookAhead, c, errorCode);
536                 }
537             }
538             break;
539         } else {
540             // Continue after partial match (USTRINGTRIE_NO_VALUE) for c.
541             // It does not have a result value, therefore it is not itself "a match in the table".
542             // If a partially-matched c has ccc!=0 then
543             // it might be skipped in discontiguous contraction.
544             c = nextCp;
545             ++sinceMatch;
546         }
547         ++lookAhead;
548         match = suffixes.nextForCodePoint(c);
549     }
550     backwardNumSkipped(sinceMatch, errorCode);
551     return ce32;
552 }
553 
554 uint32_t
nextCE32FromDiscontiguousContraction(const CollationData * d,UCharsTrie & suffixes,uint32_t ce32,int32_t lookAhead,UChar32 c,UErrorCode & errorCode)555 CollationIterator::nextCE32FromDiscontiguousContraction(
556         const CollationData *d, UCharsTrie &suffixes, uint32_t ce32,
557         int32_t lookAhead, UChar32 c,
558         UErrorCode &errorCode) {
559     if(U_FAILURE(errorCode)) { return 0; }
560 
561     // UCA section 3.3.2 Contractions:
562     // Contractions that end with non-starter characters
563     // are known as discontiguous contractions.
564     // ... discontiguous contractions must be detected in input text
565     // whenever the final sequence of non-starter characters could be rearranged
566     // so as to make a contiguous matching sequence that is canonically equivalent.
567 
568     // UCA: http://www.unicode.org/reports/tr10/#S2.1
569     // S2.1 Find the longest initial substring S at each point that has a match in the table.
570     // S2.1.1 If there are any non-starters following S, process each non-starter C.
571     // S2.1.2 If C is not blocked from S, find if S + C has a match in the table.
572     //     Note: A non-starter in a string is called blocked
573     //     if there is another non-starter of the same canonical combining class or zero
574     //     between it and the last character of canonical combining class 0.
575     // S2.1.3 If there is a match, replace S by S + C, and remove C.
576 
577     // First: Is a discontiguous contraction even possible?
578     uint16_t fcd16 = d->getFCD16(c);
579     U_ASSERT(fcd16 > 0xff);  // The caller checked this already, as a shortcut.
580     UChar32 nextCp = nextSkippedCodePoint(errorCode);
581     if(nextCp < 0) {
582         // No further text.
583         backwardNumSkipped(1, errorCode);
584         return ce32;
585     }
586     ++lookAhead;
587     uint8_t prevCC = (uint8_t)fcd16;
588     fcd16 = d->getFCD16(nextCp);
589     if(fcd16 <= 0xff) {
590         // The next code point after c is a starter (S2.1.1 "process each non-starter").
591         backwardNumSkipped(2, errorCode);
592         return ce32;
593     }
594 
595     // We have read and matched (lookAhead-2) code points,
596     // read non-matching c and peeked ahead at nextCp.
597     // Return to the state before the mismatch and continue matching with nextCp.
598     if(skipped == NULL || skipped->isEmpty()) {
599         if(skipped == NULL) {
600             skipped = new SkippedState();
601             if(skipped == NULL) {
602                 errorCode = U_MEMORY_ALLOCATION_ERROR;
603                 return 0;
604             }
605         }
606         suffixes.reset();
607         if(lookAhead > 2) {
608             // Replay the partial match so far.
609             backwardNumCodePoints(lookAhead, errorCode);
610             suffixes.firstForCodePoint(nextCodePoint(errorCode));
611             for(int32_t i = 3; i < lookAhead; ++i) {
612                 suffixes.nextForCodePoint(nextCodePoint(errorCode));
613             }
614             // Skip c (which did not match) and nextCp (which we will try now).
615             forwardNumCodePoints(2, errorCode);
616         }
617         skipped->saveTrieState(suffixes);
618     } else {
619         // Reset to the trie state before the failed match of c.
620         skipped->resetToTrieState(suffixes);
621     }
622 
623     skipped->setFirstSkipped(c);
624     // Number of code points read since the last match (at this point: c and nextCp).
625     int32_t sinceMatch = 2;
626     c = nextCp;
627     for(;;) {
628         UStringTrieResult match;
629         // "If C is not blocked from S, find if S + C has a match in the table." (S2.1.2)
630         if(prevCC < (fcd16 >> 8) && USTRINGTRIE_HAS_VALUE(match = suffixes.nextForCodePoint(c))) {
631             // "If there is a match, replace S by S + C, and remove C." (S2.1.3)
632             // Keep prevCC unchanged.
633             ce32 = (uint32_t)suffixes.getValue();
634             sinceMatch = 0;
635             skipped->recordMatch();
636             if(!USTRINGTRIE_HAS_NEXT(match)) { break; }
637             skipped->saveTrieState(suffixes);
638         } else {
639             // No match for "S + C", skip C.
640             skipped->skip(c);
641             skipped->resetToTrieState(suffixes);
642             prevCC = (uint8_t)fcd16;
643         }
644         if((c = nextSkippedCodePoint(errorCode)) < 0) { break; }
645         ++sinceMatch;
646         fcd16 = d->getFCD16(c);
647         if(fcd16 <= 0xff) {
648             // The next code point after c is a starter (S2.1.1 "process each non-starter").
649             break;
650         }
651     }
652     backwardNumSkipped(sinceMatch, errorCode);
653     UBool isTopDiscontiguous = skipped->isEmpty();
654     skipped->replaceMatch();
655     if(isTopDiscontiguous && !skipped->isEmpty()) {
656         // We did get a match after skipping one or more combining marks,
657         // and we are not in a recursive discontiguous contraction.
658         // Append CEs from the contraction ce32
659         // and then from the combining marks that we skipped before the match.
660         c = U_SENTINEL;
661         for(;;) {
662             appendCEsFromCE32(d, c, ce32, TRUE, errorCode);
663             // Fetch CE32s for skipped combining marks from the normal data, with fallback,
664             // rather than from the CollationData where we found the contraction.
665             if(!skipped->hasNext()) { break; }
666             c = skipped->next();
667             ce32 = getDataCE32(c);
668             if(ce32 == Collation::FALLBACK_CE32) {
669                 d = data->base;
670                 ce32 = d->getCE32(c);
671             } else {
672                 d = data;
673             }
674             // Note: A nested discontiguous-contraction match
675             // replaces consumed combining marks with newly skipped ones
676             // and resets the reading position to the beginning.
677         }
678         skipped->clear();
679         ce32 = Collation::NO_CE32;  // Signal to the caller that the result is in the ceBuffer.
680     }
681     return ce32;
682 }
683 
684 void
appendNumericCEs(uint32_t ce32,UBool forward,UErrorCode & errorCode)685 CollationIterator::appendNumericCEs(uint32_t ce32, UBool forward, UErrorCode &errorCode) {
686     // Collect digits.
687     CharString digits;
688     if(forward) {
689         for(;;) {
690             char digit = Collation::digitFromCE32(ce32);
691             digits.append(digit, errorCode);
692             if(numCpFwd == 0) { break; }
693             UChar32 c = nextCodePoint(errorCode);
694             if(c < 0) { break; }
695             ce32 = data->getCE32(c);
696             if(ce32 == Collation::FALLBACK_CE32) {
697                 ce32 = data->base->getCE32(c);
698             }
699             if(!Collation::hasCE32Tag(ce32, Collation::DIGIT_TAG)) {
700                 backwardNumCodePoints(1, errorCode);
701                 break;
702             }
703             if(numCpFwd > 0) { --numCpFwd; }
704         }
705     } else {
706         for(;;) {
707             char digit = Collation::digitFromCE32(ce32);
708             digits.append(digit, errorCode);
709             UChar32 c = previousCodePoint(errorCode);
710             if(c < 0) { break; }
711             ce32 = data->getCE32(c);
712             if(ce32 == Collation::FALLBACK_CE32) {
713                 ce32 = data->base->getCE32(c);
714             }
715             if(!Collation::hasCE32Tag(ce32, Collation::DIGIT_TAG)) {
716                 forwardNumCodePoints(1, errorCode);
717                 break;
718             }
719         }
720         // Reverse the digit string.
721         char *p = digits.data();
722         char *q = p + digits.length() - 1;
723         while(p < q) {
724             char digit = *p;
725             *p++ = *q;
726             *q-- = digit;
727         }
728     }
729     if(U_FAILURE(errorCode)) { return; }
730     int32_t pos = 0;
731     do {
732         // Skip leading zeros.
733         while(pos < (digits.length() - 1) && digits[pos] == 0) { ++pos; }
734         // Write a sequence of CEs for at most 254 digits at a time.
735         int32_t segmentLength = digits.length() - pos;
736         if(segmentLength > 254) { segmentLength = 254; }
737         appendNumericSegmentCEs(digits.data() + pos, segmentLength, errorCode);
738         pos += segmentLength;
739     } while(U_SUCCESS(errorCode) && pos < digits.length());
740 }
741 
742 void
appendNumericSegmentCEs(const char * digits,int32_t length,UErrorCode & errorCode)743 CollationIterator::appendNumericSegmentCEs(const char *digits, int32_t length, UErrorCode &errorCode) {
744     U_ASSERT(1 <= length && length <= 254);
745     U_ASSERT(length == 1 || digits[0] != 0);
746     uint32_t numericPrimary = data->numericPrimary;
747     // Note: We use primary byte values 2..255: digits are not compressible.
748     if(length <= 7) {
749         // Very dense encoding for small numbers.
750         int32_t value = digits[0];
751         for(int32_t i = 1; i < length; ++i) {
752             value = value * 10 + digits[i];
753         }
754         // Primary weight second byte values:
755         //     74 byte values   2.. 75 for small numbers in two-byte primary weights.
756         //     40 byte values  76..115 for medium numbers in three-byte primary weights.
757         //     16 byte values 116..131 for large numbers in four-byte primary weights.
758         //    124 byte values 132..255 for very large numbers with 4..127 digit pairs.
759         int32_t firstByte = 2;
760         int32_t numBytes = 74;
761         if(value < numBytes) {
762             // Two-byte primary for 0..73, good for day & month numbers etc.
763             uint32_t primary = numericPrimary | ((firstByte + value) << 16);
764             ceBuffer.append(Collation::makeCE(primary), errorCode);
765             return;
766         }
767         value -= numBytes;
768         firstByte += numBytes;
769         numBytes = 40;
770         if(value < numBytes * 254) {
771             // Three-byte primary for 74..10233=74+40*254-1, good for year numbers and more.
772             uint32_t primary = numericPrimary |
773                 ((firstByte + value / 254) << 16) | ((2 + value % 254) << 8);
774             ceBuffer.append(Collation::makeCE(primary), errorCode);
775             return;
776         }
777         value -= numBytes * 254;
778         firstByte += numBytes;
779         numBytes = 16;
780         if(value < numBytes * 254 * 254) {
781             // Four-byte primary for 10234..1042489=10234+16*254*254-1.
782             uint32_t primary = numericPrimary | (2 + value % 254);
783             value /= 254;
784             primary |= (2 + value % 254) << 8;
785             value /= 254;
786             primary |= (firstByte + value % 254) << 16;
787             ceBuffer.append(Collation::makeCE(primary), errorCode);
788             return;
789         }
790         // original value > 1042489
791     }
792     U_ASSERT(length >= 7);
793 
794     // The second primary byte value 132..255 indicates the number of digit pairs (4..127),
795     // then we generate primary bytes with those pairs.
796     // Omit trailing 00 pairs.
797     // Decrement the value for the last pair.
798 
799     // Set the exponent. 4 pairs->132, 5 pairs->133, ..., 127 pairs->255.
800     int32_t numPairs = (length + 1) / 2;
801     uint32_t primary = numericPrimary | ((132 - 4 + numPairs) << 16);
802     // Find the length without trailing 00 pairs.
803     while(digits[length - 1] == 0 && digits[length - 2] == 0) {
804         length -= 2;
805     }
806     // Read the first pair.
807     uint32_t pair;
808     int32_t pos;
809     if(length & 1) {
810         // Only "half a pair" if we have an odd number of digits.
811         pair = digits[0];
812         pos = 1;
813     } else {
814         pair = digits[0] * 10 + digits[1];
815         pos = 2;
816     }
817     pair = 11 + 2 * pair;
818     // Add the pairs of digits between pos and length.
819     int32_t shift = 8;
820     while(pos < length) {
821         if(shift == 0) {
822             // Every three pairs/bytes we need to store a 4-byte-primary CE
823             // and start with a new CE with the '0' primary lead byte.
824             primary |= pair;
825             ceBuffer.append(Collation::makeCE(primary), errorCode);
826             primary = numericPrimary;
827             shift = 16;
828         } else {
829             primary |= pair << shift;
830             shift -= 8;
831         }
832         pair = 11 + 2 * (digits[pos] * 10 + digits[pos + 1]);
833         pos += 2;
834     }
835     primary |= (pair - 1) << shift;
836     ceBuffer.append(Collation::makeCE(primary), errorCode);
837 }
838 
839 int64_t
previousCE(UVector32 & offsets,UErrorCode & errorCode)840 CollationIterator::previousCE(UVector32 &offsets, UErrorCode &errorCode) {
841     if(ceBuffer.length > 0) {
842         // Return the previous buffered CE.
843         return ceBuffer.get(--ceBuffer.length);
844     }
845     offsets.removeAllElements();
846     int32_t limitOffset = getOffset();
847     UChar32 c = previousCodePoint(errorCode);
848     if(c < 0) { return Collation::NO_CE; }
849     if(data->isUnsafeBackward(c, isNumeric)) {
850         return previousCEUnsafe(c, offsets, errorCode);
851     }
852     // Simple, safe-backwards iteration:
853     // Get a CE going backwards, handle prefixes but no contractions.
854     uint32_t ce32 = data->getCE32(c);
855     const CollationData *d;
856     if(ce32 == Collation::FALLBACK_CE32) {
857         d = data->base;
858         ce32 = d->getCE32(c);
859     } else {
860         d = data;
861     }
862     if(Collation::isSimpleOrLongCE32(ce32)) {
863         return Collation::ceFromCE32(ce32);
864     }
865     appendCEsFromCE32(d, c, ce32, FALSE, errorCode);
866     if(U_SUCCESS(errorCode)) {
867         if(ceBuffer.length > 1) {
868             offsets.addElement(getOffset(), errorCode);
869             // For an expansion, the offset of each non-initial CE is the limit offset,
870             // consistent with forward iteration.
871             while(offsets.size() <= ceBuffer.length) {
872                 offsets.addElement(limitOffset, errorCode);
873             };
874         }
875         return ceBuffer.get(--ceBuffer.length);
876     } else {
877         return Collation::NO_CE_PRIMARY;
878     }
879 }
880 
881 int64_t
previousCEUnsafe(UChar32 c,UVector32 & offsets,UErrorCode & errorCode)882 CollationIterator::previousCEUnsafe(UChar32 c, UVector32 &offsets, UErrorCode &errorCode) {
883     // We just move through the input counting safe and unsafe code points
884     // without collecting the unsafe-backward substring into a buffer and
885     // switching to it.
886     // This is to keep the logic simple. Otherwise we would have to handle
887     // prefix matching going before the backward buffer, switching
888     // to iteration and back, etc.
889     // In the most important case of iterating over a normal string,
890     // reading from the string itself is already maximally fast.
891     // The only drawback there is that after getting the CEs we always
892     // skip backward to the safe character rather than switching out
893     // of a backwardBuffer.
894     // But this should not be the common case for previousCE(),
895     // and correctness and maintainability are more important than
896     // complex optimizations.
897     // Find the first safe character before c.
898     int32_t numBackward = 1;
899     while((c = previousCodePoint(errorCode)) >= 0) {
900         ++numBackward;
901         if(!data->isUnsafeBackward(c, isNumeric)) {
902             break;
903         }
904     }
905     // Set the forward iteration limit.
906     // Note: This counts code points.
907     // We cannot enforce a limit in the middle of a surrogate pair or similar.
908     numCpFwd = numBackward;
909     // Reset the forward iterator.
910     cesIndex = 0;
911     U_ASSERT(ceBuffer.length == 0);
912     // Go forward and collect the CEs.
913     int32_t offset = getOffset();
914     while(numCpFwd > 0) {
915         // nextCE() normally reads one code point.
916         // Contraction matching and digit specials read more and check numCpFwd.
917         --numCpFwd;
918         // Append one or more CEs to the ceBuffer.
919         (void)nextCE(errorCode);
920         U_ASSERT(U_FAILURE(errorCode) || ceBuffer.get(ceBuffer.length - 1) != Collation::NO_CE);
921         // No need to loop for getting each expansion CE from nextCE().
922         cesIndex = ceBuffer.length;
923         // However, we need to write an offset for each CE.
924         // This is for CollationElementIterator::getOffset() to return
925         // intermediate offsets from the unsafe-backwards segment.
926         U_ASSERT(offsets.size() < ceBuffer.length);
927         offsets.addElement(offset, errorCode);
928         // For an expansion, the offset of each non-initial CE is the limit offset,
929         // consistent with forward iteration.
930         offset = getOffset();
931         while(offsets.size() < ceBuffer.length) {
932             offsets.addElement(offset, errorCode);
933         };
934     }
935     U_ASSERT(offsets.size() == ceBuffer.length);
936     // End offset corresponding to just after the unsafe-backwards segment.
937     offsets.addElement(offset, errorCode);
938     // Reset the forward iteration limit
939     // and move backward to before the segment for which we fetched CEs.
940     numCpFwd = -1;
941     backwardNumCodePoints(numBackward, errorCode);
942     // Use the collected CEs and return the last one.
943     cesIndex = 0;  // Avoid cesIndex > ceBuffer.length when that gets decremented.
944     if(U_SUCCESS(errorCode)) {
945         return ceBuffer.get(--ceBuffer.length);
946     } else {
947         return Collation::NO_CE_PRIMARY;
948     }
949 }
950 
951 U_NAMESPACE_END
952 
953 #endif  // !UCONFIG_NO_COLLATION
954