1 // 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /* 4 ****************************************************************************** 5 * 6 * Copyright (C) 2001-2014, International Business Machines 7 * Corporation and others. All Rights Reserved. 8 * 9 ****************************************************************************** 10 * file name: utrie2.cpp 11 * encoding: UTF-8 12 * tab size: 8 (not used) 13 * indentation:4 14 * 15 * created on: 2008aug16 (starting from a copy of utrie.c) 16 * created by: Markus W. Scherer 17 * 18 * This is a common implementation of a Unicode trie. 19 * It is a kind of compressed, serializable table of 16- or 32-bit values associated with 20 * Unicode code points (0..0x10ffff). 21 * This is the second common version of a Unicode trie (hence the name UTrie2). 22 * See utrie2.h for a comparison. 23 * 24 * This file contains only the runtime and enumeration code, for read-only access. 25 * See utrie2_builder.c for the builder code. 26 */ 27 #include "unicode/utypes.h" 28 #ifdef UCPTRIE_DEBUG 29 #include "unicode/umutablecptrie.h" 30 #endif 31 #include "unicode/utf.h" 32 #include "unicode/utf8.h" 33 #include "unicode/utf16.h" 34 #include "cmemory.h" 35 #include "utrie2.h" 36 #include "utrie2_impl.h" 37 #include "uassert.h" 38 39 /* Public UTrie2 API implementation ----------------------------------------- */ 40 41 static uint32_t 42 get32(const UNewTrie2 *trie, UChar32 c, UBool fromLSCP) { 43 int32_t i2, block; 44 45 if(c>=trie->highStart && (!U_IS_LEAD(c) || fromLSCP)) { 46 return trie->data[trie->dataLength-UTRIE2_DATA_GRANULARITY]; 47 } 48 49 if(U_IS_LEAD(c) && fromLSCP) { 50 i2=(UTRIE2_LSCP_INDEX_2_OFFSET-(0xd800>>UTRIE2_SHIFT_2))+ 51 (c>>UTRIE2_SHIFT_2); 52 } else { 53 i2=trie->index1[c>>UTRIE2_SHIFT_1]+ 54 ((c>>UTRIE2_SHIFT_2)&UTRIE2_INDEX_2_MASK); 55 } 56 block=trie->index2[i2]; 57 return trie->data[block+(c&UTRIE2_DATA_MASK)]; 58 } 59 60 U_CAPI uint32_t U_EXPORT2 61 utrie2_get32(const UTrie2 *trie, UChar32 c) { 62 if(trie->data16!=NULL) { 63 return UTRIE2_GET16(trie, c); 64 } else if(trie->data32!=NULL) { 65 return UTRIE2_GET32(trie, c); 66 } else if((uint32_t)c>0x10ffff) { 67 return trie->errorValue; 68 } else { 69 return get32(trie->newTrie, c, TRUE); 70 } 71 } 72 73 U_CAPI uint32_t U_EXPORT2 74 utrie2_get32FromLeadSurrogateCodeUnit(const UTrie2 *trie, UChar32 c) { 75 if(!U_IS_LEAD(c)) { 76 return trie->errorValue; 77 } 78 if(trie->data16!=NULL) { 79 return UTRIE2_GET16_FROM_U16_SINGLE_LEAD(trie, c); 80 } else if(trie->data32!=NULL) { 81 return UTRIE2_GET32_FROM_U16_SINGLE_LEAD(trie, c); 82 } else { 83 return get32(trie->newTrie, c, FALSE); 84 } 85 } 86 87 static inline int32_t 88 u8Index(const UTrie2 *trie, UChar32 c, int32_t i) { 89 int32_t idx= 90 _UTRIE2_INDEX_FROM_CP( 91 trie, 92 trie->data32==NULL ? trie->indexLength : 0, 93 c); 94 return (idx<<3)|i; 95 } 96 97 U_CAPI int32_t U_EXPORT2 98 utrie2_internalU8NextIndex(const UTrie2 *trie, UChar32 c, 99 const uint8_t *src, const uint8_t *limit) { 100 int32_t i, length; 101 i=0; 102 /* support 64-bit pointers by avoiding cast of arbitrary difference */ 103 if((limit-src)<=7) { 104 length=(int32_t)(limit-src); 105 } else { 106 length=7; 107 } 108 c=utf8_nextCharSafeBody(src, &i, length, c, -1); 109 return u8Index(trie, c, i); 110 } 111 112 U_CAPI int32_t U_EXPORT2 113 utrie2_internalU8PrevIndex(const UTrie2 *trie, UChar32 c, 114 const uint8_t *start, const uint8_t *src) { 115 int32_t i, length; 116 /* support 64-bit pointers by avoiding cast of arbitrary difference */ 117 if((src-start)<=7) { 118 i=length=(int32_t)(src-start); 119 } else { 120 i=length=7; 121 start=src-7; 122 } 123 c=utf8_prevCharSafeBody(start, 0, &i, c, -1); 124 i=length-i; /* number of bytes read backward from src */ 125 return u8Index(trie, c, i); 126 } 127 128 U_CAPI UTrie2 * U_EXPORT2 129 utrie2_openFromSerialized(UTrie2ValueBits valueBits, 130 const void *data, int32_t length, int32_t *pActualLength, 131 UErrorCode *pErrorCode) { 132 const UTrie2Header *header; 133 const uint16_t *p16; 134 int32_t actualLength; 135 136 UTrie2 tempTrie; 137 UTrie2 *trie; 138 139 if(U_FAILURE(*pErrorCode)) { 140 return 0; 141 } 142 143 if( length<=0 || (U_POINTER_MASK_LSB(data, 3)!=0) || 144 valueBits<0 || UTRIE2_COUNT_VALUE_BITS<=valueBits 145 ) { 146 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 147 return 0; 148 } 149 150 /* enough data for a trie header? */ 151 if(length<(int32_t)sizeof(UTrie2Header)) { 152 *pErrorCode=U_INVALID_FORMAT_ERROR; 153 return 0; 154 } 155 156 /* check the signature */ 157 header=(const UTrie2Header *)data; 158 if(header->signature!=UTRIE2_SIG) { 159 *pErrorCode=U_INVALID_FORMAT_ERROR; 160 return 0; 161 } 162 163 /* get the options */ 164 if(valueBits!=(UTrie2ValueBits)(header->options&UTRIE2_OPTIONS_VALUE_BITS_MASK)) { 165 *pErrorCode=U_INVALID_FORMAT_ERROR; 166 return 0; 167 } 168 169 /* get the length values and offsets */ 170 uprv_memset(&tempTrie, 0, sizeof(tempTrie)); 171 tempTrie.indexLength=header->indexLength; 172 tempTrie.dataLength=header->shiftedDataLength<<UTRIE2_INDEX_SHIFT; 173 tempTrie.index2NullOffset=header->index2NullOffset; 174 tempTrie.dataNullOffset=header->dataNullOffset; 175 176 tempTrie.highStart=header->shiftedHighStart<<UTRIE2_SHIFT_1; 177 tempTrie.highValueIndex=tempTrie.dataLength-UTRIE2_DATA_GRANULARITY; 178 if(valueBits==UTRIE2_16_VALUE_BITS) { 179 tempTrie.highValueIndex+=tempTrie.indexLength; 180 } 181 182 /* calculate the actual length */ 183 actualLength=(int32_t)sizeof(UTrie2Header)+tempTrie.indexLength*2; 184 if(valueBits==UTRIE2_16_VALUE_BITS) { 185 actualLength+=tempTrie.dataLength*2; 186 } else { 187 actualLength+=tempTrie.dataLength*4; 188 } 189 if(length<actualLength) { 190 *pErrorCode=U_INVALID_FORMAT_ERROR; /* not enough bytes */ 191 return 0; 192 } 193 194 /* allocate the trie */ 195 trie=(UTrie2 *)uprv_malloc(sizeof(UTrie2)); 196 if(trie==NULL) { 197 *pErrorCode=U_MEMORY_ALLOCATION_ERROR; 198 return 0; 199 } 200 uprv_memcpy(trie, &tempTrie, sizeof(tempTrie)); 201 trie->memory=(uint32_t *)data; 202 trie->length=actualLength; 203 trie->isMemoryOwned=FALSE; 204 #ifdef UTRIE2_DEBUG 205 trie->name="fromSerialized"; 206 #endif 207 208 /* set the pointers to its index and data arrays */ 209 p16=(const uint16_t *)(header+1); 210 trie->index=p16; 211 p16+=trie->indexLength; 212 213 /* get the data */ 214 switch(valueBits) { 215 case UTRIE2_16_VALUE_BITS: 216 trie->data16=p16; 217 trie->data32=NULL; 218 trie->initialValue=trie->index[trie->dataNullOffset]; 219 trie->errorValue=trie->data16[UTRIE2_BAD_UTF8_DATA_OFFSET]; 220 break; 221 case UTRIE2_32_VALUE_BITS: 222 trie->data16=NULL; 223 trie->data32=(const uint32_t *)p16; 224 trie->initialValue=trie->data32[trie->dataNullOffset]; 225 trie->errorValue=trie->data32[UTRIE2_BAD_UTF8_DATA_OFFSET]; 226 break; 227 default: 228 *pErrorCode=U_INVALID_FORMAT_ERROR; 229 return 0; 230 } 231 232 if(pActualLength!=NULL) { 233 *pActualLength=actualLength; 234 } 235 return trie; 236 } 237 238 U_CAPI UTrie2 * U_EXPORT2 239 utrie2_openDummy(UTrie2ValueBits valueBits, 240 uint32_t initialValue, uint32_t errorValue, 241 UErrorCode *pErrorCode) { 242 UTrie2 *trie; 243 UTrie2Header *header; 244 uint32_t *p; 245 uint16_t *dest16; 246 int32_t indexLength, dataLength, length, i; 247 int32_t dataMove; /* >0 if the data is moved to the end of the index array */ 248 249 if(U_FAILURE(*pErrorCode)) { 250 return 0; 251 } 252 253 if(valueBits<0 || UTRIE2_COUNT_VALUE_BITS<=valueBits) { 254 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 255 return 0; 256 } 257 258 /* calculate the total length of the dummy trie data */ 259 indexLength=UTRIE2_INDEX_1_OFFSET; 260 dataLength=UTRIE2_DATA_START_OFFSET+UTRIE2_DATA_GRANULARITY; 261 length=(int32_t)sizeof(UTrie2Header)+indexLength*2; 262 if(valueBits==UTRIE2_16_VALUE_BITS) { 263 length+=dataLength*2; 264 } else { 265 length+=dataLength*4; 266 } 267 268 /* allocate the trie */ 269 trie=(UTrie2 *)uprv_malloc(sizeof(UTrie2)); 270 if(trie==NULL) { 271 *pErrorCode=U_MEMORY_ALLOCATION_ERROR; 272 return 0; 273 } 274 uprv_memset(trie, 0, sizeof(UTrie2)); 275 trie->memory=uprv_malloc(length); 276 if(trie->memory==NULL) { 277 uprv_free(trie); 278 *pErrorCode=U_MEMORY_ALLOCATION_ERROR; 279 return 0; 280 } 281 trie->length=length; 282 trie->isMemoryOwned=TRUE; 283 284 /* set the UTrie2 fields */ 285 if(valueBits==UTRIE2_16_VALUE_BITS) { 286 dataMove=indexLength; 287 } else { 288 dataMove=0; 289 } 290 291 trie->indexLength=indexLength; 292 trie->dataLength=dataLength; 293 trie->index2NullOffset=UTRIE2_INDEX_2_OFFSET; 294 trie->dataNullOffset=(uint16_t)dataMove; 295 trie->initialValue=initialValue; 296 trie->errorValue=errorValue; 297 trie->highStart=0; 298 trie->highValueIndex=dataMove+UTRIE2_DATA_START_OFFSET; 299 #ifdef UTRIE2_DEBUG 300 trie->name="dummy"; 301 #endif 302 303 /* set the header fields */ 304 header=(UTrie2Header *)trie->memory; 305 306 header->signature=UTRIE2_SIG; /* "Tri2" */ 307 header->options=(uint16_t)valueBits; 308 309 header->indexLength=(uint16_t)indexLength; 310 header->shiftedDataLength=(uint16_t)(dataLength>>UTRIE2_INDEX_SHIFT); 311 header->index2NullOffset=(uint16_t)UTRIE2_INDEX_2_OFFSET; 312 header->dataNullOffset=(uint16_t)dataMove; 313 header->shiftedHighStart=0; 314 315 /* fill the index and data arrays */ 316 dest16=(uint16_t *)(header+1); 317 trie->index=dest16; 318 319 /* write the index-2 array values shifted right by UTRIE2_INDEX_SHIFT */ 320 for(i=0; i<UTRIE2_INDEX_2_BMP_LENGTH; ++i) { 321 *dest16++=(uint16_t)(dataMove>>UTRIE2_INDEX_SHIFT); /* null data block */ 322 } 323 324 /* write UTF-8 2-byte index-2 values, not right-shifted */ 325 for(i=0; i<(0xc2-0xc0); ++i) { /* C0..C1 */ 326 *dest16++=(uint16_t)(dataMove+UTRIE2_BAD_UTF8_DATA_OFFSET); 327 } 328 for(; i<(0xe0-0xc0); ++i) { /* C2..DF */ 329 *dest16++=(uint16_t)dataMove; 330 } 331 332 /* write the 16/32-bit data array */ 333 switch(valueBits) { 334 case UTRIE2_16_VALUE_BITS: 335 /* write 16-bit data values */ 336 trie->data16=dest16; 337 trie->data32=NULL; 338 for(i=0; i<0x80; ++i) { 339 *dest16++=(uint16_t)initialValue; 340 } 341 for(; i<0xc0; ++i) { 342 *dest16++=(uint16_t)errorValue; 343 } 344 /* highValue and reserved values */ 345 for(i=0; i<UTRIE2_DATA_GRANULARITY; ++i) { 346 *dest16++=(uint16_t)initialValue; 347 } 348 break; 349 case UTRIE2_32_VALUE_BITS: 350 /* write 32-bit data values */ 351 p=(uint32_t *)dest16; 352 trie->data16=NULL; 353 trie->data32=p; 354 for(i=0; i<0x80; ++i) { 355 *p++=initialValue; 356 } 357 for(; i<0xc0; ++i) { 358 *p++=errorValue; 359 } 360 /* highValue and reserved values */ 361 for(i=0; i<UTRIE2_DATA_GRANULARITY; ++i) { 362 *p++=initialValue; 363 } 364 break; 365 default: 366 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 367 return 0; 368 } 369 370 return trie; 371 } 372 373 U_CAPI void U_EXPORT2 374 utrie2_close(UTrie2 *trie) { 375 if(trie!=NULL) { 376 if(trie->isMemoryOwned) { 377 uprv_free(trie->memory); 378 } 379 if(trie->newTrie!=NULL) { 380 uprv_free(trie->newTrie->data); 381 #ifdef UCPTRIE_DEBUG 382 umutablecptrie_close(trie->newTrie->t3); 383 #endif 384 uprv_free(trie->newTrie); 385 } 386 uprv_free(trie); 387 } 388 } 389 390 U_CAPI UBool U_EXPORT2 391 utrie2_isFrozen(const UTrie2 *trie) { 392 return (UBool)(trie->newTrie==NULL); 393 } 394 395 U_CAPI int32_t U_EXPORT2 396 utrie2_serialize(const UTrie2 *trie, 397 void *data, int32_t capacity, 398 UErrorCode *pErrorCode) { 399 /* argument check */ 400 if(U_FAILURE(*pErrorCode)) { 401 return 0; 402 } 403 404 if( trie==NULL || trie->memory==NULL || trie->newTrie!=NULL || 405 capacity<0 || (capacity>0 && (data==NULL || (U_POINTER_MASK_LSB(data, 3)!=0))) 406 ) { 407 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; 408 return 0; 409 } 410 411 if(capacity>=trie->length) { 412 uprv_memcpy(data, trie->memory, trie->length); 413 } else { 414 *pErrorCode=U_BUFFER_OVERFLOW_ERROR; 415 } 416 return trie->length; 417 } 418 419 /* enumeration -------------------------------------------------------------- */ 420 421 #define MIN_VALUE(a, b) ((a)<(b) ? (a) : (b)) 422 423 /* default UTrie2EnumValue() returns the input value itself */ 424 static uint32_t U_CALLCONV 425 enumSameValue(const void * /*context*/, uint32_t value) { 426 return value; 427 } 428 429 /** 430 * Enumerate all ranges of code points with the same relevant values. 431 * The values are transformed from the raw trie entries by the enumValue function. 432 * 433 * Currently requires start<limit and both start and limit must be multiples 434 * of UTRIE2_DATA_BLOCK_LENGTH. 435 * 436 * Optimizations: 437 * - Skip a whole block if we know that it is filled with a single value, 438 * and it is the same as we visited just before. 439 * - Handle the null block specially because we know a priori that it is filled 440 * with a single value. 441 */ 442 static void 443 enumEitherTrie(const UTrie2 *trie, 444 UChar32 start, UChar32 limit, 445 UTrie2EnumValue *enumValue, UTrie2EnumRange *enumRange, const void *context) { 446 const uint32_t *data32; 447 const uint16_t *idx; 448 449 uint32_t value, prevValue, initialValue; 450 UChar32 c, prev, highStart; 451 int32_t j, i2Block, prevI2Block, index2NullOffset, block, prevBlock, nullBlock; 452 453 if(enumRange==NULL) { 454 return; 455 } 456 if(enumValue==NULL) { 457 enumValue=enumSameValue; 458 } 459 460 if(trie->newTrie==NULL) { 461 /* frozen trie */ 462 idx=trie->index; 463 U_ASSERT(idx!=NULL); /* the following code assumes trie->newTrie is not NULL when idx is NULL */ 464 data32=trie->data32; 465 466 index2NullOffset=trie->index2NullOffset; 467 nullBlock=trie->dataNullOffset; 468 } else { 469 /* unfrozen, mutable trie */ 470 idx=NULL; 471 data32=trie->newTrie->data; 472 U_ASSERT(data32!=NULL); /* the following code assumes idx is not NULL when data32 is NULL */ 473 474 index2NullOffset=trie->newTrie->index2NullOffset; 475 nullBlock=trie->newTrie->dataNullOffset; 476 } 477 478 highStart=trie->highStart; 479 480 /* get the enumeration value that corresponds to an initial-value trie data entry */ 481 initialValue=enumValue(context, trie->initialValue); 482 483 /* set variables for previous range */ 484 prevI2Block=-1; 485 prevBlock=-1; 486 prev=start; 487 prevValue=0; 488 489 /* enumerate index-2 blocks */ 490 for(c=start; c<limit && c<highStart;) { 491 /* Code point limit for iterating inside this i2Block. */ 492 UChar32 tempLimit=c+UTRIE2_CP_PER_INDEX_1_ENTRY; 493 if(limit<tempLimit) { 494 tempLimit=limit; 495 } 496 if(c<=0xffff) { 497 if(!U_IS_SURROGATE(c)) { 498 i2Block=c>>UTRIE2_SHIFT_2; 499 } else if(U_IS_SURROGATE_LEAD(c)) { 500 /* 501 * Enumerate values for lead surrogate code points, not code units: 502 * This special block has half the normal length. 503 */ 504 i2Block=UTRIE2_LSCP_INDEX_2_OFFSET; 505 tempLimit=MIN_VALUE(0xdc00, limit); 506 } else { 507 /* 508 * Switch back to the normal part of the index-2 table. 509 * Enumerate the second half of the surrogates block. 510 */ 511 i2Block=0xd800>>UTRIE2_SHIFT_2; 512 tempLimit=MIN_VALUE(0xe000, limit); 513 } 514 } else { 515 /* supplementary code points */ 516 if(idx!=NULL) { 517 i2Block=idx[(UTRIE2_INDEX_1_OFFSET-UTRIE2_OMITTED_BMP_INDEX_1_LENGTH)+ 518 (c>>UTRIE2_SHIFT_1)]; 519 } else { 520 i2Block=trie->newTrie->index1[c>>UTRIE2_SHIFT_1]; 521 } 522 if(i2Block==prevI2Block && (c-prev)>=UTRIE2_CP_PER_INDEX_1_ENTRY) { 523 /* 524 * The index-2 block is the same as the previous one, and filled with prevValue. 525 * Only possible for supplementary code points because the linear-BMP index-2 526 * table creates unique i2Block values. 527 */ 528 c+=UTRIE2_CP_PER_INDEX_1_ENTRY; 529 continue; 530 } 531 } 532 prevI2Block=i2Block; 533 if(i2Block==index2NullOffset) { 534 /* this is the null index-2 block */ 535 if(prevValue!=initialValue) { 536 if(prev<c && !enumRange(context, prev, c-1, prevValue)) { 537 return; 538 } 539 prevBlock=nullBlock; 540 prev=c; 541 prevValue=initialValue; 542 } 543 c+=UTRIE2_CP_PER_INDEX_1_ENTRY; 544 } else { 545 /* enumerate data blocks for one index-2 block */ 546 int32_t i2, i2Limit; 547 i2=(c>>UTRIE2_SHIFT_2)&UTRIE2_INDEX_2_MASK; 548 if((c>>UTRIE2_SHIFT_1)==(tempLimit>>UTRIE2_SHIFT_1)) { 549 i2Limit=(tempLimit>>UTRIE2_SHIFT_2)&UTRIE2_INDEX_2_MASK; 550 } else { 551 i2Limit=UTRIE2_INDEX_2_BLOCK_LENGTH; 552 } 553 for(; i2<i2Limit; ++i2) { 554 if(idx!=NULL) { 555 block=(int32_t)idx[i2Block+i2]<<UTRIE2_INDEX_SHIFT; 556 } else { 557 block=trie->newTrie->index2[i2Block+i2]; 558 } 559 if(block==prevBlock && (c-prev)>=UTRIE2_DATA_BLOCK_LENGTH) { 560 /* the block is the same as the previous one, and filled with prevValue */ 561 c+=UTRIE2_DATA_BLOCK_LENGTH; 562 continue; 563 } 564 prevBlock=block; 565 if(block==nullBlock) { 566 /* this is the null data block */ 567 if(prevValue!=initialValue) { 568 if(prev<c && !enumRange(context, prev, c-1, prevValue)) { 569 return; 570 } 571 prev=c; 572 prevValue=initialValue; 573 } 574 c+=UTRIE2_DATA_BLOCK_LENGTH; 575 } else { 576 for(j=0; j<UTRIE2_DATA_BLOCK_LENGTH; ++j) { 577 value=enumValue(context, data32!=NULL ? data32[block+j] : idx[block+j]); 578 if(value!=prevValue) { 579 if(prev<c && !enumRange(context, prev, c-1, prevValue)) { 580 return; 581 } 582 prev=c; 583 prevValue=value; 584 } 585 ++c; 586 } 587 } 588 } 589 } 590 } 591 592 if(c>limit) { 593 c=limit; /* could be higher if in the index2NullOffset */ 594 } else if(c<limit) { 595 /* c==highStart<limit */ 596 uint32_t highValue; 597 if(idx!=NULL) { 598 highValue= 599 data32!=NULL ? 600 data32[trie->highValueIndex] : 601 idx[trie->highValueIndex]; 602 } else { 603 highValue=trie->newTrie->data[trie->newTrie->dataLength-UTRIE2_DATA_GRANULARITY]; 604 } 605 value=enumValue(context, highValue); 606 if(value!=prevValue) { 607 if(prev<c && !enumRange(context, prev, c-1, prevValue)) { 608 return; 609 } 610 prev=c; 611 prevValue=value; 612 } 613 c=limit; 614 } 615 616 /* deliver last range */ 617 enumRange(context, prev, c-1, prevValue); 618 } 619 620 U_CAPI void U_EXPORT2 621 utrie2_enum(const UTrie2 *trie, 622 UTrie2EnumValue *enumValue, UTrie2EnumRange *enumRange, const void *context) { 623 enumEitherTrie(trie, 0, 0x110000, enumValue, enumRange, context); 624 } 625 626 U_CAPI void U_EXPORT2 627 utrie2_enumForLeadSurrogate(const UTrie2 *trie, UChar32 lead, 628 UTrie2EnumValue *enumValue, UTrie2EnumRange *enumRange, 629 const void *context) { 630 if(!U16_IS_LEAD(lead)) { 631 return; 632 } 633 lead=(lead-0xd7c0)<<10; /* start code point */ 634 enumEitherTrie(trie, lead, lead+0x400, enumValue, enumRange, context); 635 } 636 637 /* C++ convenience wrappers ------------------------------------------------- */ 638 639 U_NAMESPACE_BEGIN 640 641 uint16_t BackwardUTrie2StringIterator::previous16() { 642 codePointLimit=codePointStart; 643 if(start>=codePointStart) { 644 codePoint=U_SENTINEL; 645 return static_cast<uint16_t>(trie->errorValue); 646 } 647 uint16_t result; 648 UTRIE2_U16_PREV16(trie, start, codePointStart, codePoint, result); 649 return result; 650 } 651 652 uint16_t ForwardUTrie2StringIterator::next16() { 653 codePointStart=codePointLimit; 654 if(codePointLimit==limit) { 655 codePoint=U_SENTINEL; 656 return static_cast<uint16_t>(trie->errorValue); 657 } 658 uint16_t result; 659 UTRIE2_U16_NEXT16(trie, codePointLimit, limit, codePoint, result); 660 return result; 661 } 662 663 U_NAMESPACE_END 664