2 ******************************************************************************
4 * Copyright (C) 2001-2014, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 ******************************************************************************
8 * file name: utrie2.cpp
10 * tab size: 8 (not used)
13 * created on: 2008aug16 (starting from a copy of utrie.c)
14 * created by: Markus W. Scherer
16 * This is a common implementation of a Unicode trie.
17 * It is a kind of compressed, serializable table of 16- or 32-bit values associated with
18 * Unicode code points (0..0x10ffff).
19 * This is the second common version of a Unicode trie (hence the name UTrie2).
20 * See utrie2.h for a comparison.
22 * This file contains only the runtime and enumeration code, for read-only access.
23 * See utrie2_builder.c for the builder code.
29 #include "unicode/utypes.h"
30 #include "unicode/utf.h"
31 #include "unicode/utf8.h"
32 #include "unicode/utf16.h"
35 #include "utrie2_impl.h"
38 /* Public UTrie2 API implementation ----------------------------------------- */
41 get32(const UNewTrie2
*trie
, UChar32 c
, UBool fromLSCP
) {
44 if(c
>=trie
->highStart
&& (!U_IS_LEAD(c
) || fromLSCP
)) {
45 return trie
->data
[trie
->dataLength
-UTRIE2_DATA_GRANULARITY
];
48 if(U_IS_LEAD(c
) && fromLSCP
) {
49 i2
=(UTRIE2_LSCP_INDEX_2_OFFSET
-(0xd800>>UTRIE2_SHIFT_2
))+
52 i2
=trie
->index1
[c
>>UTRIE2_SHIFT_1
]+
53 ((c
>>UTRIE2_SHIFT_2
)&UTRIE2_INDEX_2_MASK
);
55 block
=trie
->index2
[i2
];
56 return trie
->data
[block
+(c
&UTRIE2_DATA_MASK
)];
59 U_CAPI
uint32_t U_EXPORT2
60 utrie2_get32(const UTrie2
*trie
, UChar32 c
) {
61 if(trie
->data16
!=NULL
) {
62 return UTRIE2_GET16(trie
, c
);
63 } else if(trie
->data32
!=NULL
) {
64 return UTRIE2_GET32(trie
, c
);
65 } else if((uint32_t)c
>0x10ffff) {
66 return trie
->errorValue
;
68 return get32(trie
->newTrie
, c
, TRUE
);
72 U_CAPI
uint32_t U_EXPORT2
73 utrie2_get32FromLeadSurrogateCodeUnit(const UTrie2
*trie
, UChar32 c
) {
75 return trie
->errorValue
;
77 if(trie
->data16
!=NULL
) {
78 return UTRIE2_GET16_FROM_U16_SINGLE_LEAD(trie
, c
);
79 } else if(trie
->data32
!=NULL
) {
80 return UTRIE2_GET32_FROM_U16_SINGLE_LEAD(trie
, c
);
82 return get32(trie
->newTrie
, c
, FALSE
);
87 u8Index(const UTrie2
*trie
, UChar32 c
, int32_t i
) {
89 _UTRIE2_INDEX_FROM_CP(
91 trie
->data32
==NULL
? trie
->indexLength
: 0,
96 U_CAPI
int32_t U_EXPORT2
97 utrie2_internalU8NextIndex(const UTrie2
*trie
, UChar32 c
,
98 const uint8_t *src
, const uint8_t *limit
) {
101 /* support 64-bit pointers by avoiding cast of arbitrary difference */
103 length
=(int32_t)(limit
-src
);
107 c
=utf8_nextCharSafeBody(src
, &i
, length
, c
, -1);
108 return u8Index(trie
, c
, i
);
111 U_CAPI
int32_t U_EXPORT2
112 utrie2_internalU8PrevIndex(const UTrie2
*trie
, UChar32 c
,
113 const uint8_t *start
, const uint8_t *src
) {
115 /* support 64-bit pointers by avoiding cast of arbitrary difference */
117 i
=length
=(int32_t)(src
-start
);
122 c
=utf8_prevCharSafeBody(start
, 0, &i
, c
, -1);
123 i
=length
-i
; /* number of bytes read backward from src */
124 return u8Index(trie
, c
, i
);
127 U_CAPI UTrie2
* U_EXPORT2
128 utrie2_openFromSerialized(UTrie2ValueBits valueBits
,
129 const void *data
, int32_t length
, int32_t *pActualLength
,
130 UErrorCode
*pErrorCode
) {
131 const UTrie2Header
*header
;
133 int32_t actualLength
;
138 if(U_FAILURE(*pErrorCode
)) {
142 if( length
<=0 || (U_POINTER_MASK_LSB(data
, 3)!=0) ||
143 valueBits
<0 || UTRIE2_COUNT_VALUE_BITS
<=valueBits
145 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
149 /* enough data for a trie header? */
150 if(length
<(int32_t)sizeof(UTrie2Header
)) {
151 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
155 /* check the signature */
156 header
=(const UTrie2Header
*)data
;
157 if(header
->signature
!=UTRIE2_SIG
) {
158 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
162 /* get the options */
163 if(valueBits
!=(UTrie2ValueBits
)(header
->options
&UTRIE2_OPTIONS_VALUE_BITS_MASK
)) {
164 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
168 /* get the length values and offsets */
169 uprv_memset(&tempTrie
, 0, sizeof(tempTrie
));
170 tempTrie
.indexLength
=header
->indexLength
;
171 tempTrie
.dataLength
=header
->shiftedDataLength
<<UTRIE2_INDEX_SHIFT
;
172 tempTrie
.index2NullOffset
=header
->index2NullOffset
;
173 tempTrie
.dataNullOffset
=header
->dataNullOffset
;
175 tempTrie
.highStart
=header
->shiftedHighStart
<<UTRIE2_SHIFT_1
;
176 tempTrie
.highValueIndex
=tempTrie
.dataLength
-UTRIE2_DATA_GRANULARITY
;
177 if(valueBits
==UTRIE2_16_VALUE_BITS
) {
178 tempTrie
.highValueIndex
+=tempTrie
.indexLength
;
181 /* calculate the actual length */
182 actualLength
=(int32_t)sizeof(UTrie2Header
)+tempTrie
.indexLength
*2;
183 if(valueBits
==UTRIE2_16_VALUE_BITS
) {
184 actualLength
+=tempTrie
.dataLength
*2;
186 actualLength
+=tempTrie
.dataLength
*4;
188 if(length
<actualLength
) {
189 *pErrorCode
=U_INVALID_FORMAT_ERROR
; /* not enough bytes */
193 /* allocate the trie */
194 trie
=(UTrie2
*)uprv_malloc(sizeof(UTrie2
));
196 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
199 uprv_memcpy(trie
, &tempTrie
, sizeof(tempTrie
));
200 trie
->memory
=(uint32_t *)data
;
201 trie
->length
=actualLength
;
202 trie
->isMemoryOwned
=FALSE
;
204 /* set the pointers to its index and data arrays */
205 p16
=(const uint16_t *)(header
+1);
207 p16
+=trie
->indexLength
;
211 case UTRIE2_16_VALUE_BITS
:
214 trie
->initialValue
=trie
->index
[trie
->dataNullOffset
];
215 trie
->errorValue
=trie
->data16
[UTRIE2_BAD_UTF8_DATA_OFFSET
];
217 case UTRIE2_32_VALUE_BITS
:
219 trie
->data32
=(const uint32_t *)p16
;
220 trie
->initialValue
=trie
->data32
[trie
->dataNullOffset
];
221 trie
->errorValue
=trie
->data32
[UTRIE2_BAD_UTF8_DATA_OFFSET
];
224 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
228 if(pActualLength
!=NULL
) {
229 *pActualLength
=actualLength
;
234 U_CAPI UTrie2
* U_EXPORT2
235 utrie2_openDummy(UTrie2ValueBits valueBits
,
236 uint32_t initialValue
, uint32_t errorValue
,
237 UErrorCode
*pErrorCode
) {
239 UTrie2Header
*header
;
242 int32_t indexLength
, dataLength
, length
, i
;
243 int32_t dataMove
; /* >0 if the data is moved to the end of the index array */
245 if(U_FAILURE(*pErrorCode
)) {
249 if(valueBits
<0 || UTRIE2_COUNT_VALUE_BITS
<=valueBits
) {
250 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
254 /* calculate the total length of the dummy trie data */
255 indexLength
=UTRIE2_INDEX_1_OFFSET
;
256 dataLength
=UTRIE2_DATA_START_OFFSET
+UTRIE2_DATA_GRANULARITY
;
257 length
=(int32_t)sizeof(UTrie2Header
)+indexLength
*2;
258 if(valueBits
==UTRIE2_16_VALUE_BITS
) {
259 length
+=dataLength
*2;
261 length
+=dataLength
*4;
264 /* allocate the trie */
265 trie
=(UTrie2
*)uprv_malloc(sizeof(UTrie2
));
267 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
270 uprv_memset(trie
, 0, sizeof(UTrie2
));
271 trie
->memory
=uprv_malloc(length
);
272 if(trie
->memory
==NULL
) {
274 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
278 trie
->isMemoryOwned
=TRUE
;
280 /* set the UTrie2 fields */
281 if(valueBits
==UTRIE2_16_VALUE_BITS
) {
282 dataMove
=indexLength
;
287 trie
->indexLength
=indexLength
;
288 trie
->dataLength
=dataLength
;
289 trie
->index2NullOffset
=UTRIE2_INDEX_2_OFFSET
;
290 trie
->dataNullOffset
=(uint16_t)dataMove
;
291 trie
->initialValue
=initialValue
;
292 trie
->errorValue
=errorValue
;
294 trie
->highValueIndex
=dataMove
+UTRIE2_DATA_START_OFFSET
;
296 /* set the header fields */
297 header
=(UTrie2Header
*)trie
->memory
;
299 header
->signature
=UTRIE2_SIG
; /* "Tri2" */
300 header
->options
=(uint16_t)valueBits
;
302 header
->indexLength
=(uint16_t)indexLength
;
303 header
->shiftedDataLength
=(uint16_t)(dataLength
>>UTRIE2_INDEX_SHIFT
);
304 header
->index2NullOffset
=(uint16_t)UTRIE2_INDEX_2_OFFSET
;
305 header
->dataNullOffset
=(uint16_t)dataMove
;
306 header
->shiftedHighStart
=0;
308 /* fill the index and data arrays */
309 dest16
=(uint16_t *)(header
+1);
312 /* write the index-2 array values shifted right by UTRIE2_INDEX_SHIFT */
313 for(i
=0; i
<UTRIE2_INDEX_2_BMP_LENGTH
; ++i
) {
314 *dest16
++=(uint16_t)(dataMove
>>UTRIE2_INDEX_SHIFT
); /* null data block */
317 /* write UTF-8 2-byte index-2 values, not right-shifted */
318 for(i
=0; i
<(0xc2-0xc0); ++i
) { /* C0..C1 */
319 *dest16
++=(uint16_t)(dataMove
+UTRIE2_BAD_UTF8_DATA_OFFSET
);
321 for(; i
<(0xe0-0xc0); ++i
) { /* C2..DF */
322 *dest16
++=(uint16_t)dataMove
;
325 /* write the 16/32-bit data array */
327 case UTRIE2_16_VALUE_BITS
:
328 /* write 16-bit data values */
331 for(i
=0; i
<0x80; ++i
) {
332 *dest16
++=(uint16_t)initialValue
;
335 *dest16
++=(uint16_t)errorValue
;
337 /* highValue and reserved values */
338 for(i
=0; i
<UTRIE2_DATA_GRANULARITY
; ++i
) {
339 *dest16
++=(uint16_t)initialValue
;
342 case UTRIE2_32_VALUE_BITS
:
343 /* write 32-bit data values */
344 p
=(uint32_t *)dest16
;
347 for(i
=0; i
<0x80; ++i
) {
353 /* highValue and reserved values */
354 for(i
=0; i
<UTRIE2_DATA_GRANULARITY
; ++i
) {
359 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
366 U_CAPI
void U_EXPORT2
367 utrie2_close(UTrie2
*trie
) {
369 if(trie
->isMemoryOwned
) {
370 uprv_free(trie
->memory
);
372 if(trie
->newTrie
!=NULL
) {
373 uprv_free(trie
->newTrie
->data
);
374 uprv_free(trie
->newTrie
);
380 U_CAPI
int32_t U_EXPORT2
381 utrie2_getVersion(const void *data
, int32_t length
, UBool anyEndianOk
) {
383 if(length
<16 || data
==NULL
|| (U_POINTER_MASK_LSB(data
, 3)!=0)) {
386 signature
=*(const uint32_t *)data
;
387 if(signature
==UTRIE2_SIG
) {
390 if(anyEndianOk
&& signature
==UTRIE2_OE_SIG
) {
393 if(signature
==UTRIE_SIG
) {
396 if(anyEndianOk
&& signature
==UTRIE_OE_SIG
) {
402 U_CAPI UBool U_EXPORT2
403 utrie2_isFrozen(const UTrie2
*trie
) {
404 return (UBool
)(trie
->newTrie
==NULL
);
407 U_CAPI
int32_t U_EXPORT2
408 utrie2_serialize(const UTrie2
*trie
,
409 void *data
, int32_t capacity
,
410 UErrorCode
*pErrorCode
) {
412 if(U_FAILURE(*pErrorCode
)) {
416 if( trie
==NULL
|| trie
->memory
==NULL
|| trie
->newTrie
!=NULL
||
417 capacity
<0 || (capacity
>0 && (data
==NULL
|| (U_POINTER_MASK_LSB(data
, 3)!=0)))
419 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
423 if(capacity
>=trie
->length
) {
424 uprv_memcpy(data
, trie
->memory
, trie
->length
);
426 *pErrorCode
=U_BUFFER_OVERFLOW_ERROR
;
431 U_CAPI
int32_t U_EXPORT2
432 utrie2_swap(const UDataSwapper
*ds
,
433 const void *inData
, int32_t length
, void *outData
,
434 UErrorCode
*pErrorCode
) {
435 const UTrie2Header
*inTrie
;
437 int32_t dataLength
, size
;
438 UTrie2ValueBits valueBits
;
440 if(U_FAILURE(*pErrorCode
)) {
443 if(ds
==NULL
|| inData
==NULL
|| (length
>=0 && outData
==NULL
)) {
444 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
448 /* setup and swapping */
449 if(length
>=0 && length
<(int32_t)sizeof(UTrie2Header
)) {
450 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
454 inTrie
=(const UTrie2Header
*)inData
;
455 trie
.signature
=ds
->readUInt32(inTrie
->signature
);
456 trie
.options
=ds
->readUInt16(inTrie
->options
);
457 trie
.indexLength
=ds
->readUInt16(inTrie
->indexLength
);
458 trie
.shiftedDataLength
=ds
->readUInt16(inTrie
->shiftedDataLength
);
460 valueBits
=(UTrie2ValueBits
)(trie
.options
&UTRIE2_OPTIONS_VALUE_BITS_MASK
);
461 dataLength
=(int32_t)trie
.shiftedDataLength
<<UTRIE2_INDEX_SHIFT
;
463 if( trie
.signature
!=UTRIE2_SIG
||
464 valueBits
<0 || UTRIE2_COUNT_VALUE_BITS
<=valueBits
||
465 trie
.indexLength
<UTRIE2_INDEX_1_OFFSET
||
466 dataLength
<UTRIE2_DATA_START_OFFSET
468 *pErrorCode
=U_INVALID_FORMAT_ERROR
; /* not a UTrie */
472 size
=sizeof(UTrie2Header
)+trie
.indexLength
*2;
474 case UTRIE2_16_VALUE_BITS
:
477 case UTRIE2_32_VALUE_BITS
:
481 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
486 UTrie2Header
*outTrie
;
489 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
493 outTrie
=(UTrie2Header
*)outData
;
495 /* swap the header */
496 ds
->swapArray32(ds
, &inTrie
->signature
, 4, &outTrie
->signature
, pErrorCode
);
497 ds
->swapArray16(ds
, &inTrie
->options
, 12, &outTrie
->options
, pErrorCode
);
499 /* swap the index and the data */
501 case UTRIE2_16_VALUE_BITS
:
502 ds
->swapArray16(ds
, inTrie
+1, (trie
.indexLength
+dataLength
)*2, outTrie
+1, pErrorCode
);
504 case UTRIE2_32_VALUE_BITS
:
505 ds
->swapArray16(ds
, inTrie
+1, trie
.indexLength
*2, outTrie
+1, pErrorCode
);
506 ds
->swapArray32(ds
, (const uint16_t *)(inTrie
+1)+trie
.indexLength
, dataLength
*4,
507 (uint16_t *)(outTrie
+1)+trie
.indexLength
, pErrorCode
);
510 *pErrorCode
=U_INVALID_FORMAT_ERROR
;
518 // utrie2_swapAnyVersion() should be defined here but lives in utrie2_builder.c
519 // to avoid a dependency from utrie2.cpp on utrie.c.
521 /* enumeration -------------------------------------------------------------- */
523 #define MIN_VALUE(a, b) ((a)<(b) ? (a) : (b))
525 /* default UTrie2EnumValue() returns the input value itself */
526 static uint32_t U_CALLCONV
527 enumSameValue(const void * /*context*/, uint32_t value
) {
532 * Enumerate all ranges of code points with the same relevant values.
533 * The values are transformed from the raw trie entries by the enumValue function.
535 * Currently requires start<limit and both start and limit must be multiples
536 * of UTRIE2_DATA_BLOCK_LENGTH.
539 * - Skip a whole block if we know that it is filled with a single value,
540 * and it is the same as we visited just before.
541 * - Handle the null block specially because we know a priori that it is filled
542 * with a single value.
545 enumEitherTrie(const UTrie2
*trie
,
546 UChar32 start
, UChar32 limit
,
547 UTrie2EnumValue
*enumValue
, UTrie2EnumRange
*enumRange
, const void *context
) {
548 const uint32_t *data32
;
551 uint32_t value
, prevValue
, initialValue
;
552 UChar32 c
, prev
, highStart
;
553 int32_t j
, i2Block
, prevI2Block
, index2NullOffset
, block
, prevBlock
, nullBlock
;
555 if(enumRange
==NULL
) {
558 if(enumValue
==NULL
) {
559 enumValue
=enumSameValue
;
562 if(trie
->newTrie
==NULL
) {
565 U_ASSERT(idx
!=NULL
); /* the following code assumes trie->newTrie is not NULL when idx is NULL */
568 index2NullOffset
=trie
->index2NullOffset
;
569 nullBlock
=trie
->dataNullOffset
;
571 /* unfrozen, mutable trie */
573 data32
=trie
->newTrie
->data
;
574 U_ASSERT(data32
!=NULL
); /* the following code assumes idx is not NULL when data32 is NULL */
576 index2NullOffset
=trie
->newTrie
->index2NullOffset
;
577 nullBlock
=trie
->newTrie
->dataNullOffset
;
580 highStart
=trie
->highStart
;
582 /* get the enumeration value that corresponds to an initial-value trie data entry */
583 initialValue
=enumValue(context
, trie
->initialValue
);
585 /* set variables for previous range */
591 /* enumerate index-2 blocks */
592 for(c
=start
; c
<limit
&& c
<highStart
;) {
593 /* Code point limit for iterating inside this i2Block. */
594 UChar32 tempLimit
=c
+UTRIE2_CP_PER_INDEX_1_ENTRY
;
595 if(limit
<tempLimit
) {
599 if(!U_IS_SURROGATE(c
)) {
600 i2Block
=c
>>UTRIE2_SHIFT_2
;
601 } else if(U_IS_SURROGATE_LEAD(c
)) {
603 * Enumerate values for lead surrogate code points, not code units:
604 * This special block has half the normal length.
606 i2Block
=UTRIE2_LSCP_INDEX_2_OFFSET
;
607 tempLimit
=MIN_VALUE(0xdc00, limit
);
610 * Switch back to the normal part of the index-2 table.
611 * Enumerate the second half of the surrogates block.
613 i2Block
=0xd800>>UTRIE2_SHIFT_2
;
614 tempLimit
=MIN_VALUE(0xe000, limit
);
617 /* supplementary code points */
619 i2Block
=idx
[(UTRIE2_INDEX_1_OFFSET
-UTRIE2_OMITTED_BMP_INDEX_1_LENGTH
)+
620 (c
>>UTRIE2_SHIFT_1
)];
622 i2Block
=trie
->newTrie
->index1
[c
>>UTRIE2_SHIFT_1
];
624 if(i2Block
==prevI2Block
&& (c
-prev
)>=UTRIE2_CP_PER_INDEX_1_ENTRY
) {
626 * The index-2 block is the same as the previous one, and filled with prevValue.
627 * Only possible for supplementary code points because the linear-BMP index-2
628 * table creates unique i2Block values.
630 c
+=UTRIE2_CP_PER_INDEX_1_ENTRY
;
635 if(i2Block
==index2NullOffset
) {
636 /* this is the null index-2 block */
637 if(prevValue
!=initialValue
) {
638 if(prev
<c
&& !enumRange(context
, prev
, c
-1, prevValue
)) {
643 prevValue
=initialValue
;
645 c
+=UTRIE2_CP_PER_INDEX_1_ENTRY
;
647 /* enumerate data blocks for one index-2 block */
649 i2
=(c
>>UTRIE2_SHIFT_2
)&UTRIE2_INDEX_2_MASK
;
650 if((c
>>UTRIE2_SHIFT_1
)==(tempLimit
>>UTRIE2_SHIFT_1
)) {
651 i2Limit
=(tempLimit
>>UTRIE2_SHIFT_2
)&UTRIE2_INDEX_2_MASK
;
653 i2Limit
=UTRIE2_INDEX_2_BLOCK_LENGTH
;
655 for(; i2
<i2Limit
; ++i2
) {
657 block
=(int32_t)idx
[i2Block
+i2
]<<UTRIE2_INDEX_SHIFT
;
659 block
=trie
->newTrie
->index2
[i2Block
+i2
];
661 if(block
==prevBlock
&& (c
-prev
)>=UTRIE2_DATA_BLOCK_LENGTH
) {
662 /* the block is the same as the previous one, and filled with prevValue */
663 c
+=UTRIE2_DATA_BLOCK_LENGTH
;
667 if(block
==nullBlock
) {
668 /* this is the null data block */
669 if(prevValue
!=initialValue
) {
670 if(prev
<c
&& !enumRange(context
, prev
, c
-1, prevValue
)) {
674 prevValue
=initialValue
;
676 c
+=UTRIE2_DATA_BLOCK_LENGTH
;
678 for(j
=0; j
<UTRIE2_DATA_BLOCK_LENGTH
; ++j
) {
679 value
=enumValue(context
, data32
!=NULL
? data32
[block
+j
] : idx
[block
+j
]);
680 if(value
!=prevValue
) {
681 if(prev
<c
&& !enumRange(context
, prev
, c
-1, prevValue
)) {
695 c
=limit
; /* could be higher if in the index2NullOffset */
697 /* c==highStart<limit */
702 data32
[trie
->highValueIndex
] :
703 idx
[trie
->highValueIndex
];
705 highValue
=trie
->newTrie
->data
[trie
->newTrie
->dataLength
-UTRIE2_DATA_GRANULARITY
];
707 value
=enumValue(context
, highValue
);
708 if(value
!=prevValue
) {
709 if(prev
<c
&& !enumRange(context
, prev
, c
-1, prevValue
)) {
718 /* deliver last range */
719 enumRange(context
, prev
, c
-1, prevValue
);
722 U_CAPI
void U_EXPORT2
723 utrie2_enum(const UTrie2
*trie
,
724 UTrie2EnumValue
*enumValue
, UTrie2EnumRange
*enumRange
, const void *context
) {
725 enumEitherTrie(trie
, 0, 0x110000, enumValue
, enumRange
, context
);
728 U_CAPI
void U_EXPORT2
729 utrie2_enumForLeadSurrogate(const UTrie2
*trie
, UChar32 lead
,
730 UTrie2EnumValue
*enumValue
, UTrie2EnumRange
*enumRange
,
731 const void *context
) {
732 if(!U16_IS_LEAD(lead
)) {
735 lead
=(lead
-0xd7c0)<<10; /* start code point */
736 enumEitherTrie(trie
, lead
, lead
+0x400, enumValue
, enumRange
, context
);
739 /* C++ convenience wrappers ------------------------------------------------- */
743 uint16_t BackwardUTrie2StringIterator::previous16() {
744 codePointLimit
=codePointStart
;
745 if(start
>=codePointStart
) {
746 codePoint
=U_SENTINEL
;
750 UTRIE2_U16_PREV16(trie
, start
, codePointStart
, codePoint
, result
);
754 uint16_t ForwardUTrie2StringIterator::next16() {
755 codePointStart
=codePointLimit
;
756 if(codePointLimit
==limit
) {
757 codePoint
=U_SENTINEL
;
761 UTRIE2_U16_NEXT16(trie
, codePointLimit
, limit
, codePoint
, result
);