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 2 2 100.0
branch n/a
condition n/a
subroutine n/a
pod n/a
total 2 2 100.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 6           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 6           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             }