File Coverage

lib/Syntax/Operator/Zip.xs
Criterion Covered Total %
statement 54 72 75.0
branch 24 54 44.4
condition n/a
subroutine n/a
pod n/a
total 78 126 61.9


line stmt bran cond sub pod time code
1             /* You may distribute under the terms of either the GNU General Public License
2             * or the Artistic License (the same terms as Perl itself)
3             *
4             * (C) Paul Evans, 2021-2022 -- leonerd@leonerd.org.uk
5             */
6             #include "EXTERN.h"
7             #include "perl.h"
8             #include "XSUB.h"
9              
10             #define HAVE_PERL_VERSION(R, V, S) \
11             (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S))))))
12              
13             #include "XSParseInfix.h"
14              
15 1           static OP *pp_zip(pTHX)
16             {
17 1           dSP;
18 1           U32 rhs_mark = POPMARK;
19 1           U32 lhs_mark = POPMARK;
20              
21 1           U32 rhs_count = SP - (PL_stack_base + rhs_mark);
22 1           U32 lhs_count = rhs_mark - lhs_mark;
23              
24 1           SP = PL_stack_base + lhs_mark;
25              
26 1 50         if(GIMME_V == G_VOID)
    50          
27 0           return NORMAL;
28 1 50         if(GIMME_V == G_SCALAR) {
    50          
29             int count = 0;
30 0 0         if(lhs_count > count)
31 0           count = lhs_count;
32 0 0         if(rhs_count > count)
33 0           count = rhs_count;
34 0 0         EXTEND(SP, 1);
35 0           mPUSHi(count);
36 0           RETURN;
37             }
38              
39             /* known G_LIST */
40              
41             /* No need to EXTEND because we know the stack will be big enough */
42 1 50         PUSHMARK(SP);
43              
44 1           SV **lhs = PL_stack_base + lhs_mark + 1;
45 1           SV **rhs = PL_stack_base + rhs_mark + 1;
46 1           SV **lhs_stop = lhs + lhs_count;
47 1           SV **rhs_stop = rhs + rhs_count;
48              
49 4 100         while(lhs < lhs_stop || rhs < rhs_stop) {
50 3           AV *av = newAV();
51              
52 3 50         if(lhs < lhs_stop)
53 3           av_push(av, newSVsv(*lhs++));
54             else
55 0           av_push(av, &PL_sv_undef);
56              
57 3 50         if(rhs < rhs_stop)
58 3           av_push(av, newSVsv(*rhs++));
59             else
60 0           av_push(av, &PL_sv_undef);
61              
62 3           mPUSHs(newRV_noinc((SV *)av));
63             }
64              
65 1           RETURN;
66             }
67              
68             struct XSParseInfixHooks infix_zip = {
69             /* Parse this at ADD precedence, so that (LIST)xCOUNT can be used on RHS */
70             .cls = XPI_CLS_ADD_MISC,
71             .lhs_flags = XPI_OPERAND_TERM_LIST|XPI_OPERAND_ONLY_LOOK,
72             .rhs_flags = XPI_OPERAND_TERM_LIST|XPI_OPERAND_ONLY_LOOK,
73             .permit_hintkey = "Syntax::Operator::Zip/Z",
74              
75             .wrapper_func_name = "Syntax::Operator::Zip::zip",
76              
77             .ppaddr = &pp_zip,
78             };
79              
80 1           static OP *pp_mesh(pTHX)
81             {
82 1           dSP;
83 1           U32 rhs_mark = POPMARK;
84 1           U32 lhs_mark = POPMARK;
85              
86 1           U32 rhs_count = SP - (PL_stack_base + rhs_mark);
87 1           U32 lhs_count = rhs_mark - lhs_mark;
88              
89             int count = 0;
90 1 50         if(lhs_count > count)
91 1           count = lhs_count;
92 1 50         if(rhs_count > count)
93 0           count = rhs_count;
94              
95 1           SP = PL_stack_base + lhs_mark;
96              
97 1 50         if(GIMME_V == G_VOID)
    50          
98 0           return NORMAL;
99 1 50         if(GIMME_V == G_SCALAR) {
    50          
100 0 0         EXTEND(SP, 1);
101 0           mPUSHi(count * 2);
102 0           RETURN;
103             }
104              
105             /* known G_LIST */
106 1 50         EXTEND(SP, count * 2);
    50          
107 1 50         PUSHMARK(SP);
108              
109 1           SV **lhs = PL_stack_base + lhs_mark + 1;
110 1           SV **rhs = PL_stack_base + rhs_mark + 1;
111              
112             /* We can't easily do this inplace so we'll have to store the LHS values
113             * in a temporary array
114             */
115 1           AV *tmpav = newAV();
116 1           SAVEFREESV(tmpav);
117 1           av_extend(tmpav, lhs_count - 1);
118              
119 1 50         Copy(lhs, AvARRAY(tmpav), lhs_count, SV *);
120              
121 1           lhs = AvARRAY(tmpav);
122              
123             /* If the LHS list was too small, we'll have to move up the RHS list so we
124             * don't trash it too early
125             */
126 1 50         if(lhs_count < rhs_count) {
127 0           U32 offset = rhs_count - lhs_count;
128 0 0         Move(rhs, rhs + offset, rhs_count, SV *);
129             rhs += offset;
130             }
131              
132 1           SV **lhs_stop = lhs + lhs_count;
133 1           SV **rhs_stop = rhs + rhs_count;
134              
135 4 100         while(lhs < lhs_stop || rhs < rhs_stop) {
136 3 50         if(lhs < lhs_stop)
137 3           mPUSHs(newSVsv(*lhs++));
138             else
139 0           PUSHs(&PL_sv_undef);
140              
141 3 50         if(rhs < rhs_stop)
142 3           mPUSHs(newSVsv(*rhs++));
143             else
144 3           PUSHs(&PL_sv_undef);
145             }
146              
147 1           RETURN;
148             }
149              
150             struct XSParseInfixHooks infix_mesh = {
151             .cls = XPI_CLS_ADD_MISC,
152             .lhs_flags = XPI_OPERAND_TERM_LIST|XPI_OPERAND_ONLY_LOOK,
153             .rhs_flags = XPI_OPERAND_TERM_LIST|XPI_OPERAND_ONLY_LOOK,
154             .permit_hintkey = "Syntax::Operator::Zip/M",
155              
156             .wrapper_func_name = "Syntax::Operator::Zip::mesh",
157              
158             .ppaddr = &pp_mesh,
159             };
160              
161             MODULE = Syntax::Operator::Zip PACKAGE = Syntax::Operator::Zip
162              
163             BOOT:
164 4           boot_xs_parse_infix(0.26);
165              
166             register_xs_parse_infix("Z", &infix_zip, NULL);
167             register_xs_parse_infix("M", &infix_mesh, NULL);