Home | History | Annotate | Line # | Download | only in rt
aApplyR.d revision 1.1.1.2
      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