| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#ifndef __PDLPERL_H |
|
2
|
|
|
|
|
|
|
#define __PDLPERL_H |
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
#define PDL_XS_PREAMBLE(nret) \ |
|
5
|
|
|
|
|
|
|
char *objname = "PDL"; /* XXX maybe that class should actually depend on the value set \ |
|
6
|
|
|
|
|
|
|
by pp_bless ? (CS) */ \ |
|
7
|
|
|
|
|
|
|
HV *bless_stash = 0; \ |
|
8
|
|
|
|
|
|
|
SV *parent = 0; \ |
|
9
|
|
|
|
|
|
|
int nreturn = (nret); \ |
|
10
|
|
|
|
|
|
|
(void)nreturn; \ |
|
11
|
|
|
|
|
|
|
/* Check if you can get a package name for this input value. */ \ |
|
12
|
|
|
|
|
|
|
/* It can be either a PDL (SVt_PVMG) or a hash which is a */ \ |
|
13
|
|
|
|
|
|
|
/* derived PDL subclass (SVt_PVHV) */ \ |
|
14
|
|
|
|
|
|
|
do { \ |
|
15
|
|
|
|
|
|
|
if (SvROK(ST(0)) && ((SvTYPE(SvRV(ST(0))) == SVt_PVMG) || (SvTYPE(SvRV(ST(0))) == SVt_PVHV))) { \ |
|
16
|
|
|
|
|
|
|
parent = ST(0); \ |
|
17
|
|
|
|
|
|
|
if (sv_isobject(parent)){ \ |
|
18
|
|
|
|
|
|
|
bless_stash = SvSTASH(SvRV(parent)); \ |
|
19
|
|
|
|
|
|
|
objname = HvNAME((bless_stash)); /* The package to bless output vars into is taken from the first input var */ \ |
|
20
|
|
|
|
|
|
|
} \ |
|
21
|
|
|
|
|
|
|
} \ |
|
22
|
|
|
|
|
|
|
} while (0) |
|
23
|
|
|
|
|
|
|
|
|
24
|
13
|
|
|
|
|
|
static inline pdl *PDL_XS_pdlinit(pTHX_ char *objname, HV *bless_stash, SV *to_push, char *method, SV **svp, Core *core) { |
|
25
|
13
|
|
|
|
|
|
dSP; |
|
26
|
|
|
|
|
|
|
pdl *ret; |
|
27
|
13
|
50
|
|
|
|
|
if (strcmp(objname,"PDL") == 0) { /* shortcut if just PDL */ |
|
28
|
13
|
|
|
|
|
|
ret = core->pdlnew(); |
|
29
|
13
|
50
|
|
|
|
|
if (!ret) core->pdl_barf("Error making null pdl"); |
|
30
|
13
|
50
|
|
|
|
|
if (svp) { |
|
31
|
13
|
|
|
|
|
|
*svp = sv_newmortal(); |
|
32
|
13
|
|
|
|
|
|
core->SetSV_PDL(*svp, ret); |
|
33
|
13
|
50
|
|
|
|
|
if (bless_stash) *svp = sv_bless(*svp, bless_stash); |
|
34
|
|
|
|
|
|
|
} |
|
35
|
|
|
|
|
|
|
} else { |
|
36
|
0
|
0
|
|
|
|
|
PUSHMARK(SP); |
|
37
|
0
|
0
|
|
|
|
|
XPUSHs(to_push); |
|
38
|
0
|
|
|
|
|
|
PUTBACK; |
|
39
|
0
|
|
|
|
|
|
perl_call_method(method, G_SCALAR); |
|
40
|
0
|
|
|
|
|
|
SPAGAIN; |
|
41
|
0
|
|
|
|
|
|
SV *sv = POPs; |
|
42
|
0
|
|
|
|
|
|
PUTBACK; |
|
43
|
0
|
|
|
|
|
|
ret = core->SvPDLV(sv); |
|
44
|
0
|
0
|
|
|
|
|
if (svp) *svp = sv; |
|
45
|
|
|
|
|
|
|
} |
|
46
|
13
|
|
|
|
|
|
return ret; |
|
47
|
|
|
|
|
|
|
} |
|
48
|
|
|
|
|
|
|
#define PDL_XS_PERLINIT_initsv(sv) \ |
|
49
|
|
|
|
|
|
|
PDL_XS_pdlinit(aTHX_ objname, bless_stash, parent ? parent : sv_2mortal(newSVpv(objname, 0)), "initialize", &sv, PDL) |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
#define PDL_XS_RETURN(clause1) \ |
|
52
|
|
|
|
|
|
|
if (nreturn) { \ |
|
53
|
|
|
|
|
|
|
if (nreturn > 0) EXTEND (SP, nreturn); \ |
|
54
|
|
|
|
|
|
|
clause1; \ |
|
55
|
|
|
|
|
|
|
XSRETURN(nreturn); \ |
|
56
|
|
|
|
|
|
|
} else { \ |
|
57
|
|
|
|
|
|
|
if (GIMME_V == G_SCALAR) XSRETURN_UNDEF; /* GH#551 */ \ |
|
58
|
|
|
|
|
|
|
else XSRETURN(0); \ |
|
59
|
|
|
|
|
|
|
} |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
#define PDL_IS_INPLACE(in) ((in)->state & PDL_INPLACE) |
|
62
|
|
|
|
|
|
|
#define PDL_XS_INPLACE(in, out) \ |
|
63
|
|
|
|
|
|
|
if (PDL_IS_INPLACE(in)) { \ |
|
64
|
|
|
|
|
|
|
if (out ## _SV) barf("inplace input but different output given"); \ |
|
65
|
|
|
|
|
|
|
out ## _SV = sv_newmortal(); \ |
|
66
|
|
|
|
|
|
|
in->state &= ~PDL_INPLACE; \ |
|
67
|
|
|
|
|
|
|
out = in; \ |
|
68
|
|
|
|
|
|
|
PDL->SetSV_PDL(out ## _SV,out); \ |
|
69
|
|
|
|
|
|
|
} else \ |
|
70
|
|
|
|
|
|
|
out = out ## _SV ? PDL_CORE_(SvPDLV)(out ## _SV) : \ |
|
71
|
|
|
|
|
|
|
PDL_XS_PERLINIT_initsv(out ## _SV); |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
#define PDL_XS_SCALAR(thistype, ppsym, val) \ |
|
74
|
|
|
|
|
|
|
PDL_Anyval av = {PDL_CLD, {.H=0}}; /* guarantee all bits set */ \ |
|
75
|
|
|
|
|
|
|
av.type = thistype; av.value.ppsym=val; \ |
|
76
|
|
|
|
|
|
|
pdl *b = pdl_scalar(av); \ |
|
77
|
|
|
|
|
|
|
if (!b) XSRETURN_UNDEF; \ |
|
78
|
|
|
|
|
|
|
SV *b_SV = sv_newmortal(); \ |
|
79
|
|
|
|
|
|
|
pdl_SetSV_PDL(b_SV, b); \ |
|
80
|
|
|
|
|
|
|
EXTEND(SP, 1); \ |
|
81
|
|
|
|
|
|
|
ST(0) = b_SV; \ |
|
82
|
|
|
|
|
|
|
XSRETURN(1); |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
#define PDL_MAKE_PERL_COMPLEX(output,r,i) { \ |
|
85
|
|
|
|
|
|
|
dSP; NV rval = r, ival = i; \ |
|
86
|
|
|
|
|
|
|
perl_require_pv("PDL/Complex/Overloads.pm"); \ |
|
87
|
|
|
|
|
|
|
ENTER; SAVETMPS; \ |
|
88
|
|
|
|
|
|
|
PUSHMARK(SP); mXPUSHn(rval); mXPUSHn(ival); PUTBACK; \ |
|
89
|
|
|
|
|
|
|
int count = perl_call_pv("PDL::Complex::Overloads::cplx", G_SCALAR); \ |
|
90
|
|
|
|
|
|
|
SPAGAIN; \ |
|
91
|
|
|
|
|
|
|
if (count != 1) croak("Failed to create PDL::Complex::Overloads object (%.9" NVgf ", %.9" NVgf ")", rval, ival); \ |
|
92
|
|
|
|
|
|
|
sv_setsv(output, POPs); \ |
|
93
|
|
|
|
|
|
|
PUTBACK; \ |
|
94
|
|
|
|
|
|
|
FREETMPS; LEAVE; \ |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
/*************** |
|
98
|
|
|
|
|
|
|
* So many ways to be undefined... |
|
99
|
|
|
|
|
|
|
*/ |
|
100
|
|
|
|
|
|
|
#define PDL_SV_IS_UNDEF(sv) ( (!(sv) || ((sv)==&PL_sv_undef)) || !(SvNIOK(sv) || (SvTYPE(sv)==SVt_PVMG) || SvPOK(sv) || SvROK(sv))) |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
#define ANYVAL_FROM_SV(outany,insv,use_undefval,forced_type,warn_undef) do { \ |
|
103
|
|
|
|
|
|
|
SV *sv2 = insv; \ |
|
104
|
|
|
|
|
|
|
if (PDL_SV_IS_UNDEF(sv2)) { \ |
|
105
|
|
|
|
|
|
|
if (!use_undefval) { \ |
|
106
|
|
|
|
|
|
|
outany.type = forced_type >=0 ? forced_type : -1; \ |
|
107
|
|
|
|
|
|
|
outany.value.H = 0; \ |
|
108
|
|
|
|
|
|
|
break; \ |
|
109
|
|
|
|
|
|
|
} \ |
|
110
|
|
|
|
|
|
|
sv2 = get_sv("PDL::undefval",1); \ |
|
111
|
|
|
|
|
|
|
if ((warn_undef) && SvIV(get_sv("PDL::debug",1))) \ |
|
112
|
|
|
|
|
|
|
fprintf(stderr,"Warning: SvPDLV converted undef to $PDL::undefval (%"NVgf").\n",SvNV(sv2)); \ |
|
113
|
|
|
|
|
|
|
if (PDL_SV_IS_UNDEF(sv2)) { \ |
|
114
|
|
|
|
|
|
|
outany.type = forced_type >=0 ? forced_type : PDL_B; \ |
|
115
|
|
|
|
|
|
|
outany.value.H = 0; \ |
|
116
|
|
|
|
|
|
|
break; \ |
|
117
|
|
|
|
|
|
|
} \ |
|
118
|
|
|
|
|
|
|
} \ |
|
119
|
|
|
|
|
|
|
if (SvROK(sv2)) { \ |
|
120
|
|
|
|
|
|
|
if (sv_derived_from(sv2, "PDL")) { \ |
|
121
|
|
|
|
|
|
|
pdl *it = PDL_CORE_(SvPDLV)(sv2); \ |
|
122
|
|
|
|
|
|
|
outany.type = PDL_INVALID; \ |
|
123
|
|
|
|
|
|
|
if (it->nvals == 1) \ |
|
124
|
|
|
|
|
|
|
ANYVAL_FROM_CTYPE_OFFSET(outany, it->datatype, PDL_REPRP(it), PDL_REPROFFS(it)); \ |
|
125
|
|
|
|
|
|
|
if (outany.type < 0) PDL_CORE_(pdl_barf)("Position out of range"); \ |
|
126
|
|
|
|
|
|
|
break; \ |
|
127
|
|
|
|
|
|
|
} \ |
|
128
|
|
|
|
|
|
|
if (sv_derived_from(sv2, "Math::Complex")) { \ |
|
129
|
|
|
|
|
|
|
ANYVAL_FROM_MCOMPLEX(outany, sv2); \ |
|
130
|
|
|
|
|
|
|
break; \ |
|
131
|
|
|
|
|
|
|
} \ |
|
132
|
|
|
|
|
|
|
PDL_CORE_(pdl_barf)("Can't convert ref '%s' to Anyval", sv_reftype(SvRV(sv2), 1)); \ |
|
133
|
|
|
|
|
|
|
} else if (!SvIOK(sv2)) { /* Perl Double (e.g. 2.0) */ \ |
|
134
|
|
|
|
|
|
|
NV tmp_NV = SvNV(sv2); \ |
|
135
|
|
|
|
|
|
|
int datatype = forced_type >=0 ? forced_type : _pdl_whichdatatype_double(tmp_NV); \ |
|
136
|
|
|
|
|
|
|
ANYVAL_FROM_CTYPE(outany, datatype, tmp_NV); \ |
|
137
|
|
|
|
|
|
|
} else if (SvIsUV(sv2)) { /* Perl unsigned int */ \ |
|
138
|
|
|
|
|
|
|
UV tmp_UV = SvUV(sv2); \ |
|
139
|
|
|
|
|
|
|
int datatype = forced_type >=0 ? forced_type : _pdl_whichdatatype_uint(tmp_UV); \ |
|
140
|
|
|
|
|
|
|
ANYVAL_FROM_CTYPE(outany, datatype, tmp_UV); \ |
|
141
|
|
|
|
|
|
|
} else { /* Perl Int (e.g. 2) */ \ |
|
142
|
|
|
|
|
|
|
IV tmp_IV = SvIV(sv2); \ |
|
143
|
|
|
|
|
|
|
int datatype = forced_type >=0 ? forced_type : _pdl_whichdatatype_int(tmp_IV); \ |
|
144
|
|
|
|
|
|
|
ANYVAL_FROM_CTYPE(outany, datatype, tmp_IV); \ |
|
145
|
|
|
|
|
|
|
} \ |
|
146
|
|
|
|
|
|
|
} while (0) |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
/* only to CD, same as whichdatatype_double only D. only if know is M:C */ |
|
149
|
|
|
|
|
|
|
#define ANYVAL_FROM_MCOMPLEX(outany,insv) do { \ |
|
150
|
|
|
|
|
|
|
dSP; \ |
|
151
|
|
|
|
|
|
|
int i; \ |
|
152
|
|
|
|
|
|
|
double vals[2]; \ |
|
153
|
|
|
|
|
|
|
char *meths[] = { "Re", "Im" }; \ |
|
154
|
|
|
|
|
|
|
ENTER; SAVETMPS; \ |
|
155
|
|
|
|
|
|
|
for (i = 0; i < 2; i++) { \ |
|
156
|
|
|
|
|
|
|
PUSHMARK(SP); XPUSHs(insv); PUTBACK; \ |
|
157
|
|
|
|
|
|
|
int count = perl_call_method(meths[i], G_SCALAR); \ |
|
158
|
|
|
|
|
|
|
SPAGAIN; \ |
|
159
|
|
|
|
|
|
|
if (count != 1) PDL_CORE_(pdl_barf)("Failed Math::Complex method '%s'", meths[i]); \ |
|
160
|
|
|
|
|
|
|
vals[i] = (double)POPn; \ |
|
161
|
|
|
|
|
|
|
PUTBACK; \ |
|
162
|
|
|
|
|
|
|
} \ |
|
163
|
|
|
|
|
|
|
FREETMPS; LEAVE; \ |
|
164
|
|
|
|
|
|
|
outany.type = PDL_CD; \ |
|
165
|
|
|
|
|
|
|
outany.value.C = (PDL_CDouble)(vals[0] + I * vals[1]); \ |
|
166
|
|
|
|
|
|
|
} while (0) |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
#define ANYVAL_UNSIGNED_X(outsv, inany, sym, ctype, ppsym, ...) \ |
|
169
|
|
|
|
|
|
|
sv_setuv(outsv, (UV)(inany.value.ppsym)); |
|
170
|
|
|
|
|
|
|
#define ANYVAL_SIGNED_X(outsv, inany, sym, ctype, ppsym, ...) \ |
|
171
|
|
|
|
|
|
|
sv_setiv(outsv, (IV)(inany.value.ppsym)); |
|
172
|
|
|
|
|
|
|
#define ANYVAL_FLOATREAL_X(outsv, inany, sym, ctype, ppsym, ...) \ |
|
173
|
|
|
|
|
|
|
sv_setnv(outsv, (NV)(inany.value.ppsym)); |
|
174
|
|
|
|
|
|
|
#define ANYVAL_COMPLEX_X(outsv, inany, sym, ctype, ppsym, shortctype, defbval, realctype, convertfunc, floatsuffix, ...) \ |
|
175
|
|
|
|
|
|
|
PDL_MAKE_PERL_COMPLEX(outsv, creal ## floatsuffix(inany.value.ppsym), cimag ## floatsuffix(inany.value.ppsym)); |
|
176
|
|
|
|
|
|
|
#define ANYVAL_TO_SV(outsv,inany) do { switch (inany.type) { \ |
|
177
|
|
|
|
|
|
|
PDL_TYPELIST_UNSIGNED(PDL_GENERICSWITCH_CASE, ANYVAL_UNSIGNED_X, (outsv,inany,),) \ |
|
178
|
|
|
|
|
|
|
PDL_TYPELIST_SIGNED(PDL_GENERICSWITCH_CASE, ANYVAL_SIGNED_X, (outsv,inany,),) \ |
|
179
|
|
|
|
|
|
|
PDL_TYPELIST_FLOATREAL(PDL_GENERICSWITCH_CASE, ANYVAL_FLOATREAL_X, (outsv,inany,),) \ |
|
180
|
|
|
|
|
|
|
PDL_TYPELIST_COMPLEX(PDL_GENERICSWITCH_CASE, ANYVAL_COMPLEX_X, (outsv,inany,),) \ |
|
181
|
|
|
|
|
|
|
default: outsv = &PL_sv_undef; \ |
|
182
|
|
|
|
|
|
|
} \ |
|
183
|
|
|
|
|
|
|
} while (0) |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
/* Check minimum datatype required to represent number */ |
|
186
|
|
|
|
|
|
|
#define PDL_TESTTYPE(sym, ctype, v) {ctype foo = v; if (v == foo) return sym;} |
|
187
|
|
|
|
|
|
|
static inline int _pdl_whichdatatype_uint(UV uv) { |
|
188
|
|
|
|
|
|
|
#define X(sym, ctype, ...) PDL_TESTTYPE(sym, ctype, uv) |
|
189
|
|
|
|
|
|
|
PDL_TYPELIST_UNSIGNED(X) |
|
190
|
|
|
|
|
|
|
#undef X |
|
191
|
|
|
|
|
|
|
croak("Something's gone wrong: %llu cannot be converted by whichdatatype", (unsigned long long)uv); |
|
192
|
|
|
|
|
|
|
} |
|
193
|
|
|
|
|
|
|
static inline int _pdl_whichdatatype_int(IV iv) { |
|
194
|
|
|
|
|
|
|
#define X(sym, ctype, ...) PDL_TESTTYPE(sym, ctype, iv) |
|
195
|
|
|
|
|
|
|
PDL_TYPELIST_SIGNED(X) |
|
196
|
|
|
|
|
|
|
#undef X |
|
197
|
|
|
|
|
|
|
croak("Something's gone wrong: %lld cannot be converted by whichdatatype", (long long)iv); |
|
198
|
|
|
|
|
|
|
} |
|
199
|
|
|
|
|
|
|
/* Check minimum, at least double, datatype required to represent number */ |
|
200
|
|
|
|
|
|
|
static inline int _pdl_whichdatatype_double(NV nv) { |
|
201
|
|
|
|
|
|
|
PDL_TESTTYPE(PDL_D,PDL_Double, nv) |
|
202
|
|
|
|
|
|
|
PDL_TESTTYPE(PDL_D,PDL_LDouble, nv) |
|
203
|
|
|
|
|
|
|
#undef PDL_TESTTYPE |
|
204
|
|
|
|
|
|
|
return PDL_D; /* handles NaN */ |
|
205
|
|
|
|
|
|
|
} |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
/* __PDLPERL_H */ |
|
208
|
|
|
|
|
|
|
#endif |