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 4 4 100.0
branch n/a
condition n/a
subroutine n/a
pod n/a
total 4 4 100.0


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             }