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 32 CollationIterator::CEBuffer::~CEBuffer() {} 33 34 UBool 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. 59 SkippedState() : pos(0), skipLengthAtMatch(0) {} 60 void clear() { 61 oldBuffer.remove(); 62 pos = 0; 63 // The newBuffer is reset by setFirstSkipped(). 64 } 65 66 UBool isEmpty() const { return oldBuffer.isEmpty(); } 67 68 UBool hasNext() const { return pos < oldBuffer.length(); } 69 70 // Requires hasNext(). 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. 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. 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 106 void setFirstSkipped(UChar32 c) { 107 skipLengthAtMatch = 0; 108 newBuffer.setTo(c); 109 } 110 111 void skip(UChar32 c) { 112 newBuffer.append(c); 113 } 114 115 void recordMatch() { skipLengthAtMatch = newBuffer.length(); } 116 117 // Replaces the characters we consumed with the newly skipped ones. 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 124 void saveTrieState(const UCharsTrie &trie) { trie.saveState(state); } 125 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 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 165 CollationIterator::~CollationIterator() { 166 delete skipped; 167 } 168 169 UBool 170 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 190 CollationIterator::reset() { 191 cesIndex = ceBuffer.length = 0; 192 if(skipped != NULL) { skipped->clear(); } 193 } 194 195 int32_t 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 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 211 CollationIterator::handleGetTrailSurrogate() { 212 return 0; 213 } 214 215 UBool 216 CollationIterator::foundNULTerminator() { 217 return FALSE; 218 } 219 220 UBool 221 CollationIterator::forbidSurrogateCodePoints() const { 222 return FALSE; 223 } 224 225 uint32_t 226 CollationIterator::getDataCE32(UChar32 c) const { 227 return data->getCE32(c); 228 } 229 230 uint32_t 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 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 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 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 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 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 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 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 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 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 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 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