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 -- 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             .lhs_flags = XPI_OPERAND_TERM_LIST|XPI_OPERAND_ONLY_LOOK,
70             .rhs_flags = XPI_OPERAND_TERM_LIST|XPI_OPERAND_ONLY_LOOK,
71             .permit_hintkey = "Syntax::Operator::Zip/Z",
72             .cls = 0,
73              
74             .wrapper_func_name = "Syntax::Operator::Zip::zip",
75              
76             .ppaddr = &pp_zip,
77             };
78              
79 1           static OP *pp_mesh(pTHX)
80             {
81 1           dSP;
82 1           U32 rhs_mark = POPMARK;
83 1           U32 lhs_mark = POPMARK;
84              
85 1           U32 rhs_count = SP - (PL_stack_base + rhs_mark);
86 1           U32 lhs_count = rhs_mark - lhs_mark;
87              
88             int count = 0;
89 1 50         if(lhs_count > count)
90 1           count = lhs_count;
91 1 50         if(rhs_count > count)
92 0           count = rhs_count;
93              
94 1           SP = PL_stack_base + lhs_mark;
95              
96 1 50         if(GIMME_V == G_VOID)
    50          
97 0           return NORMAL;
98 1 50         if(GIMME_V == G_SCALAR) {
    50          
99 0 0         EXTEND(SP, 1);
100 0           mPUSHi(count * 2);
101 0           RETURN;
102             }
103              
104             /* known G_LIST */
105 1 50         EXTEND(SP, count * 2);
    50          
106 1 50         PUSHMARK(SP);
107              
108 1           SV **lhs = PL_stack_base + lhs_mark + 1;
109 1           SV **rhs = PL_stack_base + rhs_mark + 1;
110              
111             /* We can't easily do this inplace so we'll have to store the LHS values
112             * in a temporary array
113             */
114 1           AV *tmpav = newAV();
115 1           SAVEFREESV(tmpav);
116 1           av_extend(tmpav, lhs_count - 1);
117              
118 1 50         Copy(lhs, AvARRAY(tmpav), lhs_count, SV *);
119              
120 1           lhs = AvARRAY(tmpav);
121              
122             /* If the LHS list was too small, we'll have to move up the RHS list so we
123             * don't trash it too early
124             */
125 1 50         if(lhs_count < rhs_count) {
126 0           U32 offset = rhs_count - lhs_count;
127 0 0         Move(rhs, rhs + offset, rhs_count, SV *);
128             rhs += offset;
129             }
130              
131 1           SV **lhs_stop = lhs + lhs_count;
132 1           SV **rhs_stop = rhs + rhs_count;
133              
134 4 100         while(lhs < lhs_stop || rhs < rhs_stop) {
135 3 50         if(lhs < lhs_stop)
136 3           mPUSHs(newSVsv(*lhs++));
137             else
138 0           PUSHs(&PL_sv_undef);
139              
140 3 50         if(rhs < rhs_stop)
141 3           mPUSHs(newSVsv(*rhs++));
142             else
143 3           PUSHs(&PL_sv_undef);
144             }
145              
146 1           RETURN;
147             }
148              
149             struct XSParseInfixHooks infix_mesh = {
150             .lhs_flags = XPI_OPERAND_TERM_LIST|XPI_OPERAND_ONLY_LOOK,
151             .rhs_flags = XPI_OPERAND_TERM_LIST|XPI_OPERAND_ONLY_LOOK,
152             .permit_hintkey = "Syntax::Operator::Zip/Z",
153             .cls = 0,
154              
155             .wrapper_func_name = "Syntax::Operator::Zip::mesh",
156              
157             .ppaddr = &pp_mesh,
158             };
159              
160             MODULE = Syntax::Operator::Zip PACKAGE = Syntax::Operator::Zip
161              
162             BOOT:
163 4           boot_xs_parse_infix(0.18);
164              
165             register_xs_parse_infix("Z", &infix_zip, NULL);
166             register_xs_parse_infix("M", &infix_mesh, NULL);