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