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