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