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