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