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