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 
_aApplyRcd1(in char[]aa,dg_t dg)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 
foreach_reverse(dchar d;s)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;
foreach_reverse(dchar d;s)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 
_aApplyRwd1(in wchar[]aa,dg_t dg)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 
foreach_reverse(dchar d;s)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;
foreach_reverse(dchar d;s)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 
_aApplyRcw1(in char[]aa,dg_t dg)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 
foreach_reverse(wchar d;s)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;
foreach_reverse(wchar d;s)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 
_aApplyRwc1(in wchar[]aa,dg_t dg)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 
foreach_reverse(char d;s)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;
foreach_reverse(char d;s)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 
_aApplyRdc1(in dchar[]aa,dg_t dg)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 
foreach_reverse(char d;s)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;
foreach_reverse(char d;s)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 
_aApplyRdw1(in dchar[]aa,dg_t dg)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 
foreach_reverse(wchar d;s)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;
foreach_reverse(wchar d;s)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 
_aApplyRcd2(in char[]aa,dg2_t dg)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 
foreach_reverse(k,dchar d;s)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;
foreach_reverse(k,dchar d;s)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 
_aApplyRwd2(in wchar[]aa,dg2_t dg)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 
foreach_reverse(k,dchar d;s)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;
foreach_reverse(k,dchar d;s)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 
_aApplyRcw2(in char[]aa,dg2_t dg)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 
foreach_reverse(k,wchar d;s)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;
foreach_reverse(k,wchar d;s)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 
_aApplyRwc2(in wchar[]aa,dg2_t dg)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 
foreach_reverse(k,char d;s)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;
foreach_reverse(k,char d;s)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 
_aApplyRdc2(in dchar[]aa,dg2_t dg)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 
foreach_reverse(k,char d;s)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;
foreach_reverse(k,char d;s)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 
_aApplyRdw2(in dchar[]aa,dg2_t dg)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 
foreach_reverse(k,wchar d;s)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;
foreach_reverse(k,wchar d;s)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