File: | out/../deps/icu-small/source/i18n/collationiterator.cpp |
Warning: | line 413, column 21 The result of the left shift is undefined because the left operand is negative |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | // © 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_COLLATION0 | |||
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_BEGINnamespace icu_71 { | |||
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 TRUE1; } | |||
40 | if(U_FAILURE(errorCode)) { return FALSE0; } | |||
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__null) { | |||
50 | errorCode = U_MEMORY_ALLOCATION_ERROR; | |||
51 | return FALSE0; | |||
52 | } | |||
53 | return TRUE1; | |||
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)((uint32_t)(c)<=0xffff ? 1 : 2); | |||
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())(void)0; | |||
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__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 | bool | |||
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__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 FALSE0; | |||
220 | } | |||
221 | ||||
222 | UBool | |||
223 | CollationIterator::forbidSurrogateCodePoints() const { | |||
224 | return FALSE0; | |||
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, TRUE1, 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__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)(void)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(-1), jamoCE32s[c], forward, errorCode); | |||
397 | appendCEsFromCE32(d, U_SENTINEL(-1), 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(-1); | |||
405 | break; | |||
406 | } | |||
407 | } | |||
408 | case Collation::LEAD_SURROGATE_TAG: { | |||
409 | U_ASSERT(forward)(void)0; // Backward iteration should never see lead surrogate code _unit_ data. | |||
410 | U_ASSERT(U16_IS_LEAD(c))(void)0; | |||
411 | UChar trail; | |||
412 | if(U16_IS_TRAIL(trail = handleGetTrailSurrogate())(((trail = handleGetTrailSurrogate())&0xfffffc00)==0xdc00 )) { | |||
413 | c = U16_GET_SUPPLEMENTARY(c, trail)(((UChar32)(c)<<10UL)+(UChar32)(trail)-((0xd800<< 10UL)+0xdc00-0x10000)); | |||
| ||||
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)(void)0; | |||
431 | ceBuffer.append(d->getCEFromOffsetCE32(c, ce32), errorCode); | |||
432 | return; | |||
433 | case Collation::IMPLICIT_TAG: | |||
434 | U_ASSERT(c >= 0)(void)0; | |||
435 | if(U_IS_SURROGATE(c)(((c)&0xfffff800)==0xd800) && 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)((match)>=USTRINGTRIE_FINAL_VALUE)) { | |||
462 | ce32 = (uint32_t)prefixes.getValue(); | |||
463 | } | |||
464 | if(!USTRINGTRIE_HAS_NEXT(match)((match)&1)) { break; } | |||
465 | } | |||
466 | forwardNumCodePoints(lookBehind, errorCode); | |||
467 | return ce32; | |||
468 | } | |||
469 | ||||
470 | UChar32 | |||
471 | CollationIterator::nextSkippedCodePoint(UErrorCode &errorCode) { | |||
472 | if(skipped != NULL__null && skipped->hasNext()) { return skipped->next(); } | |||
473 | if(numCpFwd == 0) { return U_SENTINEL(-1); } | |||
474 | UChar32 c = nextCodePoint(errorCode); | |||
475 | if(skipped != NULL__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__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__null && !skipped->isEmpty()) { skipped->saveTrieState(suffixes); } | |||
505 | UStringTrieResult match = suffixes.firstForCodePoint(c); | |||
506 | for(;;) { | |||
507 | UChar32 nextCp; | |||
508 | if(USTRINGTRIE_HAS_VALUE(match)((match)>=USTRINGTRIE_FINAL_VALUE)) { | |||
509 | ce32 = (uint32_t)suffixes.getValue(); | |||
510 | if(!USTRINGTRIE_HAS_NEXT(match)((match)&1) || (c = nextSkippedCodePoint(errorCode)) < 0) { | |||
511 | return ce32; | |||
512 | } | |||
513 | if(skipped != NULL__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)(void)0; // 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__null || skipped->isEmpty()) { | |||
601 | if(skipped == NULL__null) { | |||
602 | skipped = new SkippedState(); | |||
603 | if(skipped == NULL__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))((match = suffixes.nextForCodePoint(c))>=USTRINGTRIE_FINAL_VALUE )) { | |||
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)((match)&1)) { 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(-1); | |||
663 | for(;;) { | |||
664 | appendCEsFromCE32(d, c, ce32, TRUE1, 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)(void)0; | |||
747 | U_ASSERT(length == 1 || digits[0] != 0)(void)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)(void)0; | |||
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, FALSE0, 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)(void)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)(void)0; | |||
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)(void)0; | |||
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)(void)0; | |||
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 |