File Coverage

/usr/local/lib/perl5/site_perl/5.26.1/x86_64-linux/XS/Framework.x/i/xs/typemap/object.h
Criterion Covered Total %
statement 106 156 67.9
branch 371 1620 22.9
condition n/a
subroutine n/a
pod n/a
total 477 1776 26.8


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 2224 100         PANDA_GLOBAL_MEMBER_PTR(TypemapMarker, svt_clear_t, get, &func);
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             static inline void* get (SV* arg) {
40             return SvIOK(arg) ? (void*)SvIVX(arg) : nullptr;
41             }
42              
43             static inline void set (SV* arg, void* ptr) {
44             SvIOK_on(arg);
45             SvIVX(arg) = (IV)ptr;
46             }
47              
48             static Sv out (const TYPE& var, const Sv& proto) {
49             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 976           static inline void* get (SV* arg) {
60 976           MAGIC* mg = _get_magic(arg);
61 976 50         return mg ? mg->mg_ptr : NULL;
    50          
62             }
63              
64 136           static inline void set (SV* arg, void* ptr) {
65 136 50         auto marker = xs::Sv::PayloadMarker::get();
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
66 136 50         marker->svt_clear = typemap::object::TypemapMarker::get();
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
67 136           marker->svt_free = _on_free;
68 136           _set_br(marker, BACKREF());
69              
70             MAGIC* mg;
71 136 50         Newx(mg, 1, MAGIC);
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
72 136           mg->mg_moremagic = SvMAGIC(arg);
73 136           SvMAGIC_set(arg, mg);
74 136           mg->mg_virtual = marker;
75 136           mg->mg_type = PERL_MAGIC_ext;
76 136           mg->mg_len = 0;
77 136           mg->mg_obj = nullptr;
78 136           mg->mg_ptr = (char*)ptr;
79 136           mg->mg_private = 0;
80              
81             #ifdef USE_ITHREADS
82             marker->svt_dup = _on_svdup;
83             mg->mg_flags = MGf_DUP;
84             #else
85 136           mg->mg_flags = 0;
86             #endif
87 136           }
88              
89 136 50         static Sv out (const TYPE& var, const Sv& proto) { return _out(var, proto, BACKREF()); }
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
90              
91             private:
92 976           static inline MAGIC* _get_magic (SV* sv) {
93 976           auto marker = typemap::object::TypemapMarker::get();
94             MAGIC *mg;
95 1952 50         for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) if (mg->mg_virtual && mg->mg_virtual->svt_clear == marker) return mg;
    50          
    100          
    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          
    100          
96 0           return NULL;
97             }
98              
99             static inline void _set_br (Sv::payload_marker_t*, std::false_type) {}
100 136           static inline void _set_br (Sv::payload_marker_t* marker, std::true_type) {
101 136           marker->svt_copy = typemap::object::backref_marker;
102 136           marker->svt_local = _destroy_hook;
103 136           }
104              
105             static inline Sv _out (const TYPE& var, const Sv& proto, std::false_type) { return Typemap::create(var, proto); }
106              
107 136           static inline Sv _out (const TYPE& var, const Sv& proto, std::true_type) {
108 136 50         auto br = Backref::get(var);
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
109 136 50         if (!br) return Typemap::create(var, proto);
    0          
    50          
    0          
    50          
    0          
    50          
    0          
    50          
    0          
    50          
    0          
    50          
    0          
    50          
    0          
    50          
    0          
    100          
    50          
110 113 50         if (br->svobj) {
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
111 0           if (!std::is_const>::value) SvREADONLY_off(br->svobj);
112 0 0         if (!br->zombie) return Ref::create(br->svobj);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
113 0 0         _from_zombie(Typemap::IType::template cast(var), br->svobj, _get_magic(br->svobj), br);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
114 0 0         return Sv::noinc(newRV_noinc(br->svobj));
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
115             }
116 249 50         auto ret = Typemap::create(var, proto);
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
117 113           br->svobj = SvRV(ret);
118 113           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 544           static int _destroy_hook (pTHX_ SV* sv, MAGIC* mg) { return throw_guard(Sub(), [=]() -> int {
124 136           TYPEMAP var = Typemap::IType::template in(mg->mg_ptr);
125 136 50         auto br = Backref::get(var);
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
126 136 50         if (!br) return 0;
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
127              
128 113 50         if (br->zombie) {
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
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 0 0         _restore_dtor(sv);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
133 0 0         _from_zombie(var, sv, mg, br);
134 0 0         if (br->in_cdtor) Typemap::IType::retain(var); // avoid double deletion if refcnt policy of 'var' drops to 0 during deletion
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
135             else assert(PL_in_clean_objs);
136 0           return 0;
137             }
138              
139             // if we are the only owner or in global destroy phase there is no sense of making zombie
140 113 50         if (Typemap::IType::use_count(var) <= 1 || PL_in_clean_objs) {
    0          
    50          
    50          
    0          
    50          
    50          
    0          
    50          
    50          
    0          
    50          
    50          
    0          
    50          
    50          
    0          
    50          
    50          
    0          
    50          
    50          
    0          
    50          
    50          
    0          
    50          
    50          
    0          
    50          
141 113 50         _restore_dtor(sv);
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
142 113           br->svobj = NULL;
143 113           return 0;
144             }
145              
146             // perl SV goes out of scope, but C object is still accessible -> save SV to zombie
147 0 0         _to_zombie(var, sv, mg, br);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
148 136           return 1;
149 272 50         });}
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
150              
151             struct ZombieMarker {};
152              
153 0           static inline MAGIC* _zombie_get_stash_magic (HV* stash) {
154 0           auto marker = xs::Sv::PayloadMarker::get();
155             MAGIC *mg;
156 0 0         for (mg = SvMAGIC(stash); mg; mg = mg->mg_moremagic) if (mg->mg_virtual == marker) return mg;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
157 0           return NULL;
158             }
159              
160             #if PERL_VERSION >= 24
161             // prevent S_curse from calling dtor
162 0           static inline void _ignore_dtor (SV* sv) {
163 0           auto stash = SvSTASH(sv);
164 0 0         auto meta = HvMROMETA(stash);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
165 0 0         if (meta->destroy == typemap::object::fake_dtor) return;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
166 0 0         auto stmg = _zombie_get_stash_magic(stash);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
167 0 0         if (!stmg) stmg = Sv(stash).payload_attach(Sv::Payload(), xs::Sv::PayloadMarker::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          
    0          
    0          
168 0           stmg->mg_obj = (SV*)meta->destroy;
169 0           stmg->mg_ptr = (char*)(uint64_t)meta->destroy_gen;
170 0           meta->destroy = typemap::object::fake_dtor;
171 0           meta->destroy_gen = PL_sub_generation; // make cache valid
172             }
173              
174 113           static inline void _restore_dtor (SV* sv) {
175 113           auto stash = SvSTASH(sv);
176 113 50         auto meta = HvMROMETA(stash);
    0          
    50          
    0          
    50          
    0          
    50          
    0          
    50          
    0          
    50          
    0          
    50          
    0          
    50          
    0          
    50          
    0          
    50          
    0          
177 113 50         if (meta->destroy != typemap::object::fake_dtor) return;
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
178 0 0         auto stmg = _zombie_get_stash_magic(stash);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
179 0           meta->destroy = (CV*)stmg->mg_obj; // restore dtor
180 113           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 0           static inline void _to_zombie (const TYPEMAP& var, SV* sv, MAGIC*, const Backref* br) {
188 0           br->zombie = true;
189 0           SvREFCNT(sv)++;
190 0           Typemap::IType::release(var);
191 0           _ignore_dtor(sv);
192 0           }
193              
194 0           static inline void _from_zombie (const TYPEMAP& var, SV*, MAGIC*, const Backref* br) {
195 0           br->zombie = false;
196 0           Typemap::IType::retain(var);
197 0           }
198              
199 544           static int _on_free (pTHX_ SV* sv, MAGIC* mg) {return throw_guard(Sub(), [=]() -> int {
200             using IType = typename Typemap::IType;
201 136           TYPEMAP downgraded = IType::template in(mg->mg_ptr);
202 136 50         TYPE var = Typemap::template cast(downgraded);
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
203 136 50         if (!var) throw "TYPEMAP PANIC: bad object in sv";
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
204 136 50         Typemap::dispose(var, sv);
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
205 136           return 0;
206 272 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             template static inline T in (void* p) { return static_cast(p); }
233             template static inline const void* out (T* var) { return var; }
234             template static inline void destroy (T* var, SV*) { delete var; }
235              
236             template static inline TO cast (FROM* var) { return static_cast(const_cast*>(var)); }
237             template static inline TO upgrade (FROM* var) { return panda::dyn_cast(var); }
238             };
239              
240             struct ObjectTypeForeignPtr {
241             template static inline T in (void* p) { return static_cast(p); }
242             template static inline const void* out (T* var) { return var; }
243             template static inline void destroy (T*, SV*) {}
244              
245             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 2496           template static inline T in (void* p) { return static_cast(p); }
251 272           template static inline const void* out (T* var) { refcnt_inc(var); return var; }
252 272           template static inline void destroy (T* var, SV*) { refcnt_dec(var); }
253 0           template static inline void retain (T* var) { refcnt_inc(var); }
254 0           template static inline void release (T* var) { refcnt_dec(var); }
255 226           template static inline uint32_t use_count (T* var) { return refcnt_get(var); }
256              
257 272           template static inline TO cast (FROM* var) { return static_cast(const_cast*>(var)); }
258 2224           template static inline TO upgrade (FROM* var) { return panda::dyn_cast(var); }
259             };
260              
261             struct ObjectTypeSharedPtr {
262             template static inline T in (void* p) { return *(static_cast(p)); }
263             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             template static inline void destroy (const std::shared_ptr&, SV* arg) {
278             using sp_t = std::shared_ptr;
279             void* p = Typemap::IStorage::get(arg);
280             delete static_cast(p);
281             }
282              
283             template static inline TO cast (const std::shared_ptr& var) {
284             return std::static_pointer_cast(std::const_pointer_cast>(var));
285             }
286              
287             template static inline TO upgrade (const std::shared_ptr& var) {
288             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 976           static TYPE in (SV* arg) {
302 976 50         if (!SvOBJECT(arg)) {
    50          
303 976 50         if (SvROK(arg)) {
    50          
304 976           arg = SvRV(arg);
305 976 50         if (!SvOBJECT(arg)) throw "arg is a reference to non-object";
    50          
306             }
307 0 0         else if (!SvOK(arg)) return TYPE();
    0          
    0          
    0          
    0          
    0          
308 0           else throw "arg is not a reference to object";
309             }
310              
311 976 50         auto ptr = IStorage::get(arg);
    50          
312 976 50         if (ptr) {
    50          
313 976           TYPEMAP downgraded = IType::template in(ptr);
314 976 50         TYPE ret = cast(downgraded);
    50          
315 976 50         if (ret) {
    50          
316 972 50         if (!std::is_const::value && SvREADONLY(arg)) throw "cannot modify read-only object";
317 976           return ret;
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 0           auto package = Typemap::package();
324 0           auto package_view = panda::string_view{ package.data(), package.length() };
325 976           typemap::object::_throw_incorrect_arg(arg, typeid (TYPE), package_view);
326             }
327              
328 272           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 136           static Sv create (const TYPE& var, const Sv& proto = Sv()) {
344 136 50         if (!var) return &PL_sv_undef;
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
345 272           Sv rv;
346             SV* base;
347 136 50         if (proto) {
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
348 134 50         if (SvROK(proto)) { // ref to object/base
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
349 0 0         rv = proto;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
350 0           base = SvRV(proto);
351             }
352 134 50         else if (proto.type() <= SVt_PVMG) { // class name
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
353 115 50         if (SvOBJECT(proto)) {
    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          
356             } else {
357 115 50         base = newSV_type(SVt_PVMG);
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
358 115 50         rv = Sv::noinc(newRV_noinc(base));
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
359 115 50         sv_bless(rv, gv_stashsv(proto, GV_ADD));
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
360             }
361 115           goto ATTACH; // skip optional blessing
362             }
363 19 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          
    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          
    50          
    50          
    50          
    50          
    0          
    50          
    50          
    50          
    50          
364 19 0         base = newSV_type(SVt_PVMG);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
365 19 0         rv = Sv::noinc(newRV_noinc(base));
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
366 19 0         sv_bless(rv, proto.get());
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
367 19           goto ATTACH; // skip optional blessing
368             }
369             else { // base given
370 0 0         rv = Sv::noinc(newRV(proto));
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
371 0           base = proto;
372             }
373             }
374             else { // nothing given, create ref to undef
375 2 0         base = newSV_type(SVt_PVMG);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
376 2 0         rv = Sv::noinc(newRV_noinc(base));
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
377 2           goto BLESS; // definitely needs blessing
378             }
379              
380 0 0         if (!SvOBJECT(base)) { // not blessed -> bless to default typemap's class
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
381             BLESS:
382 2 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          
    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          
    0          
383 2 0         sv_bless(rv, stash); // TODO: custom faster bless
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
384             }
385              
386             ATTACH:
387 136 50         IStorage::set(base, const_cast(IType::out(IType::template cast(var))));
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
388              
389             if (std::is_const::value) SvREADONLY_on(base);
390              
391 136           return rv;
392             }
393              
394             static TYPEMAP dup (const TYPEMAP& obj) { return obj; }
395              
396 136           static void dispose (const TYPE& var, SV* arg) {
397 136           IType::destroy(var, arg);
398 136           }
399              
400             static void destroy (const TYPE& var, SV* arg) {
401             if (!std::is_same::value) return;
402             if (!IStorage::auto_disposable) dispose(var, arg);
403             }
404              
405 1112 50         template static inline TO cast (FROM v) { return _cast(v, CastType()); }
    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 2224           template static inline TO _cast (FROM v, DynamicCast) { return IType::template upgrade(v); }
416             template static inline TO _cast (FROM v, StaticCast) { return IType::template cast(v); }
417             };
418              
419             }