File Coverage

/usr/local/lib/perl5/site_perl/5.26.1/x86_64-linux/XS/Framework.x/i/xs/Sub.h
Criterion Covered Total %
statement 0 4 0.0
branch n/a
condition n/a
subroutine n/a
pod n/a
total 0 4 0.0


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