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