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