2 * This code handles decoding UTF strings for `foreach_reverse` loops.
4 * Copyright: Copyright Digital Mars 2004 - 2010.
5 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6 * Authors: Walter Bright, Sean Kelly
7 * Source: $(DRUNTIMESRC rt/_aApplyR.d)
11 import core
.internal
.utf
;
13 /**********************************************/
14 /* 1 argument versions */
16 // Note: dg is extern(D), but _aApplyRcd() is extern(C)
19 Delegate type corresponding to transformed loop body
21 The parameter is a pointer to the current `char`, `wchar` or `dchar`
23 Returns: non-zero when a `break` statement is hit
25 extern (D
) alias dg_t
= int delegate(void* c
);
28 Same as `_aApplyXXX` functions, but for `foreach_reverse`
32 dg = foreach body transformed into a delegate, similar to `opApply`
35 non-zero when the loop was exited through a `break`
37 extern (C
) int _aApplyRcd1(scope const(char)[] aa
, dg_t dg
)
40 debug(apply
) printf("_aApplyRcd1(), len = %d\n", aa
.length
);
41 for (size_t i
= aa
.length
; i
!= 0; )
47 { char c
= cast(char)d
;
51 while ((c
& 0xC0) != 0xC0)
53 onUnicodeError("Invalid UTF-8 sequence", 0);
62 result
= dg(cast(void *)&d
);
71 debug(apply
) printf("_aApplyRcd1.unittest\n");
76 foreach_reverse (dchar d
; s
)
80 case 0: assert(d
== 'o'); break;
81 case 1: assert(d
== 'l'); break;
82 case 2: assert(d
== 'l'); break;
83 case 3: assert(d
== 'e'); break;
84 case 4: assert(d
== 'h'); break;
91 s
= "a\u1234\U000A0456b";
93 foreach_reverse (dchar d
; s
)
95 //printf("i = %d, d = %x\n", i, d);
98 case 0: assert(d
== 'b'); break;
99 case 1: assert(d
== '\U000A0456'); break;
100 case 2: assert(d
== '\u1234'); break;
101 case 3: assert(d
== 'a'); break;
110 extern (C
) int _aApplyRwd1(scope const(wchar)[] aa
, dg_t dg
)
113 debug(apply
) printf("_aApplyRwd1(), len = %d\n", aa
.length
);
114 for (size_t i
= aa
.length
; i
!= 0; )
119 if (d
>= 0xDC00 && d
<= 0xDFFF)
121 onUnicodeError("Invalid UTF-16 sequence", 0);
123 d
= ((aa
[i
] - 0xD7C0) << 10) + (d
- 0xDC00);
125 result
= dg(cast(void *)&d
);
134 debug(apply
) printf("_aApplyRwd1.unittest\n");
139 foreach_reverse (dchar d
; s
)
143 case 0: assert(d
== 'o'); break;
144 case 1: assert(d
== 'l'); break;
145 case 2: assert(d
== 'l'); break;
146 case 3: assert(d
== 'e'); break;
147 case 4: assert(d
== 'h'); break;
154 s
= "a\u1234\U000A0456b";
156 foreach_reverse (dchar d
; s
)
158 //printf("i = %d, d = %x\n", i, d);
161 case 0: assert(d
== 'b'); break;
162 case 1: assert(d
== '\U000A0456'); break;
163 case 2: assert(d
== '\u1234'); break;
164 case 3: assert(d
== 'a'); break;
173 extern (C
) int _aApplyRcw1(scope const(char)[] aa
, dg_t dg
)
176 debug(apply
) printf("_aApplyRcw1(), len = %d\n", aa
.length
);
177 for (size_t i
= aa
.length
; i
!= 0; )
184 { char c
= cast(char)w
;
188 while ((c
& 0xC0) != 0xC0)
190 onUnicodeError("Invalid UTF-8 sequence", 0);
192 d |
= (c
& 0x3F) << j
;
203 w
= cast(wchar) ((((d
- 0x10000) >> 10) & 0x3FF) + 0xD800);
204 result
= dg(cast(void *)&w
);
207 w
= cast(wchar) (((d
- 0x10000) & 0x3FF) + 0xDC00);
210 result
= dg(cast(void *)&w
);
219 debug(apply
) printf("_aApplyRcw1.unittest\n");
224 foreach_reverse (wchar d
; s
)
228 case 0: assert(d
== 'o'); break;
229 case 1: assert(d
== 'l'); break;
230 case 2: assert(d
== 'l'); break;
231 case 3: assert(d
== 'e'); break;
232 case 4: assert(d
== 'h'); break;
239 s
= "a\u1234\U000A0456b";
241 foreach_reverse (wchar d
; s
)
243 //printf("i = %d, d = %x\n", i, d);
246 case 0: assert(d
== 'b'); break;
247 case 1: assert(d
== 0xDA41); break;
248 case 2: assert(d
== 0xDC56); break;
249 case 3: assert(d
== 0x1234); break;
250 case 4: assert(d
== 'a'); break;
259 extern (C
) int _aApplyRwc1(scope const(wchar)[] aa
, dg_t dg
)
262 debug(apply
) printf("_aApplyRwc1(), len = %d\n", aa
.length
);
263 for (size_t i
= aa
.length
; i
!= 0; )
269 if (d
>= 0xDC00 && d
<= 0xDFFF)
271 onUnicodeError("Invalid UTF-16 sequence", 0);
273 d
= ((aa
[i
] - 0xD7C0) << 10) + (d
- 0xDC00);
280 auto b
= toUTF8(buf
, d
);
283 result
= dg(cast(void *)&c2
);
290 result
= dg(cast(void *)&c
);
299 debug(apply
) printf("_aApplyRwc1.unittest\n");
304 foreach_reverse (char d
; s
)
308 case 0: assert(d
== 'o'); break;
309 case 1: assert(d
== 'l'); break;
310 case 2: assert(d
== 'l'); break;
311 case 3: assert(d
== 'e'); break;
312 case 4: assert(d
== 'h'); break;
319 s
= "a\u1234\U000A0456b";
321 foreach_reverse (char d
; s
)
323 //printf("i = %d, d = %x\n", i, d);
326 case 0: assert(d
== 'b'); break;
327 case 1: assert(d
== 0xF2); break;
328 case 2: assert(d
== 0xA0); break;
329 case 3: assert(d
== 0x91); break;
330 case 4: assert(d
== 0x96); break;
331 case 5: assert(d
== 0xE1); break;
332 case 6: assert(d
== 0x88); break;
333 case 7: assert(d
== 0xB4); break;
334 case 8: assert(d
== 'a'); break;
343 extern (C
) int _aApplyRdc1(scope const(dchar)[] aa
, dg_t dg
)
346 debug(apply
) printf("_aApplyRdc1(), len = %d\n", aa
.length
);
347 for (size_t i
= aa
.length
; i
!= 0;)
355 auto b
= toUTF8(buf
, d
);
358 result
= dg(cast(void *)&c2
);
368 result
= dg(cast(void *)&c
);
377 debug(apply
) printf("_aApplyRdc1.unittest\n");
382 foreach_reverse (char d
; s
)
386 case 0: assert(d
== 'o'); break;
387 case 1: assert(d
== 'l'); break;
388 case 2: assert(d
== 'l'); break;
389 case 3: assert(d
== 'e'); break;
390 case 4: assert(d
== 'h'); break;
397 s
= "a\u1234\U000A0456b";
399 foreach_reverse (char d
; s
)
401 //printf("i = %d, d = %x\n", i, d);
404 case 0: assert(d
== 'b'); break;
405 case 1: assert(d
== 0xF2); break;
406 case 2: assert(d
== 0xA0); break;
407 case 3: assert(d
== 0x91); break;
408 case 4: assert(d
== 0x96); break;
409 case 5: assert(d
== 0xE1); break;
410 case 6: assert(d
== 0x88); break;
411 case 7: assert(d
== 0xB4); break;
412 case 8: assert(d
== 'a'); break;
421 extern (C
) int _aApplyRdw1(scope const(dchar)[] aa
, dg_t dg
)
424 debug(apply
) printf("_aApplyRdw1(), len = %d\n", aa
.length
);
425 for (size_t i
= aa
.length
; i
!= 0; )
433 w
= cast(wchar) ((((d
- 0x10000) >> 10) & 0x3FF) + 0xD800);
434 result
= dg(cast(void *)&w
);
437 w
= cast(wchar) (((d
- 0x10000) & 0x3FF) + 0xDC00);
439 result
= dg(cast(void *)&w
);
448 debug(apply
) printf("_aApplyRdw1.unittest\n");
453 foreach_reverse (wchar d
; s
)
457 case 0: assert(d
== 'o'); break;
458 case 1: assert(d
== 'l'); break;
459 case 2: assert(d
== 'l'); break;
460 case 3: assert(d
== 'e'); break;
461 case 4: assert(d
== 'h'); break;
468 s
= "a\u1234\U000A0456b";
470 foreach_reverse (wchar d
; s
)
472 //printf("i = %d, d = %x\n", i, d);
475 case 0: assert(d
== 'b'); break;
476 case 1: assert(d
== 0xDA41); break;
477 case 2: assert(d
== 0xDC56); break;
478 case 3: assert(d
== 0x1234); break;
479 case 4: assert(d
== 'a'); break;
488 /****************************************************************************/
489 /* 2 argument versions */
492 Delegate type corresponding to transformed loop body
494 Parameters are pointers to a `size_t` loop index, and the current `char`, `wchar` or `dchar`.
496 Returns: non-zero when a `break` statement is hit
498 extern (D
) alias dg2_t
= int delegate(void* i
, void* c
);
500 // Note: dg is extern(D), but _aApplyRcd2() is extern(C)
503 Variants of _aApplyRXXX that include a loop index.
505 extern (C
) int _aApplyRcd2(scope const(char)[] aa
, dg2_t dg
)
508 size_t len
= aa
.length
;
510 debug(apply
) printf("_aApplyRcd2(), len = %d\n", len
);
511 for (i
= len
; i
!= 0; )
517 { char c
= cast(char)d
;
521 while ((c
& 0xC0) != 0xC0)
523 onUnicodeError("Invalid UTF-8 sequence", 0);
525 d |
= (c
& 0x3F) << j
;
532 result
= dg(&i
, cast(void *)&d
);
541 debug(apply
) printf("_aApplyRcd2.unittest\n");
546 foreach_reverse (k
, dchar d
; s
)
551 case 0: assert(d
== 'o'); break;
552 case 1: assert(d
== 'l'); break;
553 case 2: assert(d
== 'l'); break;
554 case 3: assert(d
== 'e'); break;
555 case 4: assert(d
== 'h'); break;
562 s
= "a\u1234\U000A0456b";
564 foreach_reverse (k
, dchar d
; s
)
566 //printf("i = %d, k = %d, d = %x\n", i, k, d);
569 case 0: assert(d
== 'b'); assert(k
== 8); break;
570 case 1: assert(d
== '\U000A0456'); assert(k
== 4); break;
571 case 2: assert(d
== '\u1234'); assert(k
== 1); break;
572 case 3: assert(d
== 'a'); assert(k
== 0); break;
581 extern (C
) int _aApplyRwd2(scope const(wchar)[] aa
, dg2_t dg
)
584 debug(apply
) printf("_aApplyRwd2(), len = %d\n", aa
.length
);
585 for (size_t i
= aa
.length
; i
!= 0; )
590 if (d
>= 0xDC00 && d
<= 0xDFFF)
592 onUnicodeError("Invalid UTF-16 sequence", 0);
594 d
= ((aa
[i
] - 0xD7C0) << 10) + (d
- 0xDC00);
596 result
= dg(&i
, cast(void *)&d
);
605 debug(apply
) printf("_aApplyRwd2.unittest\n");
610 foreach_reverse (k
, dchar d
; s
)
612 //printf("i = %d, k = %d, d = %x\n", i, k, d);
616 case 0: assert(d
== 'o'); break;
617 case 1: assert(d
== 'l'); break;
618 case 2: assert(d
== 'l'); break;
619 case 3: assert(d
== 'e'); break;
620 case 4: assert(d
== 'h'); break;
627 s
= "a\u1234\U000A0456b";
629 foreach_reverse (k
, dchar d
; s
)
631 //printf("i = %d, k = %d, d = %x\n", i, k, d);
634 case 0: assert(k
== 4); assert(d
== 'b'); break;
635 case 1: assert(k
== 2); assert(d
== '\U000A0456'); break;
636 case 2: assert(k
== 1); assert(d
== '\u1234'); break;
637 case 3: assert(k
== 0); assert(d
== 'a'); break;
646 extern (C
) int _aApplyRcw2(scope const(char)[] aa
, dg2_t dg
)
649 debug(apply
) printf("_aApplyRcw2(), len = %d\n", aa
.length
);
650 for (size_t i
= aa
.length
; i
!= 0; )
657 { char c
= cast(char)w
;
661 while ((c
& 0xC0) != 0xC0)
663 onUnicodeError("Invalid UTF-8 sequence", 0);
665 d |
= (c
& 0x3F) << j
;
676 w
= cast(wchar) ((((d
- 0x10000) >> 10) & 0x3FF) + 0xD800);
677 result
= dg(&i
, cast(void *)&w
);
680 w
= cast(wchar) (((d
- 0x10000) & 0x3FF) + 0xDC00);
683 result
= dg(&i
, cast(void *)&w
);
692 debug(apply
) printf("_aApplyRcw2.unittest\n");
697 foreach_reverse (k
, wchar d
; s
)
699 //printf("i = %d, k = %d, d = %x\n", i, k, d);
703 case 0: assert(d
== 'o'); break;
704 case 1: assert(d
== 'l'); break;
705 case 2: assert(d
== 'l'); break;
706 case 3: assert(d
== 'e'); break;
707 case 4: assert(d
== 'h'); break;
714 s
= "a\u1234\U000A0456b";
716 foreach_reverse (k
, wchar d
; s
)
718 //printf("i = %d, k = %d, d = %x\n", i, k, d);
721 case 0: assert(k
== 8); assert(d
== 'b'); break;
722 case 1: assert(k
== 4); assert(d
== 0xDA41); break;
723 case 2: assert(k
== 4); assert(d
== 0xDC56); break;
724 case 3: assert(k
== 1); assert(d
== 0x1234); break;
725 case 4: assert(k
== 0); assert(d
== 'a'); break;
734 extern (C
) int _aApplyRwc2(scope const(wchar)[] aa
, dg2_t dg
)
737 debug(apply
) printf("_aApplyRwc2(), len = %d\n", aa
.length
);
738 for (size_t i
= aa
.length
; i
!= 0; )
744 if (d
>= 0xDC00 && d
<= 0xDFFF)
746 onUnicodeError("Invalid UTF-16 sequence", 0);
748 d
= ((aa
[i
] - 0xD7C0) << 10) + (d
- 0xDC00);
755 auto b
= toUTF8(buf
, d
);
758 result
= dg(&i
, cast(void *)&c2
);
765 result
= dg(&i
, cast(void *)&c
);
774 debug(apply
) printf("_aApplyRwc2.unittest\n");
779 foreach_reverse (k
, char d
; s
)
781 //printf("i = %d, k = %d, d = %x\n", i, k, d);
785 case 0: assert(d
== 'o'); break;
786 case 1: assert(d
== 'l'); break;
787 case 2: assert(d
== 'l'); break;
788 case 3: assert(d
== 'e'); break;
789 case 4: assert(d
== 'h'); break;
796 s
= "a\u1234\U000A0456b";
798 foreach_reverse (k
, char d
; s
)
800 //printf("i = %d, k = %d, d = %x\n", i, k, d);
803 case 0: assert(k
== 4); assert(d
== 'b'); break;
804 case 1: assert(k
== 2); assert(d
== 0xF2); break;
805 case 2: assert(k
== 2); assert(d
== 0xA0); break;
806 case 3: assert(k
== 2); assert(d
== 0x91); break;
807 case 4: assert(k
== 2); assert(d
== 0x96); break;
808 case 5: assert(k
== 1); assert(d
== 0xE1); break;
809 case 6: assert(k
== 1); assert(d
== 0x88); break;
810 case 7: assert(k
== 1); assert(d
== 0xB4); break;
811 case 8: assert(k
== 0); assert(d
== 'a'); break;
820 extern (C
) int _aApplyRdc2(scope const(dchar)[] aa
, dg2_t dg
)
823 debug(apply
) printf("_aApplyRdc2(), len = %d\n", aa
.length
);
824 for (size_t i
= aa
.length
; i
!= 0; )
832 auto b
= toUTF8(buf
, d
);
835 result
= dg(&i
, cast(void *)&c2
);
844 result
= dg(&i
, cast(void *)&c
);
853 debug(apply
) printf("_aApplyRdc2.unittest\n");
858 foreach_reverse (k
, char d
; s
)
860 //printf("i = %d, k = %d, d = %x\n", i, k, d);
864 case 0: assert(d
== 'o'); break;
865 case 1: assert(d
== 'l'); break;
866 case 2: assert(d
== 'l'); break;
867 case 3: assert(d
== 'e'); break;
868 case 4: assert(d
== 'h'); break;
875 s
= "a\u1234\U000A0456b";
877 foreach_reverse (k
, char d
; s
)
879 //printf("i = %d, k = %d, d = %x\n", i, k, d);
882 case 0: assert(k
== 3); assert(d
== 'b'); break;
883 case 1: assert(k
== 2); assert(d
== 0xF2); break;
884 case 2: assert(k
== 2); assert(d
== 0xA0); break;
885 case 3: assert(k
== 2); assert(d
== 0x91); break;
886 case 4: assert(k
== 2); assert(d
== 0x96); break;
887 case 5: assert(k
== 1); assert(d
== 0xE1); break;
888 case 6: assert(k
== 1); assert(d
== 0x88); break;
889 case 7: assert(k
== 1); assert(d
== 0xB4); break;
890 case 8: assert(k
== 0); assert(d
== 'a'); break;
899 extern (C
) int _aApplyRdw2(scope const(dchar)[] aa
, dg2_t dg
)
902 debug(apply
) printf("_aApplyRdw2(), len = %d\n", aa
.length
);
903 for (size_t i
= aa
.length
; i
!= 0; )
911 w
= cast(wchar) ((((d
- 0x10000) >> 10) & 0x3FF) + 0xD800);
912 result
= dg(&i
, cast(void *)&w
);
915 w
= cast(wchar) (((d
- 0x10000) & 0x3FF) + 0xDC00);
917 result
= dg(&i
, cast(void *)&w
);
926 debug(apply
) printf("_aApplyRdw2.unittest\n");
931 foreach_reverse (k
, wchar d
; s
)
933 //printf("i = %d, k = %d, d = %x\n", i, k, d);
937 case 0: assert(d
== 'o'); break;
938 case 1: assert(d
== 'l'); break;
939 case 2: assert(d
== 'l'); break;
940 case 3: assert(d
== 'e'); break;
941 case 4: assert(d
== 'h'); break;
948 s
= "a\u1234\U000A0456b";
950 foreach_reverse (k
, wchar d
; s
)
952 //printf("i = %d, k = %d, d = %x\n", i, k, d);
955 case 0: assert(k
== 3); assert(d
== 'b'); break;
956 case 1: assert(k
== 2); assert(d
== 0xDA41); break;
957 case 2: assert(k
== 2); assert(d
== 0xDC56); break;
958 case 3: assert(k
== 1); assert(d
== 0x1234); break;
959 case 4: assert(k
== 0); assert(d
== 'a'); break;