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