1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
5 * Copyright (C) 2010-2014, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * collationiterator.cpp
10 * created on: 2010oct27
11 * created by: Markus W. Scherer
14 #include "utypeinfo.h" // for 'typeid' to work
16 #include "unicode/utypes.h"
18 #if !UCONFIG_NO_COLLATION
20 #include "unicode/ucharstrie.h"
21 #include "unicode/ustringtrie.h"
24 #include "collation.h"
25 #include "collationdata.h"
26 #include "collationfcd.h"
27 #include "collationiterator.h"
28 #include "normalizer2impl.h"
34 CollationIterator::CEBuffer::~CEBuffer() {}
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
; }
47 } while(capacity
< (length
+ appCap
));
48 int64_t *p
= buffer
.resize(capacity
, length
);
50 errorCode
= U_MEMORY_ALLOCATION_ERROR
;
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
{
60 // Born active but empty.
61 SkippedState() : pos(0), skipLengthAtMatch(0) {}
65 // The newBuffer is reset by setFirstSkipped().
68 UBool
isEmpty() const { return oldBuffer
.isEmpty(); }
70 UBool
hasNext() const { return pos
< oldBuffer
.length(); }
72 // Requires hasNext().
74 UChar32 c
= oldBuffer
.char32At(pos
);
79 // Accounts for one more input code point read beyond the end of the marks buffer.
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
;
93 // Not back far enough to re-enter the oldBuffer.
97 // Back out all beyond-oldBuffer code points and re-enter the buffer.
98 pos
= oldBuffer
.moveIndex32(length
, beyond
- n
);
102 // Go backwards from inside the oldBuffer.
103 pos
= oldBuffer
.moveIndex32(pos
, -n
);
108 void setFirstSkipped(UChar32 c
) {
109 skipLengthAtMatch
= 0;
113 void skip(UChar32 c
) {
117 void recordMatch() { skipLengthAtMatch
= newBuffer
.length(); }
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
);
126 void saveTrieState(const UCharsTrie
&trie
) { trie
.saveState(state
); }
127 void resetToTrieState(UCharsTrie
&trie
) const { trie
.resetToState(state
); }
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()).
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
;
147 CollationIterator::CollationIterator(const CollationIterator
&other
)
151 cesIndex(other
.cesIndex
),
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
));
161 ceBuffer
.length
= length
;
167 CollationIterator::~CollationIterator() {
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
)) {
185 for(int32_t i
= 0; i
< ceBuffer
.length
; ++i
) {
186 if(ceBuffer
.get(i
) != other
.ceBuffer
.get(i
)) { return FALSE
; }
192 CollationIterator::reset() {
193 cesIndex
= ceBuffer
.length
= 0;
194 if(skipped
!= NULL
) { skipped
->clear(); }
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
;
203 return ceBuffer
.length
;
207 CollationIterator::handleNextCE32(UChar32
&c
, UErrorCode
&errorCode
) {
208 c
= nextCodePoint(errorCode
);
209 return (c
< 0) ? Collation::FALLBACK_CE32
: data
->getCE32(c
);
213 CollationIterator::handleGetTrailSurrogate() {
218 CollationIterator::foundNULTerminator() {
223 CollationIterator::forbidSurrogateCodePoints() const {
228 CollationIterator::getDataCE32(UChar32 c
) const {
229 return data
->getCE32(c
);
233 CollationIterator::getCE32FromBuilderData(uint32_t /*ce32*/, UErrorCode
&errorCode
) {
234 if(U_SUCCESS(errorCode
)) { errorCode
= U_INTERNAL_PROGRAM_ERROR
; }
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
++);
246 return Collation::NO_CE_PRIMARY
;
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
; }
259 case Collation::LONG_PRIMARY_TAG
:
260 ceBuffer
.append(Collation::ceFromLongPrimaryCE32(ce32
), errorCode
);
262 case Collation::LONG_SECONDARY_TAG
:
263 ceBuffer
.append(Collation::ceFromLongSecondaryCE32(ce32
), errorCode
);
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;
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
)) {
277 ceBuffer
.appendUnsafe(Collation::ceFromCE32(*ce32s
++));
278 } while(--length
> 0);
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
)) {
287 ceBuffer
.appendUnsafe(*ces
++);
288 } while(--length
> 0);
292 case Collation::BUILDER_DATA_TAG
:
293 ce32
= getCE32FromBuilderData(ce32
, errorCode
);
294 if(U_FAILURE(errorCode
)) { return; }
295 if(ce32
== Collation::FALLBACK_CE32
) {
297 ce32
= d
->getCE32(c
);
300 case Collation::PREFIX_TAG
:
301 if(forward
) { backwardNumCodePoints(1, errorCode
); }
302 ce32
= getCE32FromPrefix(d
, ce32
, errorCode
);
303 if(forward
) { forwardNumCodePoints(1, errorCode
); }
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.
309 // Backward contractions are handled by previousCEUnsafe().
310 // c has contractions but they were not found.
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
);
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
);
332 nextCp
= nextSkippedCodePoint(errorCode
);
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
);
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.
354 case Collation::DIGIT_TAG
:
356 appendNumericCEs(ce32
, forward
, errorCode
);
359 // Fetch the non-numeric-collation CE32 and continue.
360 ce32
= d
->ce32s
[Collation::indexFromCE32(ce32
)];
363 case Collation::U0000_TAG
:
365 if(forward
&& foundNULTerminator()) {
366 // Handle NUL-termination. (Not needed in Java.)
367 ceBuffer
.append(Collation::NO_CE
, errorCode
);
370 // Fetch the normal ce32 for U+0000 and continue.
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;
389 ceBuffer
.appendUnsafe(Collation::ceFromCE32(jamoCE32s
[39 + t
]));
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:
403 ce32
= jamoCE32s
[39 + t
];
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
));
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
421 ce32
= d
->getCE32FromSupplementary(c
);
424 // c is an unpaired surrogate.
425 ce32
= Collation::UNASSIGNED_CE32
;
429 case Collation::OFFSET_TAG
:
431 ceBuffer
.append(d
->getCEFromOffsetCE32(c
, ce32
), errorCode
);
433 case Collation::IMPLICIT_TAG
:
435 if(U_IS_SURROGATE(c
) && forbidSurrogateCodePoints()) {
436 ce32
= Collation::FFFD_CE32
;
439 ceBuffer
.append(Collation::unassignedCEFromCodePoint(c
), errorCode
);
444 ceBuffer
.append(Collation::ceFromSimpleCE32(ce32
), errorCode
);
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.
453 // Number of code points read before the original code point.
454 int32_t lookBehind
= 0;
455 UCharsTrie
prefixes(p
);
457 UChar32 c
= previousCodePoint(errorCode
);
460 UStringTrieResult match
= prefixes
.nextForCodePoint(c
);
461 if(USTRINGTRIE_HAS_VALUE(match
)) {
462 ce32
= (uint32_t)prefixes
.getValue();
464 if(!USTRINGTRIE_HAS_NEXT(match
)) { break; }
466 forwardNumCodePoints(lookBehind
, errorCode
);
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
; }
481 CollationIterator::backwardNumSkipped(int32_t n
, UErrorCode
&errorCode
) {
482 if(skipped
!= NULL
&& !skipped
->isEmpty()) {
483 n
= skipped
->backwardNumCodePoints(n
);
485 backwardNumCodePoints(n
, errorCode
);
486 if(numCpFwd
>= 0) { numCpFwd
+= n
; }
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
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
);
508 if(USTRINGTRIE_HAS_VALUE(match
)) {
509 ce32
= (uint32_t)suffixes
.getValue();
510 if(!USTRINGTRIE_HAS_NEXT(match
) || (c
= nextSkippedCodePoint(errorCode
)) < 0) {
513 if(skipped
!= NULL
&& !skipped
->isEmpty()) { skipped
->saveTrieState(suffixes
); }
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).
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;
535 if(d
->getFCD16(c
) > 0xff) {
536 return nextCE32FromDiscontiguousContraction(
537 d
, suffixes
, ce32
, lookAhead
, c
, errorCode
);
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.
550 match
= suffixes
.nextForCodePoint(c
);
552 backwardNumSkipped(sinceMatch
, errorCode
);
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; }
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.
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.
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
);
585 backwardNumSkipped(1, errorCode
);
589 uint8_t prevCC
= (uint8_t)fcd16
;
590 fcd16
= d
->getFCD16(nextCp
);
592 // The next code point after c is a starter (S2.1.1 "process each non-starter").
593 backwardNumSkipped(2, errorCode
);
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
;
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
));
616 // Skip c (which did not match) and nextCp (which we will try now).
617 forwardNumCodePoints(2, errorCode
);
619 skipped
->saveTrieState(suffixes
);
621 // Reset to the trie state before the failed match of c.
622 skipped
->resetToTrieState(suffixes
);
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;
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();
637 skipped
->recordMatch();
638 if(!USTRINGTRIE_HAS_NEXT(match
)) { break; }
639 skipped
->saveTrieState(suffixes
);
641 // No match for "S + C", skip C.
643 skipped
->resetToTrieState(suffixes
);
644 prevCC
= (uint8_t)fcd16
;
646 if((c
= nextSkippedCodePoint(errorCode
)) < 0) { break; }
648 fcd16
= d
->getFCD16(c
);
650 // The next code point after c is a starter (S2.1.1 "process each non-starter").
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.
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; }
669 ce32
= getDataCE32(c
);
670 if(ce32
== Collation::FALLBACK_CE32
) {
672 ce32
= d
->getCE32(c
);
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.
681 ce32
= Collation::NO_CE32
; // Signal to the caller that the result is in the ceBuffer.
687 CollationIterator::appendNumericCEs(uint32_t ce32
, UBool forward
, UErrorCode
&errorCode
) {
692 char digit
= Collation::digitFromCE32(ce32
);
693 digits
.append(digit
, errorCode
);
694 if(numCpFwd
== 0) { break; }
695 UChar32 c
= nextCodePoint(errorCode
);
697 ce32
= data
->getCE32(c
);
698 if(ce32
== Collation::FALLBACK_CE32
) {
699 ce32
= data
->base
->getCE32(c
);
701 if(!Collation::hasCE32Tag(ce32
, Collation::DIGIT_TAG
)) {
702 backwardNumCodePoints(1, errorCode
);
705 if(numCpFwd
> 0) { --numCpFwd
; }
709 char digit
= Collation::digitFromCE32(ce32
);
710 digits
.append(digit
, errorCode
);
711 UChar32 c
= previousCodePoint(errorCode
);
713 ce32
= data
->getCE32(c
);
714 if(ce32
== Collation::FALLBACK_CE32
) {
715 ce32
= data
->base
->getCE32(c
);
717 if(!Collation::hasCE32Tag(ce32
, Collation::DIGIT_TAG
)) {
718 forwardNumCodePoints(1, errorCode
);
722 // Reverse the digit string.
723 char *p
= digits
.data();
724 char *q
= p
+ digits
.length() - 1;
731 if(U_FAILURE(errorCode
)) { return; }
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());
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.
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
];
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
);
770 firstByte
+= numBytes
;
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
);
779 value
-= numBytes
* 254;
780 firstByte
+= numBytes
;
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);
786 primary
|= (2 + value
% 254) << 8;
788 primary
|= (firstByte
+ value
% 254) << 16;
789 ceBuffer
.append(Collation::makeCE(primary
), errorCode
);
792 // original value > 1042489
794 U_ASSERT(length
>= 7);
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.
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) {
808 // Read the first pair.
812 // Only "half a pair" if we have an odd number of digits.
816 pair
= digits
[0] * 10 + digits
[1];
819 pair
= 11 + 2 * pair
;
820 // Add the pairs of digits between pos and length.
822 while(pos
< length
) {
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.
827 ceBuffer
.append(Collation::makeCE(primary
), errorCode
);
828 primary
= numericPrimary
;
831 primary
|= pair
<< shift
;
834 pair
= 11 + 2 * (digits
[pos
] * 10 + digits
[pos
+ 1]);
837 primary
|= (pair
- 1) << shift
;
838 ceBuffer
.append(Collation::makeCE(primary
), errorCode
);
842 CollationIterator::previousCE(UVector32
&offsets
, UErrorCode
&errorCode
) {
843 if(ceBuffer
.length
> 0) {
844 // Return the previous buffered CE.
845 return ceBuffer
.get(--ceBuffer
.length
);
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
);
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
) {
860 ce32
= d
->getCE32(c
);
864 if(Collation::isSimpleOrLongCE32(ce32
)) {
865 return Collation::ceFromCE32(ce32
);
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
);
877 return ceBuffer
.get(--ceBuffer
.length
);
879 return Collation::NO_CE_PRIMARY
;
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
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) {
903 if(!data
->isUnsafeBackward(c
, isNumeric
)) {
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.
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.
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
);
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.
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
);
949 return Collation::NO_CE_PRIMARY
;
955 #endif // !UCONFIG_NO_COLLATION