File Coverage

src/xs/typemap/object.h
Criterion Covered Total %
statement 182 189 96.3
branch 968 3284 29.4
condition n/a
subroutine n/a
pod n/a
total 1150 3473 33.1


line stmt bran cond sub pod time code
1             #pragma once
2             #include "base.h"
3             #include "../Ref.h"
4             #include "../Stash.h"
5             #include "../catch.h"
6             #include "../Backref.h"
7             #include
8             #include
9              
10             namespace xs {
11              
12             using panda::refcnt_inc;
13             using panda::refcnt_dec;
14             using panda::refcnt_get;
15              
16             namespace typemap { namespace object {
17             using svt_clear_t = int(*)(pTHX_ SV*, MAGIC*);
18             using svt_copy_t = int(*)(pTHX_ SV*, MAGIC*, SV*, const char*, I32);
19              
20             extern CV* fake_dtor;
21             extern svt_copy_t backref_marker;
22              
23             void init ();
24              
25             template struct TypemapMarker {
26 0           static int func (pTHX_ SV*, MAGIC*) { return 0; }
27 570 100         PANDA_GLOBAL_MEMBER_PTR(TypemapMarker, svt_clear_t, get, &func);
    100          
    100          
    0          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
28             };
29              
30             panda::string type_details(const std::type_info&);
31             [[ noreturn ]] void _throw_incorrect_arg(SV* arg, const std::type_info& expected, panda::string_view package);
32             [[ noreturn ]] void _throw_no_package (const std::type_info&);
33             }}
34              
35             template
36             struct ObjectStorageIV {
37             static const bool auto_disposable = false;
38              
39 86           static inline void* get (SV* arg) {
40 86 50         return SvIOK(arg) ? (void*)SvIVX(arg) : nullptr;
    50          
    50          
    50          
    50          
    50          
    50          
    100          
41             }
42              
43 19           static inline void set (SV* arg, void* ptr) {
44 19           SvIOK_on(arg);
45 19           SvIVX(arg) = (IV)ptr;
46 19           }
47              
48 19           static Sv out (const TYPE& var, const Sv& proto) {
49 19           return Typemap::create(var, proto);
50             }
51             };
52              
53             template
54             struct ObjectStorageMG_Impl {
55             using PURE_TYPEMAP = std::remove_const_t>>;
56              
57             static const bool auto_disposable = true;
58              
59 226           static inline void* get (SV* arg) {
60 226           MAGIC* mg = _get_magic(arg);
61 226 50         return mg ? mg->mg_ptr : NULL;
    50          
    50          
    0          
    50          
    50          
    100          
    100          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
62             }
63              
64 57           static inline void set (SV* arg, void* ptr) {
65 57 50         auto marker = xs::Sv::PayloadMarker::get();
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
66 57 50         marker->svt_clear = typemap::object::TypemapMarker::get();
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
67 57           marker->svt_free = _on_free;
68 57           _set_br(marker, BACKREF());
69              
70             MAGIC* mg;
71 57 50         Newx(mg, 1, MAGIC);
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
72 57           mg->mg_moremagic = SvMAGIC(arg);
73 57           SvMAGIC_set(arg, mg);
74 57           mg->mg_virtual = marker;
75 57           mg->mg_type = PERL_MAGIC_ext;
76 57           mg->mg_len = 0;
77 57           mg->mg_obj = nullptr;
78 57           mg->mg_ptr = (char*)ptr;
79 57           mg->mg_private = 0;
80              
81             #ifdef USE_ITHREADS
82             marker->svt_dup = _on_svdup;
83             mg->mg_flags = MGf_DUP;
84             #else
85 57           mg->mg_flags = 0;
86             #endif
87 57           }
88              
89 64 50         static Sv out (const TYPE& var, const Sv& proto) { return _out(var, proto, BACKREF()); }
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
90              
91             private:
92 228           static inline MAGIC* _get_magic (SV* sv) {
93 228           auto marker = typemap::object::TypemapMarker::get();
94             MAGIC *mg;
95 286 100         for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) if (mg->mg_virtual && mg->mg_virtual->svt_clear == marker) return mg;
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    100          
    100          
    50          
    100          
    50          
    50          
    100          
    100          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    100          
    50          
    100          
96 14           return NULL;
97             }
98              
99 46           static inline void _set_br (Sv::payload_marker_t*, std::false_type) {}
100 11           static inline void _set_br (Sv::payload_marker_t* marker, std::true_type) {
101 11           marker->svt_copy = typemap::object::backref_marker;
102 11           marker->svt_local = _destroy_hook;
103 11           }
104              
105 92           static inline Sv _out (const TYPE& var, const Sv& proto, std::false_type) { return Typemap::create(var, proto); }
106              
107 18           static inline Sv _out (const TYPE& var, const Sv& proto, std::true_type) {
108 18 50         auto br = Backref::get(var);
109 18 100         if (!br) return Typemap::create(var, proto);
    50          
110 12 100         if (br->svobj) {
111 5           if (!std::is_const>::value) SvREADONLY_off(br->svobj);
112 5 100         if (!br->zombie) return Ref::create(br->svobj);
    50          
113 2 50         _from_zombie(Typemap::IType::template cast(var), br->svobj, _get_magic(br->svobj), br);
    50          
114 2 50         return Sv::noinc(newRV_noinc(br->svobj));
115             }
116 25 50         auto ret = Typemap::create(var, proto);
117 7           br->svobj = SvRV(ret);
118 7           return ret;
119             }
120              
121             // this hook is invoked before perl frees SV and before DESTROY() method if SV is an object
122             // if non-zero value is returned then the destruction of SV is completely aborted (and DESTROY() method is not called)
123 72           static int _destroy_hook (pTHX_ SV* sv, MAGIC* mg) { return throw_guard(Sub(), [=]() -> int {
124 18           TYPEMAP var = Typemap::IType::template in(mg->mg_ptr);
125 18 50         auto br = Backref::get(var);
126 18 100         if (!br) return 0;
127              
128 14 100         if (br->zombie) {
129             // as no one has strong reference to our zombie SV backref, its destruction is only possible in 2 cases:
130             // - decremented from C destructor of XSBackref class
131             // - perl is cleaning his arena in destruction phase
132 5 50         _restore_dtor(sv);
133 5 50         _from_zombie(var, sv, mg, br);
134 5 100         if (br->in_cdtor) Typemap::IType::retain(var); // avoid double deletion if refcnt policy of 'var' drops to 0 during deletion
135             else assert(PL_in_clean_objs);
136 5           return 0;
137             }
138              
139             // if we are the only owner or in global destroy phase there is no sense of making zombie
140 9 100         if (Typemap::IType::use_count(var) <= 1 || PL_in_clean_objs) {
    50          
    100          
141 2 50         _restore_dtor(sv);
142 2           br->svobj = NULL;
143 2           return 0;
144             }
145              
146             // perl SV goes out of scope, but C object is still accessible -> save SV to zombie
147 7 50         _to_zombie(var, sv, mg, br);
148 18           return 1;
149 36 50         });}
150              
151             struct ZombieMarker {};
152              
153 8           static inline MAGIC* _zombie_get_stash_magic (HV* stash) {
154 8           auto marker = xs::Sv::PayloadMarker::get();
155             MAGIC *mg;
156 10 100         for (mg = SvMAGIC(stash); mg; mg = mg->mg_moremagic) if (mg->mg_virtual == marker) return mg;
    100          
157 2           return NULL;
158             }
159              
160             #if PERL_VERSION >= 24
161             // prevent S_curse from calling dtor
162 7           static inline void _ignore_dtor (SV* sv) {
163 7           auto stash = SvSTASH(sv);
164 7 50         auto meta = HvMROMETA(stash);
    0          
165 7 100         if (meta->destroy == typemap::object::fake_dtor) return;
166 4 50         auto stmg = _zombie_get_stash_magic(stash);
167 4 100         if (!stmg) stmg = Sv(stash).payload_attach(Sv::Payload(), xs::Sv::PayloadMarker::get());
    50          
    50          
168 4           stmg->mg_obj = (SV*)meta->destroy;
169 4           stmg->mg_ptr = (char*)(uint64_t)meta->destroy_gen;
170 4           meta->destroy = typemap::object::fake_dtor;
171 7           meta->destroy_gen = PL_sub_generation; // make cache valid
172             }
173              
174 7           static inline void _restore_dtor (SV* sv) {
175 7           auto stash = SvSTASH(sv);
176 7 50         auto meta = HvMROMETA(stash);
    0          
177 7 100         if (meta->destroy != typemap::object::fake_dtor) return;
178 4 50         auto stmg = _zombie_get_stash_magic(stash);
179 4           meta->destroy = (CV*)stmg->mg_obj; // restore dtor
180 7           meta->destroy_gen = (uint64_t)stmg->mg_ptr;
181             }
182             #else
183             static inline void _ignore_dtor (SV*) {}
184             static inline void _restore_dtor (SV*) {}
185             #endif
186              
187 7           static inline void _to_zombie (const TYPEMAP& var, SV* sv, MAGIC*, const Backref* br) {
188 7           br->zombie = true;
189 7           SvREFCNT(sv)++;
190 7           Typemap::IType::release(var);
191 7           _ignore_dtor(sv);
192 7           }
193              
194 7           static inline void _from_zombie (const TYPEMAP& var, SV*, MAGIC*, const Backref* br) {
195 7           br->zombie = false;
196 7           Typemap::IType::retain(var);
197 7           }
198              
199 224           static int _on_free (pTHX_ SV* sv, MAGIC* mg) {return throw_guard(Sub(), [=]() -> int {
200             using IType = typename Typemap::IType;
201 60           TYPEMAP downgraded = IType::template in(mg->mg_ptr);
202 60 50         TYPE var = Typemap::template cast(downgraded);
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
203 56 50         if (!var) throw "TYPEMAP PANIC: bad object in sv";
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
204 56 50         Typemap::dispose(var, sv);
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
205 56           return 0;
206 112 50         });}
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
207              
208             static int _on_svdup (pTHX_ MAGIC* mg, CLONE_PARAMS*) { return throw_guard(Sub(), [=]() -> int {
209             using IType = typename Typemap::IType;
210             TYPEMAP downgraded = IType::template in(mg->mg_ptr);
211             TYPEMAP new_downgraded = Typemap::dup(downgraded);
212             _on_svdup_br(downgraded, new_downgraded, BACKREF());
213             mg->mg_ptr = (char*)IType::out(new_downgraded);
214             return 0;
215             });}
216              
217             static void _on_svdup_br (const TYPEMAP&, const TYPEMAP&, std::false_type) {}
218             static void _on_svdup_br (const TYPEMAP& var, const TYPEMAP& new_var, std::true_type) {
219             auto br = Backref::get(var);
220             auto new_br = Backref::get(new_var);
221             if (br && br->svobj && new_br) {
222             new_br->svobj = MUTABLE_SV(ptr_table_fetch(PL_ptr_table, br->svobj));
223             assert(new_br->svobj);
224             }
225             }
226             };
227              
228             template using ObjectStorageMG = ObjectStorageMG_Impl;
229             template using ObjectStorageMGBackref = ObjectStorageMG_Impl;
230              
231             struct ObjectTypePtr {
232 432           template static inline T in (void* p) { return static_cast(p); }
233 80           template static inline const void* out (T* var) { return var; }
234 80 50         template static inline void destroy (T* var, SV*) { delete var; }
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
235              
236 120           template static inline TO cast (FROM* var) { return static_cast(const_cast*>(var)); }
237 392           template static inline TO upgrade (FROM* var) { return panda::dyn_cast(var); }
238             };
239              
240             struct ObjectTypeForeignPtr {
241 10           template static inline T in (void* p) { return static_cast(p); }
242 2           template static inline const void* out (T* var) { return var; }
243 1           template static inline void destroy (T*, SV*) {}
244              
245 12           template static inline TO cast (FROM* var) { return static_cast(const_cast*>(var)); }
246             template static inline TO upgrade (FROM* var) { return panda::dyn_cast(var); }
247             };
248              
249             struct ObjectTypeRefcntPtr {
250 218           template static inline T in (void* p) { return static_cast(p); }
251 54 0         template static inline const void* out (T* var) { refcnt_inc(var); return var; }
252 52 0         template static inline void destroy (T* var, SV*) { refcnt_dec(var); }
253 22           template static inline void retain (T* var) { refcnt_inc(var); }
254 14           template static inline void release (T* var) { refcnt_dec(var); }
255 18           template static inline uint32_t use_count (T* var) { return refcnt_get(var); }
256              
257 58           template static inline TO cast (FROM* var) { return static_cast(const_cast*>(var)); }
258 182           template static inline TO upgrade (FROM* var) { return panda::dyn_cast(var); }
259             };
260              
261             struct ObjectTypeSharedPtr {
262 52           template static inline T in (void* p) { return *(static_cast(p)); }
263 16           template static inline const void* out (const std::shared_ptr& var) { return new std::shared_ptr(var); }
264              
265             template static inline void retain (const std::shared_ptr& var) {
266             char tmp[sizeof(var)];
267             new (tmp) std::shared_ptr(var);
268             }
269              
270             template static inline void release (const std::shared_ptr& var) {
271             std::shared_ptr tmp;
272             memcpy(&tmp, &var, sizeof(tmp));
273             }
274              
275             template static inline uint32_t use_count (const std::shared_ptr& var) { return var.use_count() - 1; }
276              
277 8           template static inline void destroy (const std::shared_ptr&, SV* arg) {
278             using sp_t = std::shared_ptr;
279 8           void* p = Typemap::IStorage::get(arg);
280 8 50         delete static_cast(p);
    50          
    50          
281 8           }
282              
283 8           template static inline TO cast (const std::shared_ptr& var) {
284 8           return std::static_pointer_cast(std::const_pointer_cast>(var));
285             }
286              
287 26           template static inline TO upgrade (const std::shared_ptr& var) {
288 26           return std::dynamic_pointer_cast(var);
289             }
290             };
291              
292             using StaticCast = std::true_type;
293             using DynamicCast = std::false_type;
294              
295             template class _IStorage, class CastType = StaticCast>
296             struct TypemapObject : TypemapBase {
297             using IType = _IType;
298             using IStorage = _IStorage;
299             using TypeNP = typename std::remove_pointer::type;
300              
301 375           static TYPE in (SV* arg) {
302 375 50         if (!SvOBJECT(arg)) {
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
303 375 50         if (SvROK(arg)) {
    50          
    100          
    0          
    50          
    50          
    100          
    100          
    100          
    100          
    50          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    100          
304 332           arg = SvRV(arg);
305 332 50         if (!SvOBJECT(arg)) throw "arg is a reference to non-object";
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    100          
306             }
307 43 0         else if (!SvOK(arg)) return TYPE();
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    100          
    50          
    50          
    100          
    50          
    50          
308 16           else throw "arg is not a reference to object";
309             }
310              
311 304 50         auto ptr = IStorage::get(arg);
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
312 304 50         if (ptr) {
    50          
    50          
    0          
    50          
    50          
    100          
    100          
    50          
    100          
    50          
    50          
    50          
313 304           TYPEMAP downgraded = IType::template in(ptr);
314 304 0         TYPE ret = cast(downgraded);
    0          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
315 282 0         if (ret) {
    0          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    100          
    50          
    50          
316 280 0         if (!std::is_const::value && SvREADONLY(arg)) throw "cannot modify read-only object";
    0          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
317 282 50         return ret;
    50          
    50          
    50          
318             }
319             }
320              
321             // it's definitely developer bug, there is no known way to determine real object tyep
322             // from void*, see https://stackoverflow.com/questions/1718412/find-out-type-of-c-void-pointer
323 48 50         auto package = Typemap::package();
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
324 24           auto package_view = panda::string_view{ package.data(), package.length() };
325 331           typemap::object::_throw_incorrect_arg(arg, typeid (TYPE), package_view);
326             }
327              
328 166           static Sv out (const TYPE& var, const Sv& proto = Sv()) { return IStorage::out(var, proto); }
329              
330             /* proto is a hint for TypemapObject's out/create to attach 'var' to
331             * it might be:
332             * 1) blessed object (or reference to it): in this case it is used as final object
333             * typical usage - when calling next method
334             * PROTO = stash.call_next(...);
335             * 2) class name or stash to bless to: in this case reference to undef is created and blessed into this class
336             * typical usage - in constructor, to bless to the class 'new' was called into, not to default class
337             * PROTO = ST(0);
338             * 3) other values (or reference to it): in this case it is blessed to typemap's default class and used
339             * typical usage - in constructor or in overloaded typemap's create() method to specify object's base
340             * PROTO = Array::create();
341             * 4) empty: in this case reference to undef is created and blessed to typemap's default class and used
342             */
343 78           static Sv create (const TYPE& var, const Sv& proto = Sv()) {
344 78 50         if (!var) return &PL_sv_undef;
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
345 154           Sv rv;
346             SV* base;
347 76 50         if (proto) {
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    100          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    100          
    50          
    50          
348 67 50         if (SvROK(proto)) { // ref to object/base
    50          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
349 9 0         rv = proto;
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
350 9           base = SvRV(proto);
351             }
352 58 50         else if (proto.type() <= SVt_PVMG) { // class name
    50          
    0          
    0          
    50          
    50          
    0          
    0          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
353 56 50         if (SvOBJECT(proto)) {
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
354 0           base = proto;
355 0 0         rv = Sv::noinc(newRV_noinc(base));
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
356             } else {
357 56 50         base = newSV_type(SVt_PVMG);
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
358 56 50         rv = Sv::noinc(newRV_noinc(base));
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
359 56 50         sv_bless(rv, gv_stashsv(proto, GV_ADD));
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
360             }
361 56           goto ATTACH; // skip optional blessing
362             }
363 2 0         else if (proto.type() == SVt_PVHV && HvNAME(proto)) { // stash
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
364 0 0         base = newSV_type(SVt_PVMG);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
365 0 0         rv = Sv::noinc(newRV_noinc(base));
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
366 0 0         sv_bless(rv, proto.get());
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
367 0           goto ATTACH; // skip optional blessing
368             }
369             else { // base given
370 2 0         rv = Sv::noinc(newRV(proto));
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
371 11           base = proto;
372             }
373             }
374             else { // nothing given, create ref to undef
375 9 0         base = newSV_type(SVt_PVMG);
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
376 9 0         rv = Sv::noinc(newRV_noinc(base));
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
377 9           goto BLESS; // definitely needs blessing
378             }
379              
380 11 0         if (!SvOBJECT(base)) { // not blessed -> bless to default typemap's class
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
381             BLESS:
382 11 0         static PERL_THREAD_LOCAL HV* stash = gv_stashpvn(Typemap::package().data(), Typemap::package().length(), GV_ADD);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    100          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    0          
    100          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    0          
    100          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
383 11 0         sv_bless(rv, stash); // TODO: custom faster bless
    0          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
384             }
385              
386             ATTACH:
387 76 50         IStorage::set(base, const_cast(IType::out(IType::template cast(var))));
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
388              
389             if (std::is_const::value) SvREADONLY_on(base);
390              
391 76           return rv;
392             }
393              
394             static TYPEMAP dup (const TYPEMAP& obj) { return obj; }
395              
396 75           static void dispose (const TYPE& var, SV* arg) {
397 75           IType::destroy(var, arg);
398 75           }
399              
400 162           static void destroy (const TYPE& var, SV* arg) {
401 14           if (!std::is_same::value) return;
402 19           if (!IStorage::auto_disposable) dispose(var, arg);
403             }
404              
405 338 50         template static inline TO cast (FROM v) { return _cast(v, CastType()); }
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
406              
407             static panda::string_view package () { typemap::object::_throw_no_package(typeid(TYPE)); return ""; }
408              
409             static Stash default_stash () {
410             static PERL_THREAD_LOCAL Stash stash = gv_stashpvn(Typemap::package().data(), Typemap::package().length(), GV_ADD);
411             return stash;
412             }
413              
414             private:
415 626           template static inline TO _cast (FROM v, DynamicCast) { return IType::template upgrade(v); }
416 50           template static inline TO _cast (FROM v, StaticCast) { return IType::template cast(v); }
417             };
418              
419             }