line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#pragma once |
2
|
|
|
|
|
|
|
#include <xs/Array.h> |
3
|
|
|
|
|
|
|
#include <xs/Simple.h> |
4
|
|
|
|
|
|
|
#include <initializer_list> |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
namespace xs { |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
using xs::my_perl; |
9
|
|
|
|
|
|
|
|
10
|
14346
|
|
|
|
|
|
struct Sub : Sv { |
11
|
|
|
|
|
|
|
enum class Want { Void = G_VOID, Scalar = G_SCALAR, Array = G_ARRAY }; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
static Sub create (panda::string_view code); // create sub by evaling perl code |
14
|
|
|
|
|
|
|
static Sub create (XSUBADDR_t); // create anon XSub |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
static Sub noinc (SV* val) { return Sub(val, NONE); } |
17
|
|
|
|
|
|
|
static Sub noinc (CV* val) { return Sub(val, NONE); } |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
static Sub clone_anon_xsub (const Sub&); |
20
|
|
|
|
|
|
|
|
21
|
14322
|
|
|
|
|
|
Sub (std::nullptr_t = nullptr) {} |
22
|
|
|
|
|
|
|
Sub (SV* sv, bool policy = INCREMENT) : Sv(sv, policy) { _validate(); } |
23
|
24
|
|
|
|
|
|
Sub (CV* sv, bool policy = INCREMENT) : Sv(sv, policy) {} |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
explicit |
26
|
|
|
|
|
|
|
Sub (panda::string_view subname, I32 flags = 0) { |
27
|
|
|
|
|
|
|
*this = get_cvn_flags(subname.data(), subname.length(), flags); |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
Sub (const Sub& oth) : Sv(oth) {} |
31
|
|
|
|
|
|
|
Sub (Sub&& oth) : Sv(std::move(oth)) {} |
32
|
|
|
|
|
|
|
Sub (const Sv& oth) : Sv(oth) { _validate(); } |
33
|
|
|
|
|
|
|
Sub (Sv&& oth) : Sv(std::move(oth)) { _validate(); } |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
Sub (const Simple&) = delete; |
36
|
|
|
|
|
|
|
Sub (const Array&) = delete; |
37
|
|
|
|
|
|
|
Sub (const Hash&) = delete; |
38
|
|
|
|
|
|
|
Sub (const Glob&) = delete; |
39
|
|
|
|
|
|
|
Sub (const Io&) = delete; |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
Sub& operator= (SV* val) { Sv::operator=(val); _validate(); return *this; } |
42
|
|
|
|
|
|
|
Sub& operator= (CV* val) { Sv::operator=(val); return *this; } |
43
|
|
|
|
|
|
|
Sub& operator= (const Sub& oth) { Sv::operator=(oth); return *this; } |
44
|
|
|
|
|
|
|
Sub& operator= (Sub&& oth) { Sv::operator=(std::move(oth)); return *this; } |
45
|
|
|
|
|
|
|
Sub& operator= (const Sv& oth) { return operator=(oth.get()); } |
46
|
|
|
|
|
|
|
Sub& operator= (Sv&& oth) { Sv::operator=(std::move(oth)); _validate(); return *this; } |
47
|
|
|
|
|
|
|
Sub& operator= (const Simple&) = delete; |
48
|
|
|
|
|
|
|
Sub& operator= (const Array&) = delete; |
49
|
|
|
|
|
|
|
Sub& operator= (const Hash&) = delete; |
50
|
|
|
|
|
|
|
Sub& operator= (const Glob&) = delete; |
51
|
|
|
|
|
|
|
Sub& operator= (const Io&) = delete; |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
void set (SV* val) { Sv::operator=(val); } |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
operator AV* () const = delete; |
56
|
|
|
|
|
|
|
operator HV* () const = delete; |
57
|
14322
|
|
|
|
|
|
operator CV* () const { return (CV*)sv; } |
58
|
|
|
|
|
|
|
operator GV* () const = delete; |
59
|
|
|
|
|
|
|
operator IO* () const = delete; |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
CV* operator-> () const { return (CV*)sv; } |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
template <typename T = SV> panda::enable_if_one_of_t<T,SV,CV>* get () const { return (T*)sv; } |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
Stash stash () const; |
66
|
|
|
|
|
|
|
Glob glob () const; |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
panda::string_view name () const { |
69
|
|
|
|
|
|
|
GV* gv = CvGV((CV*)sv); |
70
|
|
|
|
|
|
|
return panda::string_view(GvNAME(gv), GvNAMELEN(gv)); |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
bool named () const { return CvNAMED((CV*)sv); } |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
Sub SUPER () const { |
76
|
|
|
|
|
|
|
GV* mygv = CvGV((CV*)sv); |
77
|
|
|
|
|
|
|
GV* supergv = gv_fetchmeth_pvn(GvSTASH(mygv), GvNAME(mygv), GvNAMELEN(mygv), 0, GV_SUPER); |
78
|
|
|
|
|
|
|
return Sub(supergv ? GvCV(supergv) : nullptr); |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
Sub SUPER_strict () const { |
82
|
|
|
|
|
|
|
Sub ret = SUPER(); |
83
|
|
|
|
|
|
|
if (!ret) _throw_super(); |
84
|
|
|
|
|
|
|
return ret; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
static Want want () { return (Want)GIMME_V; } |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
static int want_count (); |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
private: |
92
|
|
|
|
|
|
|
struct CallArgs { |
93
|
|
|
|
|
|
|
SV* self; |
94
|
|
|
|
|
|
|
SV*const* list; |
95
|
|
|
|
|
|
|
const Scalar* scalars; |
96
|
|
|
|
|
|
|
size_t items; |
97
|
|
|
|
|
|
|
}; |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
template <class Enable, class...Ctx> struct CallContext; |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
public: |
102
|
|
|
|
|
|
|
template <class...Ctx> using call_t = decltype(CallContext<void, Ctx...>::call((CV*)nullptr, CallArgs())); |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
template <class...Ctx, class...Args> |
105
|
|
|
|
|
|
|
call_t<Ctx...> call (Args&&...va) const { |
106
|
|
|
|
|
|
|
auto args = _get_args(va...); |
107
|
|
|
|
|
|
|
return CallContext<void, Ctx...>::call((CV*)sv, args); |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
template <class...Args> |
111
|
|
|
|
|
|
|
Scalar operator() (Args&&...args) const { return call<Scalar>(std::forward<Args>(args)...); } |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
private: |
114
|
|
|
|
|
|
|
void _validate () { |
115
|
|
|
|
|
|
|
if (!sv) return; |
116
|
|
|
|
|
|
|
if (SvTYPE(sv) == SVt_PVCV) return; |
117
|
|
|
|
|
|
|
if (SvROK(sv)) { // reference to code? |
118
|
|
|
|
|
|
|
SV* val = SvRV(sv); |
119
|
|
|
|
|
|
|
if (SvTYPE(val) == SVt_PVCV) { |
120
|
|
|
|
|
|
|
Sv::operator=(val); |
121
|
|
|
|
|
|
|
return; |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
if (is_undef()) return reset(); |
125
|
|
|
|
|
|
|
reset(); |
126
|
|
|
|
|
|
|
throw std::invalid_argument("SV is not a Sub or Sub reference"); |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
void _throw_super () const; |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
template <class...Args> |
132
|
|
|
|
|
|
|
struct VCallArgs : CallArgs { |
133
|
|
|
|
|
|
|
SV* list[sizeof...(Args)]; |
134
|
|
|
|
|
|
|
VCallArgs (Args&&...args) : CallArgs{nullptr, list, nullptr, sizeof...(Args)}, list{std::forward<Args>(args)...} { |
135
|
|
|
|
|
|
|
for (auto sv : list) |
136
|
|
|
|
|
|
|
if (sv && SvTYPE(sv) > SVt_PVMG && SvTYPE(sv) != SVt_PVGV) |
137
|
|
|
|
|
|
|
throw std::invalid_argument("one of arguments for sub.call() is not a scalar value"); |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
}; |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
template <class...T> struct type_pack {}; |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
static CallArgs _get_args (SV*const* args = nullptr, size_t items = 0) { return {nullptr, args, nullptr, items}; } |
144
|
|
|
|
|
|
|
static CallArgs _get_args (SV* arg0, SV*const* args, size_t items) { return { arg0, args, nullptr, items}; } |
145
|
|
|
|
|
|
|
static CallArgs _get_args (const Scalar* args, size_t items) { return {nullptr, nullptr, args, items}; } |
146
|
|
|
|
|
|
|
static CallArgs _get_args (SV* arg0, const Scalar* args, size_t items) { return { arg0, nullptr, args, items}; } |
147
|
|
|
|
|
|
|
static CallArgs _get_args (const std::initializer_list<Scalar>& l) { return {nullptr, nullptr, l.begin(), l.size()}; } |
148
|
|
|
|
|
|
|
static CallArgs _get_args (SV* arg0, const std::initializer_list<Scalar>& l) { return { arg0, nullptr, l.begin(), l.size()}; } |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
template <class...Args, typename = type_pack<decltype(Scalar(std::declval<Args>()))...>> |
151
|
|
|
|
|
|
|
static VCallArgs<Args...> _get_args (Args&&...args) { return {std::forward<Args>(args)...}; } |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
static size_t _call (CV*, I32 flags, const CallArgs&, SV** ret, size_t maxret, AV** avr); |
154
|
|
|
|
|
|
|
}; |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
template <class...Types> |
157
|
|
|
|
|
|
|
struct Sub::CallContext<void, std::tuple<Types...>> { |
158
|
|
|
|
|
|
|
using type = std::tuple<Types...>; |
159
|
|
|
|
|
|
|
static constexpr size_t N = sizeof...(Types); |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
static type call (CV* cv, const CallArgs& args) { |
162
|
|
|
|
|
|
|
SV* ret[N] = {nullptr}; |
163
|
|
|
|
|
|
|
_call(cv, G_ARRAY, args, ret, N, nullptr); |
164
|
|
|
|
|
|
|
return _make_tuple<type>(ret, std::make_index_sequence<N>()); |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
template <class T, size_t...Inds> |
168
|
|
|
|
|
|
|
static T _make_tuple (SV** svs, std::integer_sequence<size_t, Inds...>) { |
169
|
|
|
|
|
|
|
return T(typename std::tuple_element<Inds, T>::type(svs[Inds], Sv::NONE)...); |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
}; |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
template <class Enable, class...Ret> |
174
|
|
|
|
|
|
|
struct Sub::CallContext : Sub::CallContext<void, std::tuple<Ret...>> {}; |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
template <class T> |
177
|
|
|
|
|
|
|
struct Sub::CallContext<enable_if_sv_t<T,void>, T> { |
178
|
|
|
|
|
|
|
static T call (CV* cv, const CallArgs& args) { |
179
|
|
|
|
|
|
|
SV* ret = NULL; |
180
|
|
|
|
|
|
|
_call(cv, G_SCALAR, args, &ret, 1, nullptr); |
181
|
|
|
|
|
|
|
return T(ret, Sv::NONE); |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
}; |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
template <> |
186
|
|
|
|
|
|
|
struct Sub::CallContext<void> : Sub::CallContext<void, Scalar> {}; |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
template <> |
189
|
|
|
|
|
|
|
struct Sub::CallContext<void, List> { |
190
|
|
|
|
|
|
|
static List call (CV* cv, const CallArgs& args) { |
191
|
|
|
|
|
|
|
AV* av = NULL; |
192
|
|
|
|
|
|
|
_call(cv, G_ARRAY, args, nullptr, 0, &av); |
193
|
|
|
|
|
|
|
return List(av, Sv::NONE); |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
}; |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
template <> |
198
|
|
|
|
|
|
|
struct Sub::CallContext<void, void> { |
199
|
|
|
|
|
|
|
static void call (CV* cv, const CallArgs& args) { _call(cv, G_VOID, args, nullptr, 0, nullptr); } |
200
|
|
|
|
|
|
|
}; |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
template <class T, size_t N> |
203
|
|
|
|
|
|
|
struct Sub::CallContext<enable_if_sv_t<T,void>, std::array<T,N>> { |
204
|
|
|
|
|
|
|
using type = std::array<T,N>; |
205
|
|
|
|
|
|
|
static type call (CV* cv, const CallArgs& args) { |
206
|
|
|
|
|
|
|
SV* svret[N]; |
207
|
|
|
|
|
|
|
auto nret = _call(cv, G_ARRAY, args, svret, N, nullptr); |
208
|
|
|
|
|
|
|
type ret; |
209
|
|
|
|
|
|
|
for (size_t i = 0; i < nret; ++i) ret[i] = T(svret[i], Sv::NONE); |
210
|
|
|
|
|
|
|
return ret; |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
}; |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
template <> |
215
|
|
|
|
|
|
|
struct Sub::CallContext<void, panda::string> { |
216
|
|
|
|
|
|
|
static panda::string call (CV* cv, const CallArgs& args) { return CallContext<void, Simple>::call(cv, args).as_string<panda::string>(); } |
217
|
|
|
|
|
|
|
}; |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
template <class T> |
220
|
|
|
|
|
|
|
struct Sub::CallContext<panda::enable_if_arithmetic_t<T,void>, T> { |
221
|
|
|
|
|
|
|
static T call (CV* cv, const CallArgs& args) { return CallContext<void, Simple>::call(cv, args); } |
222
|
|
|
|
|
|
|
}; |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
} |