1 /** 2 * This code handles decoding UTF strings for `foreach_reverse` loops. 3 * 4 * Copyright: Copyright Digital Mars 2004 - 2010. 5 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 6 * Authors: Walter Bright, Sean Kelly 7 * Source: $(DRUNTIMESRC rt/_aApplyR.d) 8 */ 9 module rt.aApplyR; 10 11 import core.internal.utf; 12 13 /**********************************************/ 14 /* 1 argument versions */ 15 16 // Note: dg is extern(D), but _aApplyRcd() is extern(C) 17 18 /** 19 Delegate type corresponding to transformed loop body 20 21 The parameter is a pointer to the current `char`, `wchar` or `dchar` 22 23 Returns: non-zero when a `break` statement is hit 24 */ 25 extern (D) alias dg_t = int delegate(void* c); 26 27 /** 28 Same as `_aApplyXXX` functions, but for `foreach_reverse` 29 30 Params: 31 aa = input string 32 dg = foreach body transformed into a delegate, similar to `opApply` 33 34 Returns: 35 non-zero when the loop was exited through a `break` 36 */ 37 extern (C) int _aApplyRcd1(scope const(char)[] aa, dg_t dg) 38 { int result; 39 40 debug(apply) printf("_aApplyRcd1(), len = %d\n", aa.length); 41 for (size_t i = aa.length; i != 0; ) 42 { dchar d; 43 44 i--; 45 d = aa[i]; 46 if (d & 0x80) 47 { char c = cast(char)d; 48 uint j; 49 uint m = 0x3F; 50 d = 0; 51 while ((c & 0xC0) != 0xC0) 52 { if (i == 0) 53 onUnicodeError("Invalid UTF-8 sequence", 0); 54 i--; 55 d |= (c & 0x3F) << j; 56 j += 6; 57 m >>= 1; 58 c = aa[i]; 59 } 60 d |= (c & m) << j; 61 } 62 result = dg(cast(void *)&d); 63 if (result) 64 break; 65 } 66 return result; 67 } 68 69 unittest 70 { 71 debug(apply) printf("_aApplyRcd1.unittest\n"); 72 73 auto s = "hello"c[]; 74 int i; 75 76 foreach_reverse (dchar d; s) 77 { 78 switch (i) 79 { 80 case 0: assert(d == 'o'); break; 81 case 1: assert(d == 'l'); break; 82 case 2: assert(d == 'l'); break; 83 case 3: assert(d == 'e'); break; 84 case 4: assert(d == 'h'); break; 85 default: assert(0); 86 } 87 i++; 88 } 89 assert(i == 5); 90 91 s = "a\u1234\U000A0456b"; 92 i = 0; 93 foreach_reverse (dchar d; s) 94 { 95 //printf("i = %d, d = %x\n", i, d); 96 switch (i) 97 { 98 case 0: assert(d == 'b'); break; 99 case 1: assert(d == '\U000A0456'); break; 100 case 2: assert(d == '\u1234'); break; 101 case 3: assert(d == 'a'); break; 102 default: assert(0); 103 } 104 i++; 105 } 106 assert(i == 4); 107 } 108 109 /// ditto 110 extern (C) int _aApplyRwd1(scope const(wchar)[] aa, dg_t dg) 111 { int result; 112 113 debug(apply) printf("_aApplyRwd1(), len = %d\n", aa.length); 114 for (size_t i = aa.length; i != 0; ) 115 { dchar d; 116 117 i--; 118 d = aa[i]; 119 if (d >= 0xDC00 && d <= 0xDFFF) 120 { if (i == 0) 121 onUnicodeError("Invalid UTF-16 sequence", 0); 122 i--; 123 d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00); 124 } 125 result = dg(cast(void *)&d); 126 if (result) 127 break; 128 } 129 return result; 130 } 131 132 unittest 133 { 134 debug(apply) printf("_aApplyRwd1.unittest\n"); 135 136 auto s = "hello"w[]; 137 int i; 138 139 foreach_reverse (dchar d; s) 140 { 141 switch (i) 142 { 143 case 0: assert(d == 'o'); break; 144 case 1: assert(d == 'l'); break; 145 case 2: assert(d == 'l'); break; 146 case 3: assert(d == 'e'); break; 147 case 4: assert(d == 'h'); break; 148 default: assert(0); 149 } 150 i++; 151 } 152 assert(i == 5); 153 154 s = "a\u1234\U000A0456b"; 155 i = 0; 156 foreach_reverse (dchar d; s) 157 { 158 //printf("i = %d, d = %x\n", i, d); 159 switch (i) 160 { 161 case 0: assert(d == 'b'); break; 162 case 1: assert(d == '\U000A0456'); break; 163 case 2: assert(d == '\u1234'); break; 164 case 3: assert(d == 'a'); break; 165 default: assert(0); 166 } 167 i++; 168 } 169 assert(i == 4); 170 } 171 172 /// ditto 173 extern (C) int _aApplyRcw1(scope const(char)[] aa, dg_t dg) 174 { int result; 175 176 debug(apply) printf("_aApplyRcw1(), len = %d\n", aa.length); 177 for (size_t i = aa.length; i != 0; ) 178 { dchar d; 179 wchar w; 180 181 i--; 182 w = aa[i]; 183 if (w & 0x80) 184 { char c = cast(char)w; 185 uint j; 186 uint m = 0x3F; 187 d = 0; 188 while ((c & 0xC0) != 0xC0) 189 { if (i == 0) 190 onUnicodeError("Invalid UTF-8 sequence", 0); 191 i--; 192 d |= (c & 0x3F) << j; 193 j += 6; 194 m >>= 1; 195 c = aa[i]; 196 } 197 d |= (c & m) << j; 198 199 if (d <= 0xFFFF) 200 w = cast(wchar) d; 201 else 202 { 203 w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800); 204 result = dg(cast(void *)&w); 205 if (result) 206 break; 207 w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00); 208 } 209 } 210 result = dg(cast(void *)&w); 211 if (result) 212 break; 213 } 214 return result; 215 } 216 217 unittest 218 { 219 debug(apply) printf("_aApplyRcw1.unittest\n"); 220 221 auto s = "hello"c[]; 222 int i; 223 224 foreach_reverse (wchar d; s) 225 { 226 switch (i) 227 { 228 case 0: assert(d == 'o'); break; 229 case 1: assert(d == 'l'); break; 230 case 2: assert(d == 'l'); break; 231 case 3: assert(d == 'e'); break; 232 case 4: assert(d == 'h'); break; 233 default: assert(0); 234 } 235 i++; 236 } 237 assert(i == 5); 238 239 s = "a\u1234\U000A0456b"; 240 i = 0; 241 foreach_reverse (wchar d; s) 242 { 243 //printf("i = %d, d = %x\n", i, d); 244 switch (i) 245 { 246 case 0: assert(d == 'b'); break; 247 case 1: assert(d == 0xDA41); break; 248 case 2: assert(d == 0xDC56); break; 249 case 3: assert(d == 0x1234); break; 250 case 4: assert(d == 'a'); break; 251 default: assert(0); 252 } 253 i++; 254 } 255 assert(i == 5); 256 } 257 258 /// ditto 259 extern (C) int _aApplyRwc1(scope const(wchar)[] aa, dg_t dg) 260 { int result; 261 262 debug(apply) printf("_aApplyRwc1(), len = %d\n", aa.length); 263 for (size_t i = aa.length; i != 0; ) 264 { dchar d; 265 char c; 266 267 i--; 268 d = aa[i]; 269 if (d >= 0xDC00 && d <= 0xDFFF) 270 { if (i == 0) 271 onUnicodeError("Invalid UTF-16 sequence", 0); 272 i--; 273 d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00); 274 } 275 276 if (d & ~0x7F) 277 { 278 char[4] buf = void; 279 280 auto b = toUTF8(buf, d); 281 foreach (char c2; b) 282 { 283 result = dg(cast(void *)&c2); 284 if (result) 285 return result; 286 } 287 continue; 288 } 289 c = cast(char)d; 290 result = dg(cast(void *)&c); 291 if (result) 292 break; 293 } 294 return result; 295 } 296 297 unittest 298 { 299 debug(apply) printf("_aApplyRwc1.unittest\n"); 300 301 auto s = "hello"w[]; 302 int i; 303 304 foreach_reverse (char d; s) 305 { 306 switch (i) 307 { 308 case 0: assert(d == 'o'); break; 309 case 1: assert(d == 'l'); break; 310 case 2: assert(d == 'l'); break; 311 case 3: assert(d == 'e'); break; 312 case 4: assert(d == 'h'); break; 313 default: assert(0); 314 } 315 i++; 316 } 317 assert(i == 5); 318 319 s = "a\u1234\U000A0456b"; 320 i = 0; 321 foreach_reverse (char d; s) 322 { 323 //printf("i = %d, d = %x\n", i, d); 324 switch (i) 325 { 326 case 0: assert(d == 'b'); break; 327 case 1: assert(d == 0xF2); break; 328 case 2: assert(d == 0xA0); break; 329 case 3: assert(d == 0x91); break; 330 case 4: assert(d == 0x96); break; 331 case 5: assert(d == 0xE1); break; 332 case 6: assert(d == 0x88); break; 333 case 7: assert(d == 0xB4); break; 334 case 8: assert(d == 'a'); break; 335 default: assert(0); 336 } 337 i++; 338 } 339 assert(i == 9); 340 } 341 342 /// ditto 343 extern (C) int _aApplyRdc1(scope const(dchar)[] aa, dg_t dg) 344 { int result; 345 346 debug(apply) printf("_aApplyRdc1(), len = %d\n", aa.length); 347 for (size_t i = aa.length; i != 0;) 348 { dchar d = aa[--i]; 349 char c; 350 351 if (d & ~0x7F) 352 { 353 char[4] buf = void; 354 355 auto b = toUTF8(buf, d); 356 foreach (char c2; b) 357 { 358 result = dg(cast(void *)&c2); 359 if (result) 360 return result; 361 } 362 continue; 363 } 364 else 365 { 366 c = cast(char)d; 367 } 368 result = dg(cast(void *)&c); 369 if (result) 370 break; 371 } 372 return result; 373 } 374 375 unittest 376 { 377 debug(apply) printf("_aApplyRdc1.unittest\n"); 378 379 auto s = "hello"d[]; 380 int i; 381 382 foreach_reverse (char d; s) 383 { 384 switch (i) 385 { 386 case 0: assert(d == 'o'); break; 387 case 1: assert(d == 'l'); break; 388 case 2: assert(d == 'l'); break; 389 case 3: assert(d == 'e'); break; 390 case 4: assert(d == 'h'); break; 391 default: assert(0); 392 } 393 i++; 394 } 395 assert(i == 5); 396 397 s = "a\u1234\U000A0456b"; 398 i = 0; 399 foreach_reverse (char d; s) 400 { 401 //printf("i = %d, d = %x\n", i, d); 402 switch (i) 403 { 404 case 0: assert(d == 'b'); break; 405 case 1: assert(d == 0xF2); break; 406 case 2: assert(d == 0xA0); break; 407 case 3: assert(d == 0x91); break; 408 case 4: assert(d == 0x96); break; 409 case 5: assert(d == 0xE1); break; 410 case 6: assert(d == 0x88); break; 411 case 7: assert(d == 0xB4); break; 412 case 8: assert(d == 'a'); break; 413 default: assert(0); 414 } 415 i++; 416 } 417 assert(i == 9); 418 } 419 420 /// ditto 421 extern (C) int _aApplyRdw1(scope const(dchar)[] aa, dg_t dg) 422 { int result; 423 424 debug(apply) printf("_aApplyRdw1(), len = %d\n", aa.length); 425 for (size_t i = aa.length; i != 0; ) 426 { dchar d = aa[--i]; 427 wchar w; 428 429 if (d <= 0xFFFF) 430 w = cast(wchar) d; 431 else 432 { 433 w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800); 434 result = dg(cast(void *)&w); 435 if (result) 436 break; 437 w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00); 438 } 439 result = dg(cast(void *)&w); 440 if (result) 441 break; 442 } 443 return result; 444 } 445 446 unittest 447 { 448 debug(apply) printf("_aApplyRdw1.unittest\n"); 449 450 auto s = "hello"d[]; 451 int i; 452 453 foreach_reverse (wchar d; s) 454 { 455 switch (i) 456 { 457 case 0: assert(d == 'o'); break; 458 case 1: assert(d == 'l'); break; 459 case 2: assert(d == 'l'); break; 460 case 3: assert(d == 'e'); break; 461 case 4: assert(d == 'h'); break; 462 default: assert(0); 463 } 464 i++; 465 } 466 assert(i == 5); 467 468 s = "a\u1234\U000A0456b"; 469 i = 0; 470 foreach_reverse (wchar d; s) 471 { 472 //printf("i = %d, d = %x\n", i, d); 473 switch (i) 474 { 475 case 0: assert(d == 'b'); break; 476 case 1: assert(d == 0xDA41); break; 477 case 2: assert(d == 0xDC56); break; 478 case 3: assert(d == 0x1234); break; 479 case 4: assert(d == 'a'); break; 480 default: assert(0); 481 } 482 i++; 483 } 484 assert(i == 5); 485 } 486 487 488 /****************************************************************************/ 489 /* 2 argument versions */ 490 491 /** 492 Delegate type corresponding to transformed loop body 493 494 Parameters are pointers to a `size_t` loop index, and the current `char`, `wchar` or `dchar`. 495 496 Returns: non-zero when a `break` statement is hit 497 */ 498 extern (D) alias dg2_t = int delegate(void* i, void* c); 499 500 // Note: dg is extern(D), but _aApplyRcd2() is extern(C) 501 502 /** 503 Variants of _aApplyRXXX that include a loop index. 504 */ 505 extern (C) int _aApplyRcd2(scope const(char)[] aa, dg2_t dg) 506 { int result; 507 size_t i; 508 size_t len = aa.length; 509 510 debug(apply) printf("_aApplyRcd2(), len = %d\n", len); 511 for (i = len; i != 0; ) 512 { dchar d; 513 514 i--; 515 d = aa[i]; 516 if (d & 0x80) 517 { char c = cast(char)d; 518 uint j; 519 uint m = 0x3F; 520 d = 0; 521 while ((c & 0xC0) != 0xC0) 522 { if (i == 0) 523 onUnicodeError("Invalid UTF-8 sequence", 0); 524 i--; 525 d |= (c & 0x3F) << j; 526 j += 6; 527 m >>= 1; 528 c = aa[i]; 529 } 530 d |= (c & m) << j; 531 } 532 result = dg(&i, cast(void *)&d); 533 if (result) 534 break; 535 } 536 return result; 537 } 538 539 unittest 540 { 541 debug(apply) printf("_aApplyRcd2.unittest\n"); 542 543 auto s = "hello"c[]; 544 int i; 545 546 foreach_reverse (k, dchar d; s) 547 { 548 assert(k == 4 - i); 549 switch (i) 550 { 551 case 0: assert(d == 'o'); break; 552 case 1: assert(d == 'l'); break; 553 case 2: assert(d == 'l'); break; 554 case 3: assert(d == 'e'); break; 555 case 4: assert(d == 'h'); break; 556 default: assert(0); 557 } 558 i++; 559 } 560 assert(i == 5); 561 562 s = "a\u1234\U000A0456b"; 563 i = 0; 564 foreach_reverse (k, dchar d; s) 565 { 566 //printf("i = %d, k = %d, d = %x\n", i, k, d); 567 switch (i) 568 { 569 case 0: assert(d == 'b'); assert(k == 8); break; 570 case 1: assert(d == '\U000A0456'); assert(k == 4); break; 571 case 2: assert(d == '\u1234'); assert(k == 1); break; 572 case 3: assert(d == 'a'); assert(k == 0); break; 573 default: assert(0); 574 } 575 i++; 576 } 577 assert(i == 4); 578 } 579 580 /// ditto 581 extern (C) int _aApplyRwd2(scope const(wchar)[] aa, dg2_t dg) 582 { int result; 583 584 debug(apply) printf("_aApplyRwd2(), len = %d\n", aa.length); 585 for (size_t i = aa.length; i != 0; ) 586 { dchar d; 587 588 i--; 589 d = aa[i]; 590 if (d >= 0xDC00 && d <= 0xDFFF) 591 { if (i == 0) 592 onUnicodeError("Invalid UTF-16 sequence", 0); 593 i--; 594 d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00); 595 } 596 result = dg(&i, cast(void *)&d); 597 if (result) 598 break; 599 } 600 return result; 601 } 602 603 unittest 604 { 605 debug(apply) printf("_aApplyRwd2.unittest\n"); 606 607 auto s = "hello"w[]; 608 int i; 609 610 foreach_reverse (k, dchar d; s) 611 { 612 //printf("i = %d, k = %d, d = %x\n", i, k, d); 613 assert(k == 4 - i); 614 switch (i) 615 { 616 case 0: assert(d == 'o'); break; 617 case 1: assert(d == 'l'); break; 618 case 2: assert(d == 'l'); break; 619 case 3: assert(d == 'e'); break; 620 case 4: assert(d == 'h'); break; 621 default: assert(0); 622 } 623 i++; 624 } 625 assert(i == 5); 626 627 s = "a\u1234\U000A0456b"; 628 i = 0; 629 foreach_reverse (k, dchar d; s) 630 { 631 //printf("i = %d, k = %d, d = %x\n", i, k, d); 632 switch (i) 633 { 634 case 0: assert(k == 4); assert(d == 'b'); break; 635 case 1: assert(k == 2); assert(d == '\U000A0456'); break; 636 case 2: assert(k == 1); assert(d == '\u1234'); break; 637 case 3: assert(k == 0); assert(d == 'a'); break; 638 default: assert(0); 639 } 640 i++; 641 } 642 assert(i == 4); 643 } 644 645 /// ditto 646 extern (C) int _aApplyRcw2(scope const(char)[] aa, dg2_t dg) 647 { int result; 648 649 debug(apply) printf("_aApplyRcw2(), len = %d\n", aa.length); 650 for (size_t i = aa.length; i != 0; ) 651 { dchar d; 652 wchar w; 653 654 i--; 655 w = aa[i]; 656 if (w & 0x80) 657 { char c = cast(char)w; 658 uint j; 659 uint m = 0x3F; 660 d = 0; 661 while ((c & 0xC0) != 0xC0) 662 { if (i == 0) 663 onUnicodeError("Invalid UTF-8 sequence", 0); 664 i--; 665 d |= (c & 0x3F) << j; 666 j += 6; 667 m >>= 1; 668 c = aa[i]; 669 } 670 d |= (c & m) << j; 671 672 if (d <= 0xFFFF) 673 w = cast(wchar) d; 674 else 675 { 676 w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800); 677 result = dg(&i, cast(void *)&w); 678 if (result) 679 break; 680 w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00); 681 } 682 } 683 result = dg(&i, cast(void *)&w); 684 if (result) 685 break; 686 } 687 return result; 688 } 689 690 unittest 691 { 692 debug(apply) printf("_aApplyRcw2.unittest\n"); 693 694 auto s = "hello"c[]; 695 int i; 696 697 foreach_reverse (k, wchar d; s) 698 { 699 //printf("i = %d, k = %d, d = %x\n", i, k, d); 700 assert(k == 4 - i); 701 switch (i) 702 { 703 case 0: assert(d == 'o'); break; 704 case 1: assert(d == 'l'); break; 705 case 2: assert(d == 'l'); break; 706 case 3: assert(d == 'e'); break; 707 case 4: assert(d == 'h'); break; 708 default: assert(0); 709 } 710 i++; 711 } 712 assert(i == 5); 713 714 s = "a\u1234\U000A0456b"; 715 i = 0; 716 foreach_reverse (k, wchar d; s) 717 { 718 //printf("i = %d, k = %d, d = %x\n", i, k, d); 719 switch (i) 720 { 721 case 0: assert(k == 8); assert(d == 'b'); break; 722 case 1: assert(k == 4); assert(d == 0xDA41); break; 723 case 2: assert(k == 4); assert(d == 0xDC56); break; 724 case 3: assert(k == 1); assert(d == 0x1234); break; 725 case 4: assert(k == 0); assert(d == 'a'); break; 726 default: assert(0); 727 } 728 i++; 729 } 730 assert(i == 5); 731 } 732 733 /// ditto 734 extern (C) int _aApplyRwc2(scope const(wchar)[] aa, dg2_t dg) 735 { int result; 736 737 debug(apply) printf("_aApplyRwc2(), len = %d\n", aa.length); 738 for (size_t i = aa.length; i != 0; ) 739 { dchar d; 740 char c; 741 742 i--; 743 d = aa[i]; 744 if (d >= 0xDC00 && d <= 0xDFFF) 745 { if (i == 0) 746 onUnicodeError("Invalid UTF-16 sequence", 0); 747 i--; 748 d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00); 749 } 750 751 if (d & ~0x7F) 752 { 753 char[4] buf = void; 754 755 auto b = toUTF8(buf, d); 756 foreach (char c2; b) 757 { 758 result = dg(&i, cast(void *)&c2); 759 if (result) 760 return result; 761 } 762 continue; 763 } 764 c = cast(char)d; 765 result = dg(&i, cast(void *)&c); 766 if (result) 767 break; 768 } 769 return result; 770 } 771 772 unittest 773 { 774 debug(apply) printf("_aApplyRwc2.unittest\n"); 775 776 auto s = "hello"w[]; 777 int i; 778 779 foreach_reverse (k, char d; s) 780 { 781 //printf("i = %d, k = %d, d = %x\n", i, k, d); 782 assert(k == 4 - i); 783 switch (i) 784 { 785 case 0: assert(d == 'o'); break; 786 case 1: assert(d == 'l'); break; 787 case 2: assert(d == 'l'); break; 788 case 3: assert(d == 'e'); break; 789 case 4: assert(d == 'h'); break; 790 default: assert(0); 791 } 792 i++; 793 } 794 assert(i == 5); 795 796 s = "a\u1234\U000A0456b"; 797 i = 0; 798 foreach_reverse (k, char d; s) 799 { 800 //printf("i = %d, k = %d, d = %x\n", i, k, d); 801 switch (i) 802 { 803 case 0: assert(k == 4); assert(d == 'b'); break; 804 case 1: assert(k == 2); assert(d == 0xF2); break; 805 case 2: assert(k == 2); assert(d == 0xA0); break; 806 case 3: assert(k == 2); assert(d == 0x91); break; 807 case 4: assert(k == 2); assert(d == 0x96); break; 808 case 5: assert(k == 1); assert(d == 0xE1); break; 809 case 6: assert(k == 1); assert(d == 0x88); break; 810 case 7: assert(k == 1); assert(d == 0xB4); break; 811 case 8: assert(k == 0); assert(d == 'a'); break; 812 default: assert(0); 813 } 814 i++; 815 } 816 assert(i == 9); 817 } 818 819 /// ditto 820 extern (C) int _aApplyRdc2(scope const(dchar)[] aa, dg2_t dg) 821 { int result; 822 823 debug(apply) printf("_aApplyRdc2(), len = %d\n", aa.length); 824 for (size_t i = aa.length; i != 0; ) 825 { dchar d = aa[--i]; 826 char c; 827 828 if (d & ~0x7F) 829 { 830 char[4] buf = void; 831 832 auto b = toUTF8(buf, d); 833 foreach (char c2; b) 834 { 835 result = dg(&i, cast(void *)&c2); 836 if (result) 837 return result; 838 } 839 continue; 840 } 841 else 842 { c = cast(char)d; 843 } 844 result = dg(&i, cast(void *)&c); 845 if (result) 846 break; 847 } 848 return result; 849 } 850 851 unittest 852 { 853 debug(apply) printf("_aApplyRdc2.unittest\n"); 854 855 auto s = "hello"d[]; 856 int i; 857 858 foreach_reverse (k, char d; s) 859 { 860 //printf("i = %d, k = %d, d = %x\n", i, k, d); 861 assert(k == 4 - i); 862 switch (i) 863 { 864 case 0: assert(d == 'o'); break; 865 case 1: assert(d == 'l'); break; 866 case 2: assert(d == 'l'); break; 867 case 3: assert(d == 'e'); break; 868 case 4: assert(d == 'h'); break; 869 default: assert(0); 870 } 871 i++; 872 } 873 assert(i == 5); 874 875 s = "a\u1234\U000A0456b"; 876 i = 0; 877 foreach_reverse (k, char d; s) 878 { 879 //printf("i = %d, k = %d, d = %x\n", i, k, d); 880 switch (i) 881 { 882 case 0: assert(k == 3); assert(d == 'b'); break; 883 case 1: assert(k == 2); assert(d == 0xF2); break; 884 case 2: assert(k == 2); assert(d == 0xA0); break; 885 case 3: assert(k == 2); assert(d == 0x91); break; 886 case 4: assert(k == 2); assert(d == 0x96); break; 887 case 5: assert(k == 1); assert(d == 0xE1); break; 888 case 6: assert(k == 1); assert(d == 0x88); break; 889 case 7: assert(k == 1); assert(d == 0xB4); break; 890 case 8: assert(k == 0); assert(d == 'a'); break; 891 default: assert(0); 892 } 893 i++; 894 } 895 assert(i == 9); 896 } 897 898 /// ditto 899 extern (C) int _aApplyRdw2(scope const(dchar)[] aa, dg2_t dg) 900 { int result; 901 902 debug(apply) printf("_aApplyRdw2(), len = %d\n", aa.length); 903 for (size_t i = aa.length; i != 0; ) 904 { dchar d = aa[--i]; 905 wchar w; 906 907 if (d <= 0xFFFF) 908 w = cast(wchar) d; 909 else 910 { 911 w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800); 912 result = dg(&i, cast(void *)&w); 913 if (result) 914 break; 915 w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00); 916 } 917 result = dg(&i, cast(void *)&w); 918 if (result) 919 break; 920 } 921 return result; 922 } 923 924 unittest 925 { 926 debug(apply) printf("_aApplyRdw2.unittest\n"); 927 928 auto s = "hello"d[]; 929 int i; 930 931 foreach_reverse (k, wchar d; s) 932 { 933 //printf("i = %d, k = %d, d = %x\n", i, k, d); 934 assert(k == 4 - i); 935 switch (i) 936 { 937 case 0: assert(d == 'o'); break; 938 case 1: assert(d == 'l'); break; 939 case 2: assert(d == 'l'); break; 940 case 3: assert(d == 'e'); break; 941 case 4: assert(d == 'h'); break; 942 default: assert(0); 943 } 944 i++; 945 } 946 assert(i == 5); 947 948 s = "a\u1234\U000A0456b"; 949 i = 0; 950 foreach_reverse (k, wchar d; s) 951 { 952 //printf("i = %d, k = %d, d = %x\n", i, k, d); 953 switch (i) 954 { 955 case 0: assert(k == 3); assert(d == 'b'); break; 956 case 1: assert(k == 2); assert(d == 0xDA41); break; 957 case 2: assert(k == 2); assert(d == 0xDC56); break; 958 case 3: assert(k == 1); assert(d == 0x1234); break; 959 case 4: assert(k == 0); assert(d == 'a'); break; 960 default: assert(0); 961 } 962 i++; 963 } 964 assert(i == 5); 965 }