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