forked from nothingmuch/xs-object-magic
/
Magic.xs
225 lines (180 loc) · 4.67 KB
/
Magic.xs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#include "xs_object_magic.h"
STATIC MGVTBL null_mg_vtbl = {
NULL, /* get */
NULL, /* set */
NULL, /* len */
NULL, /* clear */
NULL, /* free */
#if MGf_COPY
NULL, /* copy */
#endif /* MGf_COPY */
#if MGf_DUP
NULL, /* dup */
#endif /* MGf_DUP */
#if MGf_LOCAL
NULL, /* local */
#endif /* MGf_LOCAL */
};
void xs_object_magic_attach_struct (pTHX_ SV *sv, void *ptr) {
sv_magicext(sv, NULL, PERL_MAGIC_ext, &null_mg_vtbl, ptr, 0 );
}
int xs_object_magic_detach_struct (pTHX_ SV *sv, void *ptr) {
MAGIC *mg, *prevmagic, *moremagic = NULL;
int removed = 0;
if (SvTYPE(sv) < SVt_PVMG)
return 0;
/* find our magic, remembering the magic before and the magic after */
for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic) {
moremagic = mg->mg_moremagic;
if (mg->mg_type == PERL_MAGIC_ext &&
mg->mg_virtual == &null_mg_vtbl &&
( ptr == NULL || mg->mg_ptr == ptr )) {
if(prevmagic != NULL) {
prevmagic->mg_moremagic = moremagic;
}
else {
SvMAGIC_set(sv, moremagic);
}
mg->mg_moremagic = NULL;
Safefree(mg);
mg = prevmagic;
removed++;
}
}
return removed;
}
int xs_object_magic_detach_struct_rv (pTHX_ SV *sv, void *ptr){
if(sv && SvROK(sv)) {
sv = SvRV(sv);
return xs_object_magic_detach_struct(aTHX_ sv, ptr);
}
return 0;
}
SV *xs_object_magic_create (pTHX_ void *ptr, HV *stash) {
HV *hv = newHV();
SV *obj = newRV_noinc((SV *)hv);
sv_bless(obj, stash);
xs_object_magic_attach_struct(aTHX_ (SV *)hv, ptr);
return obj;
}
MAGIC *xs_object_magic_get_mg (pTHX_ SV *sv) {
MAGIC *mg;
if (SvTYPE(sv) >= SVt_PVMG) {
for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
if (
(mg->mg_type == PERL_MAGIC_ext)
&&
(mg->mg_virtual == &null_mg_vtbl)
) {
return mg;
}
}
}
return NULL;
}
int xs_object_magic_has_struct (pTHX_ SV *sv) {
MAGIC *mg = xs_object_magic_get_mg(aTHX_ sv);
return mg ? 1 : 0;
}
int xs_object_magic_has_struct_rv (pTHX_ SV *sv) {
if( sv && SvROK(sv) ){
sv = SvRV(sv);
MAGIC *mg = xs_object_magic_get_mg(aTHX_ sv);
return mg ? 1 : 0;
}
return 0;
}
void *xs_object_magic_get_struct (pTHX_ SV *sv) {
MAGIC *mg = xs_object_magic_get_mg(aTHX_ sv);
if ( mg )
return mg->mg_ptr;
else
return NULL;
}
void *xs_object_magic_get_struct_rv_pretty (pTHX_ SV *sv, const char *name) {
if ( sv && SvROK(sv) ) {
MAGIC *mg = xs_object_magic_get_mg(aTHX_ SvRV(sv));
if ( mg )
return mg->mg_ptr;
else
croak("%s does not have a struct associated with it", name);
} else {
croak("%s is not a reference", name);
}
}
void *xs_object_magic_get_struct_rv (pTHX_ SV *sv) {
return xs_object_magic_get_struct_rv_pretty(aTHX_ sv, "argument");
}
/* stuff for the test follows */
typedef struct {
I32 i;
} _xs_magic_object_test_t;
static I32 destroyed = 0;
static _xs_magic_object_test_t *test_new () {
_xs_magic_object_test_t *t;
Newx(t, 1, _xs_magic_object_test_t);
t->i = 0;
return t;
}
static int test_count (_xs_magic_object_test_t *t) {
return ++t->i;
}
static void test_DESTROY (_xs_magic_object_test_t *t) {
Safefree(t);
destroyed++;
}
MODULE = XS::Object::Magic PACKAGE = XS::Object::Magic::Test PREFIX = test_
PROTOTYPES: DISABLE
SV *
new(char *class)
CODE:
RETVAL = xs_object_magic_create(aTHX_ (void *)test_new(), gv_stashpv(class, 0));
OUTPUT: RETVAL
I32
test_count (self)
_xs_magic_object_test_t *self;
void
test_has (self)
SV *self;
PPCODE:
if (xs_object_magic_has_struct_rv(aTHX_ self))
XSRETURN_YES;
XSRETURN_NO;
void
test_attach_again (self)
SV *self
void *s = xs_object_magic_get_struct_rv(aTHX_ self);
CODE:
xs_object_magic_attach_struct(aTHX_ SvRV(self), s );
int
test_detach_null (self)
SV *self;
CODE:
RETVAL = xs_object_magic_detach_struct_rv(aTHX_ self, NULL);
OUTPUT: RETVAL
int
test_detach_struct (self)
SV *self;
void *s = xs_object_magic_get_struct_rv(aTHX_ self);
CODE:
RETVAL = xs_object_magic_detach_struct_rv(aTHX_ self, s);
OUTPUT: RETVAL
int
test_detach_garbage (self)
SV *self;
void *s = (void *) 0x123456;
CODE:
RETVAL = xs_object_magic_detach_struct_rv(aTHX_ self, s);
OUTPUT: RETVAL
void
test_DESTROY (self)
_xs_magic_object_test_t *self;
I32
destroyed ()
CODE:
RETVAL = destroyed;
OUTPUT: RETVAL