1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
5 * Copyright (C) 2013-2015, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * collationfastlatin.cpp
10 * created on: 2013aug18
11 * created by: Markus W. Scherer
14 #include "unicode/utypes.h"
16 #if !UCONFIG_NO_COLLATION
18 #include "unicode/ucol.h"
19 #include "collationdata.h"
20 #include "collationfastlatin.h"
21 #include "collationsettings.h"
27 CollationFastLatin::getOptions(const CollationData
*data
, const CollationSettings
&settings
,
28 uint16_t *primaries
, int32_t capacity
) {
29 const uint16_t *table
= data
->fastLatinTable
;
30 if(table
== NULL
) { return -1; }
31 U_ASSERT(capacity
== LATIN_LIMIT
);
32 if(capacity
!= LATIN_LIMIT
) { return -1; }
35 if((settings
.options
& CollationSettings::ALTERNATE_MASK
) == 0) {
36 // No mini primaries are variable, set a variableTop just below the
37 // lowest long mini primary.
38 miniVarTop
= MIN_LONG
- 1;
40 int32_t headerLength
= *table
& 0xff;
41 int32_t i
= 1 + settings
.getMaxVariable();
42 if(i
>= headerLength
) {
43 return -1; // variableTop >= digits, should not occur
45 miniVarTop
= table
[i
];
48 UBool digitsAreReordered
= FALSE
;
49 if(settings
.hasReordering()) {
50 uint32_t prevStart
= 0;
51 uint32_t beforeDigitStart
= 0;
52 uint32_t digitStart
= 0;
53 uint32_t afterDigitStart
= 0;
54 for(int32_t group
= UCOL_REORDER_CODE_FIRST
;
55 group
< UCOL_REORDER_CODE_FIRST
+ CollationData::MAX_NUM_SPECIAL_REORDER_CODES
;
57 uint32_t start
= data
->getFirstPrimaryForGroup(group
);
58 start
= settings
.reorder(start
);
59 if(group
== UCOL_REORDER_CODE_DIGIT
) {
60 beforeDigitStart
= prevStart
;
62 } else if(start
!= 0) {
63 if(start
< prevStart
) {
64 // The permutation affects the groups up to Latin.
67 // In the future, there might be a special group between digits & Latin.
68 if(digitStart
!= 0 && afterDigitStart
== 0 && prevStart
== beforeDigitStart
) {
69 afterDigitStart
= start
;
74 uint32_t latinStart
= data
->getFirstPrimaryForGroup(USCRIPT_LATIN
);
75 latinStart
= settings
.reorder(latinStart
);
76 if(latinStart
< prevStart
) {
79 if(afterDigitStart
== 0) {
80 afterDigitStart
= latinStart
;
82 if(!(beforeDigitStart
< digitStart
&& digitStart
< afterDigitStart
)) {
83 digitsAreReordered
= TRUE
;
87 table
+= (table
[0] & 0xff); // skip the header
88 for(UChar32 c
= 0; c
< LATIN_LIMIT
; ++c
) {
89 uint32_t p
= table
[c
];
91 p
&= SHORT_PRIMARY_MASK
;
92 } else if(p
> miniVarTop
) {
93 p
&= LONG_PRIMARY_MASK
;
97 primaries
[c
] = (uint16_t)p
;
99 if(digitsAreReordered
|| (settings
.options
& CollationSettings::NUMERIC
) != 0) {
100 // Bail out for digits.
101 for(UChar32 c
= 0x30; c
<= 0x39; ++c
) { primaries
[c
] = 0; }
104 // Shift the miniVarTop above other options.
105 return ((int32_t)miniVarTop
<< 16) | settings
.options
;
109 CollationFastLatin::compareUTF16(const uint16_t *table
, const uint16_t *primaries
, int32_t options
,
110 const UChar
*left
, int32_t leftLength
,
111 const UChar
*right
, int32_t rightLength
) {
112 // This is a modified copy of CollationCompare::compareUpToQuaternary(),
113 // optimized for common Latin text.
114 // Keep them in sync!
115 // Keep compareUTF16() and compareUTF8() in sync very closely!
117 U_ASSERT((table
[0] >> 8) == VERSION
);
118 table
+= (table
[0] & 0xff); // skip the header
119 uint32_t variableTop
= (uint32_t)options
>> 16; // see getOptions()
120 options
&= 0xffff; // needed for CollationSettings::getStrength() to work
122 // Check for supported characters, fetch mini CEs, and compare primaries.
123 int32_t leftIndex
= 0, rightIndex
= 0;
125 * Single mini CE or a pair.
126 * The current mini CE is in the lower 16 bits, the next one is in the upper 16 bits.
127 * If there is only one, then it is in the lower bits, and the upper bits are 0.
129 uint32_t leftPair
= 0, rightPair
= 0;
131 // We fetch CEs until we get a non-ignorable primary or reach the end.
132 while(leftPair
== 0) {
133 if(leftIndex
== leftLength
) {
137 UChar32 c
= left
[leftIndex
++];
139 leftPair
= primaries
[c
];
140 if(leftPair
!= 0) { break; }
141 if(c
<= 0x39 && c
>= 0x30 && (options
& CollationSettings::NUMERIC
) != 0) {
142 return BAIL_OUT_RESULT
;
145 } else if(PUNCT_START
<= c
&& c
< PUNCT_LIMIT
) {
146 leftPair
= table
[c
- PUNCT_START
+ LATIN_LIMIT
];
148 leftPair
= lookup(table
, c
);
150 if(leftPair
>= MIN_SHORT
) {
151 leftPair
&= SHORT_PRIMARY_MASK
;
153 } else if(leftPair
> variableTop
) {
154 leftPair
&= LONG_PRIMARY_MASK
;
157 leftPair
= nextPair(table
, c
, leftPair
, left
, NULL
, leftIndex
, leftLength
);
158 if(leftPair
== BAIL_OUT
) { return BAIL_OUT_RESULT
; }
159 leftPair
= getPrimaries(variableTop
, leftPair
);
163 while(rightPair
== 0) {
164 if(rightIndex
== rightLength
) {
168 UChar32 c
= right
[rightIndex
++];
170 rightPair
= primaries
[c
];
171 if(rightPair
!= 0) { break; }
172 if(c
<= 0x39 && c
>= 0x30 && (options
& CollationSettings::NUMERIC
) != 0) {
173 return BAIL_OUT_RESULT
;
175 rightPair
= table
[c
];
176 } else if(PUNCT_START
<= c
&& c
< PUNCT_LIMIT
) {
177 rightPair
= table
[c
- PUNCT_START
+ LATIN_LIMIT
];
179 rightPair
= lookup(table
, c
);
181 if(rightPair
>= MIN_SHORT
) {
182 rightPair
&= SHORT_PRIMARY_MASK
;
184 } else if(rightPair
> variableTop
) {
185 rightPair
&= LONG_PRIMARY_MASK
;
188 rightPair
= nextPair(table
, c
, rightPair
, right
, NULL
, rightIndex
, rightLength
);
189 if(rightPair
== BAIL_OUT
) { return BAIL_OUT_RESULT
; }
190 rightPair
= getPrimaries(variableTop
, rightPair
);
194 if(leftPair
== rightPair
) {
195 if(leftPair
== EOS
) { break; }
196 leftPair
= rightPair
= 0;
199 uint32_t leftPrimary
= leftPair
& 0xffff;
200 uint32_t rightPrimary
= rightPair
& 0xffff;
201 if(leftPrimary
!= rightPrimary
) {
202 // Return the primary difference.
203 return (leftPrimary
< rightPrimary
) ? UCOL_LESS
: UCOL_GREATER
;
205 if(leftPair
== EOS
) { break; }
209 // In the following, we need to re-fetch each character because we did not buffer the CEs,
210 // but we know that the string is well-formed and
211 // only contains supported characters and mappings.
213 // We might skip the secondary level but continue with the case level
214 // which is turned on separately.
215 if(CollationSettings::getStrength(options
) >= UCOL_SECONDARY
) {
216 leftIndex
= rightIndex
= 0;
217 leftPair
= rightPair
= 0;
219 while(leftPair
== 0) {
220 if(leftIndex
== leftLength
) {
224 UChar32 c
= left
[leftIndex
++];
227 } else if(PUNCT_START
<= c
&& c
< PUNCT_LIMIT
) {
228 leftPair
= table
[c
- PUNCT_START
+ LATIN_LIMIT
];
230 leftPair
= lookup(table
, c
);
232 if(leftPair
>= MIN_SHORT
) {
233 leftPair
= getSecondariesFromOneShortCE(leftPair
);
235 } else if(leftPair
> variableTop
) {
236 leftPair
= COMMON_SEC_PLUS_OFFSET
;
239 leftPair
= nextPair(table
, c
, leftPair
, left
, NULL
, leftIndex
, leftLength
);
240 leftPair
= getSecondaries(variableTop
, leftPair
);
244 while(rightPair
== 0) {
245 if(rightIndex
== rightLength
) {
249 UChar32 c
= right
[rightIndex
++];
251 rightPair
= table
[c
];
252 } else if(PUNCT_START
<= c
&& c
< PUNCT_LIMIT
) {
253 rightPair
= table
[c
- PUNCT_START
+ LATIN_LIMIT
];
255 rightPair
= lookup(table
, c
);
257 if(rightPair
>= MIN_SHORT
) {
258 rightPair
= getSecondariesFromOneShortCE(rightPair
);
260 } else if(rightPair
> variableTop
) {
261 rightPair
= COMMON_SEC_PLUS_OFFSET
;
264 rightPair
= nextPair(table
, c
, rightPair
, right
, NULL
, rightIndex
, rightLength
);
265 rightPair
= getSecondaries(variableTop
, rightPair
);
269 if(leftPair
== rightPair
) {
270 if(leftPair
== EOS
) { break; }
271 leftPair
= rightPair
= 0;
274 uint32_t leftSecondary
= leftPair
& 0xffff;
275 uint32_t rightSecondary
= rightPair
& 0xffff;
276 if(leftSecondary
!= rightSecondary
) {
277 if((options
& CollationSettings::BACKWARD_SECONDARY
) != 0) {
278 // Full support for backwards secondary requires backwards contraction matching
279 // and moving backwards between merge separators.
280 return BAIL_OUT_RESULT
;
282 return (leftSecondary
< rightSecondary
) ? UCOL_LESS
: UCOL_GREATER
;
284 if(leftPair
== EOS
) { break; }
290 if((options
& CollationSettings::CASE_LEVEL
) != 0) {
291 UBool strengthIsPrimary
= CollationSettings::getStrength(options
) == UCOL_PRIMARY
;
292 leftIndex
= rightIndex
= 0;
293 leftPair
= rightPair
= 0;
295 while(leftPair
== 0) {
296 if(leftIndex
== leftLength
) {
300 UChar32 c
= left
[leftIndex
++];
301 leftPair
= (c
<= LATIN_MAX
) ? table
[c
] : lookup(table
, c
);
302 if(leftPair
< MIN_LONG
) {
303 leftPair
= nextPair(table
, c
, leftPair
, left
, NULL
, leftIndex
, leftLength
);
305 leftPair
= getCases(variableTop
, strengthIsPrimary
, leftPair
);
308 while(rightPair
== 0) {
309 if(rightIndex
== rightLength
) {
313 UChar32 c
= right
[rightIndex
++];
314 rightPair
= (c
<= LATIN_MAX
) ? table
[c
] : lookup(table
, c
);
315 if(rightPair
< MIN_LONG
) {
316 rightPair
= nextPair(table
, c
, rightPair
, right
, NULL
, rightIndex
, rightLength
);
318 rightPair
= getCases(variableTop
, strengthIsPrimary
, rightPair
);
321 if(leftPair
== rightPair
) {
322 if(leftPair
== EOS
) { break; }
323 leftPair
= rightPair
= 0;
326 uint32_t leftCase
= leftPair
& 0xffff;
327 uint32_t rightCase
= rightPair
& 0xffff;
328 if(leftCase
!= rightCase
) {
329 if((options
& CollationSettings::UPPER_FIRST
) == 0) {
330 return (leftCase
< rightCase
) ? UCOL_LESS
: UCOL_GREATER
;
332 return (leftCase
< rightCase
) ? UCOL_GREATER
: UCOL_LESS
;
335 if(leftPair
== EOS
) { break; }
340 if(CollationSettings::getStrength(options
) <= UCOL_SECONDARY
) { return UCOL_EQUAL
; }
342 // Remove the case bits from the tertiary weight when caseLevel is on or caseFirst is off.
343 UBool withCaseBits
= CollationSettings::isTertiaryWithCaseBits(options
);
345 leftIndex
= rightIndex
= 0;
346 leftPair
= rightPair
= 0;
348 while(leftPair
== 0) {
349 if(leftIndex
== leftLength
) {
353 UChar32 c
= left
[leftIndex
++];
354 leftPair
= (c
<= LATIN_MAX
) ? table
[c
] : lookup(table
, c
);
355 if(leftPair
< MIN_LONG
) {
356 leftPair
= nextPair(table
, c
, leftPair
, left
, NULL
, leftIndex
, leftLength
);
358 leftPair
= getTertiaries(variableTop
, withCaseBits
, leftPair
);
361 while(rightPair
== 0) {
362 if(rightIndex
== rightLength
) {
366 UChar32 c
= right
[rightIndex
++];
367 rightPair
= (c
<= LATIN_MAX
) ? table
[c
] : lookup(table
, c
);
368 if(rightPair
< MIN_LONG
) {
369 rightPair
= nextPair(table
, c
, rightPair
, right
, NULL
, rightIndex
, rightLength
);
371 rightPair
= getTertiaries(variableTop
, withCaseBits
, rightPair
);
374 if(leftPair
== rightPair
) {
375 if(leftPair
== EOS
) { break; }
376 leftPair
= rightPair
= 0;
379 uint32_t leftTertiary
= leftPair
& 0xffff;
380 uint32_t rightTertiary
= rightPair
& 0xffff;
381 if(leftTertiary
!= rightTertiary
) {
382 if(CollationSettings::sortsTertiaryUpperCaseFirst(options
)) {
383 // Pass through EOS and MERGE_WEIGHT
384 // and keep real tertiary weights larger than the MERGE_WEIGHT.
385 // Tertiary CEs (secondary ignorables) are not supported in fast Latin.
386 if(leftTertiary
> MERGE_WEIGHT
) {
387 leftTertiary
^= CASE_MASK
;
389 if(rightTertiary
> MERGE_WEIGHT
) {
390 rightTertiary
^= CASE_MASK
;
393 return (leftTertiary
< rightTertiary
) ? UCOL_LESS
: UCOL_GREATER
;
395 if(leftPair
== EOS
) { break; }
399 if(CollationSettings::getStrength(options
) <= UCOL_TERTIARY
) { return UCOL_EQUAL
; }
401 leftIndex
= rightIndex
= 0;
402 leftPair
= rightPair
= 0;
404 while(leftPair
== 0) {
405 if(leftIndex
== leftLength
) {
409 UChar32 c
= left
[leftIndex
++];
410 leftPair
= (c
<= LATIN_MAX
) ? table
[c
] : lookup(table
, c
);
411 if(leftPair
< MIN_LONG
) {
412 leftPair
= nextPair(table
, c
, leftPair
, left
, NULL
, leftIndex
, leftLength
);
414 leftPair
= getQuaternaries(variableTop
, leftPair
);
417 while(rightPair
== 0) {
418 if(rightIndex
== rightLength
) {
422 UChar32 c
= right
[rightIndex
++];
423 rightPair
= (c
<= LATIN_MAX
) ? table
[c
] : lookup(table
, c
);
424 if(rightPair
< MIN_LONG
) {
425 rightPair
= nextPair(table
, c
, rightPair
, right
, NULL
, rightIndex
, rightLength
);
427 rightPair
= getQuaternaries(variableTop
, rightPair
);
430 if(leftPair
== rightPair
) {
431 if(leftPair
== EOS
) { break; }
432 leftPair
= rightPair
= 0;
435 uint32_t leftQuaternary
= leftPair
& 0xffff;
436 uint32_t rightQuaternary
= rightPair
& 0xffff;
437 if(leftQuaternary
!= rightQuaternary
) {
438 return (leftQuaternary
< rightQuaternary
) ? UCOL_LESS
: UCOL_GREATER
;
440 if(leftPair
== EOS
) { break; }
448 CollationFastLatin::compareUTF8(const uint16_t *table
, const uint16_t *primaries
, int32_t options
,
449 const uint8_t *left
, int32_t leftLength
,
450 const uint8_t *right
, int32_t rightLength
) {
451 // Keep compareUTF16() and compareUTF8() in sync very closely!
453 U_ASSERT((table
[0] >> 8) == VERSION
);
454 table
+= (table
[0] & 0xff); // skip the header
455 uint32_t variableTop
= (uint32_t)options
>> 16; // see RuleBasedCollator::getFastLatinOptions()
456 options
&= 0xffff; // needed for CollationSettings::getStrength() to work
458 // Check for supported characters, fetch mini CEs, and compare primaries.
459 int32_t leftIndex
= 0, rightIndex
= 0;
461 * Single mini CE or a pair.
462 * The current mini CE is in the lower 16 bits, the next one is in the upper 16 bits.
463 * If there is only one, then it is in the lower bits, and the upper bits are 0.
465 uint32_t leftPair
= 0, rightPair
= 0;
466 // Note: There is no need to assemble the code point.
467 // We only need to look up the table entry for the character,
468 // and nextPair() looks for whether c==0.
470 // We fetch CEs until we get a non-ignorable primary or reach the end.
471 while(leftPair
== 0) {
472 if(leftIndex
== leftLength
) {
476 UChar32 c
= left
[leftIndex
++];
479 leftPair
= primaries
[c
];
480 if(leftPair
!= 0) { break; }
481 if(c
<= 0x39 && c
>= 0x30 && (options
& CollationSettings::NUMERIC
) != 0) {
482 return BAIL_OUT_RESULT
;
485 } else if(c
<= LATIN_MAX_UTF8_LEAD
&& 0xc2 <= c
&& leftIndex
!= leftLength
&&
486 0x80 <= (t
= left
[leftIndex
]) && t
<= 0xbf) {
488 c
= ((c
- 0xc2) << 6) + t
;
489 leftPair
= primaries
[c
];
490 if(leftPair
!= 0) { break; }
493 leftPair
= lookupUTF8(table
, c
, left
, leftIndex
, leftLength
);
495 if(leftPair
>= MIN_SHORT
) {
496 leftPair
&= SHORT_PRIMARY_MASK
;
498 } else if(leftPair
> variableTop
) {
499 leftPair
&= LONG_PRIMARY_MASK
;
502 leftPair
= nextPair(table
, c
, leftPair
, NULL
, left
, leftIndex
, leftLength
);
503 if(leftPair
== BAIL_OUT
) { return BAIL_OUT_RESULT
; }
504 leftPair
= getPrimaries(variableTop
, leftPair
);
508 while(rightPair
== 0) {
509 if(rightIndex
== rightLength
) {
513 UChar32 c
= right
[rightIndex
++];
516 rightPair
= primaries
[c
];
517 if(rightPair
!= 0) { break; }
518 if(c
<= 0x39 && c
>= 0x30 && (options
& CollationSettings::NUMERIC
) != 0) {
519 return BAIL_OUT_RESULT
;
521 rightPair
= table
[c
];
522 } else if(c
<= LATIN_MAX_UTF8_LEAD
&& 0xc2 <= c
&& rightIndex
!= rightLength
&&
523 0x80 <= (t
= right
[rightIndex
]) && t
<= 0xbf) {
525 c
= ((c
- 0xc2) << 6) + t
;
526 rightPair
= primaries
[c
];
527 if(rightPair
!= 0) { break; }
528 rightPair
= table
[c
];
530 rightPair
= lookupUTF8(table
, c
, right
, rightIndex
, rightLength
);
532 if(rightPair
>= MIN_SHORT
) {
533 rightPair
&= SHORT_PRIMARY_MASK
;
535 } else if(rightPair
> variableTop
) {
536 rightPair
&= LONG_PRIMARY_MASK
;
539 rightPair
= nextPair(table
, c
, rightPair
, NULL
, right
, rightIndex
, rightLength
);
540 if(rightPair
== BAIL_OUT
) { return BAIL_OUT_RESULT
; }
541 rightPair
= getPrimaries(variableTop
, rightPair
);
545 if(leftPair
== rightPair
) {
546 if(leftPair
== EOS
) { break; }
547 leftPair
= rightPair
= 0;
550 uint32_t leftPrimary
= leftPair
& 0xffff;
551 uint32_t rightPrimary
= rightPair
& 0xffff;
552 if(leftPrimary
!= rightPrimary
) {
553 // Return the primary difference.
554 return (leftPrimary
< rightPrimary
) ? UCOL_LESS
: UCOL_GREATER
;
556 if(leftPair
== EOS
) { break; }
560 // In the following, we need to re-fetch each character because we did not buffer the CEs,
561 // but we know that the string is well-formed and
562 // only contains supported characters and mappings.
564 // We might skip the secondary level but continue with the case level
565 // which is turned on separately.
566 if(CollationSettings::getStrength(options
) >= UCOL_SECONDARY
) {
567 leftIndex
= rightIndex
= 0;
568 leftPair
= rightPair
= 0;
570 while(leftPair
== 0) {
571 if(leftIndex
== leftLength
) {
575 UChar32 c
= left
[leftIndex
++];
578 } else if(c
<= LATIN_MAX_UTF8_LEAD
) {
579 leftPair
= table
[((c
- 0xc2) << 6) + left
[leftIndex
++]];
581 leftPair
= lookupUTF8Unsafe(table
, c
, left
, leftIndex
);
583 if(leftPair
>= MIN_SHORT
) {
584 leftPair
= getSecondariesFromOneShortCE(leftPair
);
586 } else if(leftPair
> variableTop
) {
587 leftPair
= COMMON_SEC_PLUS_OFFSET
;
590 leftPair
= nextPair(table
, c
, leftPair
, NULL
, left
, leftIndex
, leftLength
);
591 leftPair
= getSecondaries(variableTop
, leftPair
);
595 while(rightPair
== 0) {
596 if(rightIndex
== rightLength
) {
600 UChar32 c
= right
[rightIndex
++];
602 rightPair
= table
[c
];
603 } else if(c
<= LATIN_MAX_UTF8_LEAD
) {
604 rightPair
= table
[((c
- 0xc2) << 6) + right
[rightIndex
++]];
606 rightPair
= lookupUTF8Unsafe(table
, c
, right
, rightIndex
);
608 if(rightPair
>= MIN_SHORT
) {
609 rightPair
= getSecondariesFromOneShortCE(rightPair
);
611 } else if(rightPair
> variableTop
) {
612 rightPair
= COMMON_SEC_PLUS_OFFSET
;
615 rightPair
= nextPair(table
, c
, rightPair
, NULL
, right
, rightIndex
, rightLength
);
616 rightPair
= getSecondaries(variableTop
, rightPair
);
620 if(leftPair
== rightPair
) {
621 if(leftPair
== EOS
) { break; }
622 leftPair
= rightPair
= 0;
625 uint32_t leftSecondary
= leftPair
& 0xffff;
626 uint32_t rightSecondary
= rightPair
& 0xffff;
627 if(leftSecondary
!= rightSecondary
) {
628 if((options
& CollationSettings::BACKWARD_SECONDARY
) != 0) {
629 // Full support for backwards secondary requires backwards contraction matching
630 // and moving backwards between merge separators.
631 return BAIL_OUT_RESULT
;
633 return (leftSecondary
< rightSecondary
) ? UCOL_LESS
: UCOL_GREATER
;
635 if(leftPair
== EOS
) { break; }
641 if((options
& CollationSettings::CASE_LEVEL
) != 0) {
642 UBool strengthIsPrimary
= CollationSettings::getStrength(options
) == UCOL_PRIMARY
;
643 leftIndex
= rightIndex
= 0;
644 leftPair
= rightPair
= 0;
646 while(leftPair
== 0) {
647 if(leftIndex
== leftLength
) {
651 UChar32 c
= left
[leftIndex
++];
652 leftPair
= (c
<= 0x7f) ? table
[c
] : lookupUTF8Unsafe(table
, c
, left
, leftIndex
);
653 if(leftPair
< MIN_LONG
) {
654 leftPair
= nextPair(table
, c
, leftPair
, NULL
, left
, leftIndex
, leftLength
);
656 leftPair
= getCases(variableTop
, strengthIsPrimary
, leftPair
);
659 while(rightPair
== 0) {
660 if(rightIndex
== rightLength
) {
664 UChar32 c
= right
[rightIndex
++];
665 rightPair
= (c
<= 0x7f) ? table
[c
] : lookupUTF8Unsafe(table
, c
, right
, rightIndex
);
666 if(rightPair
< MIN_LONG
) {
667 rightPair
= nextPair(table
, c
, rightPair
, NULL
, right
, rightIndex
, rightLength
);
669 rightPair
= getCases(variableTop
, strengthIsPrimary
, rightPair
);
672 if(leftPair
== rightPair
) {
673 if(leftPair
== EOS
) { break; }
674 leftPair
= rightPair
= 0;
677 uint32_t leftCase
= leftPair
& 0xffff;
678 uint32_t rightCase
= rightPair
& 0xffff;
679 if(leftCase
!= rightCase
) {
680 if((options
& CollationSettings::UPPER_FIRST
) == 0) {
681 return (leftCase
< rightCase
) ? UCOL_LESS
: UCOL_GREATER
;
683 return (leftCase
< rightCase
) ? UCOL_GREATER
: UCOL_LESS
;
686 if(leftPair
== EOS
) { break; }
691 if(CollationSettings::getStrength(options
) <= UCOL_SECONDARY
) { return UCOL_EQUAL
; }
693 // Remove the case bits from the tertiary weight when caseLevel is on or caseFirst is off.
694 UBool withCaseBits
= CollationSettings::isTertiaryWithCaseBits(options
);
696 leftIndex
= rightIndex
= 0;
697 leftPair
= rightPair
= 0;
699 while(leftPair
== 0) {
700 if(leftIndex
== leftLength
) {
704 UChar32 c
= left
[leftIndex
++];
705 leftPair
= (c
<= 0x7f) ? table
[c
] : lookupUTF8Unsafe(table
, c
, left
, leftIndex
);
706 if(leftPair
< MIN_LONG
) {
707 leftPair
= nextPair(table
, c
, leftPair
, NULL
, left
, leftIndex
, leftLength
);
709 leftPair
= getTertiaries(variableTop
, withCaseBits
, leftPair
);
712 while(rightPair
== 0) {
713 if(rightIndex
== rightLength
) {
717 UChar32 c
= right
[rightIndex
++];
718 rightPair
= (c
<= 0x7f) ? table
[c
] : lookupUTF8Unsafe(table
, c
, right
, rightIndex
);
719 if(rightPair
< MIN_LONG
) {
720 rightPair
= nextPair(table
, c
, rightPair
, NULL
, right
, rightIndex
, rightLength
);
722 rightPair
= getTertiaries(variableTop
, withCaseBits
, rightPair
);
725 if(leftPair
== rightPair
) {
726 if(leftPair
== EOS
) { break; }
727 leftPair
= rightPair
= 0;
730 uint32_t leftTertiary
= leftPair
& 0xffff;
731 uint32_t rightTertiary
= rightPair
& 0xffff;
732 if(leftTertiary
!= rightTertiary
) {
733 if(CollationSettings::sortsTertiaryUpperCaseFirst(options
)) {
734 // Pass through EOS and MERGE_WEIGHT
735 // and keep real tertiary weights larger than the MERGE_WEIGHT.
736 // Tertiary CEs (secondary ignorables) are not supported in fast Latin.
737 if(leftTertiary
> MERGE_WEIGHT
) {
738 leftTertiary
^= CASE_MASK
;
740 if(rightTertiary
> MERGE_WEIGHT
) {
741 rightTertiary
^= CASE_MASK
;
744 return (leftTertiary
< rightTertiary
) ? UCOL_LESS
: UCOL_GREATER
;
746 if(leftPair
== EOS
) { break; }
750 if(CollationSettings::getStrength(options
) <= UCOL_TERTIARY
) { return UCOL_EQUAL
; }
752 leftIndex
= rightIndex
= 0;
753 leftPair
= rightPair
= 0;
755 while(leftPair
== 0) {
756 if(leftIndex
== leftLength
) {
760 UChar32 c
= left
[leftIndex
++];
761 leftPair
= (c
<= 0x7f) ? table
[c
] : lookupUTF8Unsafe(table
, c
, left
, leftIndex
);
762 if(leftPair
< MIN_LONG
) {
763 leftPair
= nextPair(table
, c
, leftPair
, NULL
, left
, leftIndex
, leftLength
);
765 leftPair
= getQuaternaries(variableTop
, leftPair
);
768 while(rightPair
== 0) {
769 if(rightIndex
== rightLength
) {
773 UChar32 c
= right
[rightIndex
++];
774 rightPair
= (c
<= 0x7f) ? table
[c
] : lookupUTF8Unsafe(table
, c
, right
, rightIndex
);
775 if(rightPair
< MIN_LONG
) {
776 rightPair
= nextPair(table
, c
, rightPair
, NULL
, right
, rightIndex
, rightLength
);
778 rightPair
= getQuaternaries(variableTop
, rightPair
);
781 if(leftPair
== rightPair
) {
782 if(leftPair
== EOS
) { break; }
783 leftPair
= rightPair
= 0;
786 uint32_t leftQuaternary
= leftPair
& 0xffff;
787 uint32_t rightQuaternary
= rightPair
& 0xffff;
788 if(leftQuaternary
!= rightQuaternary
) {
789 return (leftQuaternary
< rightQuaternary
) ? UCOL_LESS
: UCOL_GREATER
;
791 if(leftPair
== EOS
) { break; }
799 CollationFastLatin::lookup(const uint16_t *table
, UChar32 c
) {
800 U_ASSERT(c
> LATIN_MAX
);
801 if(PUNCT_START
<= c
&& c
< PUNCT_LIMIT
) {
802 return table
[c
- PUNCT_START
+ LATIN_LIMIT
];
803 } else if(c
== 0xfffe) {
805 } else if(c
== 0xffff) {
806 return MAX_SHORT
| COMMON_SEC
| LOWER_CASE
| COMMON_TER
;
813 CollationFastLatin::lookupUTF8(const uint16_t *table
, UChar32 c
,
814 const uint8_t *s8
, int32_t &sIndex
, int32_t sLength
) {
815 // The caller handled ASCII and valid/supported Latin.
817 int32_t i2
= sIndex
+ 1;
818 if(i2
< sLength
|| sLength
< 0) {
819 uint8_t t1
= s8
[sIndex
];
822 if(c
== 0xe2 && t1
== 0x80 && 0x80 <= t2
&& t2
<= 0xbf) {
823 return table
[(LATIN_LIMIT
- 0x80) + t2
]; // 2000..203F -> 0180..01BF
824 } else if(c
== 0xef && t1
== 0xbf) {
826 return MERGE_WEIGHT
; // U+FFFE
827 } else if(t2
== 0xbf) {
828 return MAX_SHORT
| COMMON_SEC
| LOWER_CASE
| COMMON_TER
; // U+FFFF
836 CollationFastLatin::lookupUTF8Unsafe(const uint16_t *table
, UChar32 c
,
837 const uint8_t *s8
, int32_t &sIndex
) {
838 // The caller handled ASCII.
839 // The string is well-formed and contains only supported characters.
841 if(c
<= LATIN_MAX_UTF8_LEAD
) {
842 return table
[((c
- 0xc2) << 6) + s8
[sIndex
++]]; // 0080..017F
844 uint8_t t2
= s8
[sIndex
+ 1];
847 return table
[(LATIN_LIMIT
- 0x80) + t2
]; // 2000..203F -> 0180..01BF
848 } else if(t2
== 0xbe) {
849 return MERGE_WEIGHT
; // U+FFFE
851 return MAX_SHORT
| COMMON_SEC
| LOWER_CASE
| COMMON_TER
; // U+FFFF
856 CollationFastLatin::nextPair(const uint16_t *table
, UChar32 c
, uint32_t ce
,
857 const UChar
*s16
, const uint8_t *s8
, int32_t &sIndex
, int32_t &sLength
) {
858 if(ce
>= MIN_LONG
|| ce
< CONTRACTION
) {
859 return ce
; // simple or special mini CE
860 } else if(ce
>= EXPANSION
) {
861 int32_t index
= NUM_FAST_CHARS
+ (ce
& INDEX_MASK
);
862 return ((uint32_t)table
[index
+ 1] << 16) | table
[index
];
863 } else /* ce >= CONTRACTION */ {
864 if(c
== 0 && sLength
< 0) {
865 sLength
= sIndex
- 1;
868 // Contraction list: Default mapping followed by
869 // 0 or more single-character contraction suffix mappings.
870 int32_t index
= NUM_FAST_CHARS
+ (ce
& INDEX_MASK
);
871 if(sIndex
!= sLength
) {
872 // Read the next character.
874 int32_t nextIndex
= sIndex
;
876 c2
= s16
[nextIndex
++];
878 if(PUNCT_START
<= c2
&& c2
< PUNCT_LIMIT
) {
879 c2
= c2
- PUNCT_START
+ LATIN_LIMIT
; // 2000..203F -> 0180..01BF
880 } else if(c2
== 0xfffe || c2
== 0xffff) {
881 c2
= -1; // U+FFFE & U+FFFF cannot occur in contractions.
887 c2
= s8
[nextIndex
++];
890 if(c2
<= 0xc5 && 0xc2 <= c2
&& nextIndex
!= sLength
&&
891 0x80 <= (t
= s8
[nextIndex
]) && t
<= 0xbf) {
892 c2
= ((c2
- 0xc2) << 6) + t
; // 0080..017F
895 int32_t i2
= nextIndex
+ 1;
896 if(i2
< sLength
|| sLength
< 0) {
897 if(c2
== 0xe2 && s8
[nextIndex
] == 0x80 &&
898 0x80 <= (t
= s8
[i2
]) && t
<= 0xbf) {
899 c2
= (LATIN_LIMIT
- 0x80) + t
; // 2000..203F -> 0180..01BF
900 } else if(c2
== 0xef && s8
[nextIndex
] == 0xbf &&
901 ((t
= s8
[i2
]) == 0xbe || t
== 0xbf)) {
902 c2
= -1; // U+FFFE & U+FFFF cannot occur in contractions.
913 if(c2
== 0 && sLength
< 0) {
917 // Look for the next character in the contraction suffix list,
918 // which is in ascending order of single suffix characters.
920 int32_t head
= table
[i
]; // first skip the default mapping
923 i
+= head
>> CONTR_LENGTH_SHIFT
;
925 x
= head
& CONTR_CHAR_MASK
;
932 // Return the CE or CEs for the default or contraction mapping.
933 int32_t length
= table
[index
] >> CONTR_LENGTH_SHIFT
;
937 ce
= table
[index
+ 1];
941 return ((uint32_t)table
[index
+ 2] << 16) | ce
;
947 CollationFastLatin::getSecondaries(uint32_t variableTop
, uint32_t pair
) {
950 if(pair
>= MIN_SHORT
) {
951 pair
= getSecondariesFromOneShortCE(pair
);
952 } else if(pair
> variableTop
) {
953 pair
= COMMON_SEC_PLUS_OFFSET
;
954 } else if(pair
>= MIN_LONG
) {
955 pair
= 0; // variable
957 // else special mini CE
959 uint32_t ce
= pair
& 0xffff;
960 if(ce
>= MIN_SHORT
) {
961 pair
= (pair
& TWO_SECONDARIES_MASK
) + TWO_SEC_OFFSETS
;
962 } else if(ce
> variableTop
) {
963 pair
= TWO_COMMON_SEC_PLUS_OFFSET
;
965 U_ASSERT(ce
>= MIN_LONG
);
966 pair
= 0; // variable
973 CollationFastLatin::getCases(uint32_t variableTop
, UBool strengthIsPrimary
, uint32_t pair
) {
974 // Primary+caseLevel: Ignore case level weights of primary ignorables.
975 // Otherwise: Ignore case level weights of secondary ignorables.
976 // For details see the comments in the CollationCompare class.
977 // Tertiary CEs (secondary ignorables) are not supported in fast Latin.
980 if(pair
>= MIN_SHORT
) {
981 // A high secondary weight means we really have two CEs,
982 // a primary CE and a secondary CE.
984 pair
&= CASE_MASK
; // explicit weight of primary CE
985 if(!strengthIsPrimary
&& (ce
& SECONDARY_MASK
) >= MIN_SEC_HIGH
) {
986 pair
|= LOWER_CASE
<< 16; // implied weight of secondary CE
988 } else if(pair
> variableTop
) {
990 } else if(pair
>= MIN_LONG
) {
991 pair
= 0; // variable
993 // else special mini CE
995 // two mini CEs, same primary groups, neither expands like above
996 uint32_t ce
= pair
& 0xffff;
997 if(ce
>= MIN_SHORT
) {
998 if(strengthIsPrimary
&& (pair
& (SHORT_PRIMARY_MASK
<< 16)) == 0) {
1001 pair
&= TWO_CASES_MASK
;
1003 } else if(ce
> variableTop
) {
1004 pair
= TWO_LOWER_CASES
;
1006 U_ASSERT(ce
>= MIN_LONG
);
1007 pair
= 0; // variable
1014 CollationFastLatin::getTertiaries(uint32_t variableTop
, UBool withCaseBits
, uint32_t pair
) {
1015 if(pair
<= 0xffff) {
1017 if(pair
>= MIN_SHORT
) {
1018 // A high secondary weight means we really have two CEs,
1019 // a primary CE and a secondary CE.
1022 pair
= (pair
& CASE_AND_TERTIARY_MASK
) + TER_OFFSET
;
1023 if((ce
& SECONDARY_MASK
) >= MIN_SEC_HIGH
) {
1024 pair
|= (LOWER_CASE
| COMMON_TER_PLUS_OFFSET
) << 16;
1027 pair
= (pair
& TERTIARY_MASK
) + TER_OFFSET
;
1028 if((ce
& SECONDARY_MASK
) >= MIN_SEC_HIGH
) {
1029 pair
|= COMMON_TER_PLUS_OFFSET
<< 16;
1032 } else if(pair
> variableTop
) {
1033 pair
= (pair
& TERTIARY_MASK
) + TER_OFFSET
;
1037 } else if(pair
>= MIN_LONG
) {
1038 pair
= 0; // variable
1040 // else special mini CE
1042 // two mini CEs, same primary groups, neither expands like above
1043 uint32_t ce
= pair
& 0xffff;
1044 if(ce
>= MIN_SHORT
) {
1046 pair
&= TWO_CASES_MASK
| TWO_TERTIARIES_MASK
;
1048 pair
&= TWO_TERTIARIES_MASK
;
1050 pair
+= TWO_TER_OFFSETS
;
1051 } else if(ce
> variableTop
) {
1052 pair
= (pair
& TWO_TERTIARIES_MASK
) + TWO_TER_OFFSETS
;
1054 pair
|= TWO_LOWER_CASES
;
1057 U_ASSERT(ce
>= MIN_LONG
);
1058 pair
= 0; // variable
1065 CollationFastLatin::getQuaternaries(uint32_t variableTop
, uint32_t pair
) {
1066 // Return the primary weight of a variable CE,
1067 // or the maximum primary weight for a non-variable, not-completely-ignorable CE.
1068 if(pair
<= 0xffff) {
1070 if(pair
>= MIN_SHORT
) {
1071 // A high secondary weight means we really have two CEs,
1072 // a primary CE and a secondary CE.
1073 if((pair
& SECONDARY_MASK
) >= MIN_SEC_HIGH
) {
1074 pair
= TWO_SHORT_PRIMARIES_MASK
;
1076 pair
= SHORT_PRIMARY_MASK
;
1078 } else if(pair
> variableTop
) {
1079 pair
= SHORT_PRIMARY_MASK
;
1080 } else if(pair
>= MIN_LONG
) {
1081 pair
&= LONG_PRIMARY_MASK
; // variable
1083 // else special mini CE
1085 // two mini CEs, same primary groups, neither expands like above
1086 uint32_t ce
= pair
& 0xffff;
1087 if(ce
> variableTop
) {
1088 pair
= TWO_SHORT_PRIMARIES_MASK
;
1090 U_ASSERT(ce
>= MIN_LONG
);
1091 pair
&= TWO_LONG_PRIMARIES_MASK
; // variable
1099 #endif // !UCONFIG_NO_COLLATION