Fix a memory leak
[gitmo/Class-MOP.git] / xs / MethodAccessor.xs
CommitLineData
206860b8 1#include "mop.h"
2
e989c0df 3
4static MGVTBL mop_accessor_vtbl; /* the MAGIC identity */
5
6MAGIC*
7mop_accessor_get_mg(pTHX_ CV* const xsub){
8 return mop_mg_find(aTHX_ (SV*)xsub, &mop_accessor_vtbl, MOPf_DIE_ON_FAIL);
9}
10
11CV*
12mop_install_accessor(pTHX_ const char* const fq_name, const char* const key, I32 const keylen, XSPROTO(accessor_impl), const mop_instance_vtbl* vtbl){
13 CV* const xsub = newXS((char*)fq_name, accessor_impl, __FILE__);
14 SV* const keysv = newSVpvn_share(key, keylen, 0U);
15 AV* const meta = newAV();
d83eddd0 16 MAGIC* mg;
e989c0df 17
18 if(!vtbl){
19 vtbl = mop_get_default_instance_vtbl(aTHX);
20 }
21
616d909b 22 if(!fq_name){
23 /* generated_xsub need sv_2mortal */
24 sv_2mortal((SV*)xsub);
25 }
26
d83eddd0 27 mg = sv_magicext((SV*)xsub, (SV*)meta, PERL_MAGIC_ext, &mop_accessor_vtbl, (char*)vtbl, 0);
e989c0df 28 SvREFCNT_dec(meta); /* sv_magicext() increases refcnt in mg_obj */
29
d83eddd0 30 av_store(meta, MOP_MI_SLOT, keysv);
31
32 /* NOTE:
33 * although we use MAGIC for gc, we also store mg to any slot for efficiency (gfx)
34 */
35 CvXSUBANY(xsub).any_ptr = (void*)mg;
e989c0df 36
37 return xsub;
38}
39
40
206860b8 41static CV*
e989c0df 42mop_instantiate_xs_accessor(pTHX_ SV* const accessor, XSPROTO(accessor_impl), mop_instance_vtbl* const vtbl){
43 /* $key = $accessor->associated_attribute->name */
44 SV* const attr = mop_call0(aTHX_ accessor, mop_associated_attribute);
45 SV* const key = mop_call0(aTHX_ attr, mop_name);
46 STRLEN klen;
47 const char* const kpv = SvPV_const(key, klen);
48
49 return mop_install_accessor(aTHX_ NULL /* anonymous */, kpv, klen, accessor_impl, vtbl);
50}
51
52SV*
53mop_accessor_get_self(pTHX_ I32 const ax, I32 const items, CV* const cv) {
54 SV* self;
55
56 if(items < 1){
57 croak("too few arguments for %s", GvNAME(CvGV(cv)));
58 }
59
60 self = ST(0);
61 if(!(SvROK(self) && SvOBJECT(SvRV(self)))){
62 croak("cant call %s as a class method", GvNAME(CvGV(cv)));
63 }
64 return self;
65}
66
d83eddd0 67#ifdef DEBUGGING
68SV**
69mop_debug_mi_access(pTHX_ AV* const mi, I32 const attr_ix){
70 assert(mi);
71 assert(SvTYPE(mi) == SVt_PVAV);
72 assert(AvMAX(mi) >= attr_ix);
73 return &AvARRAY(mi)[attr_ix];
74}
75#endif
76
e989c0df 77XS(mop_xs_simple_accessor)
78{
79 dVAR; dXSARGS;
80 dMOP_METHOD_COMMON; /* self, mg */
81 SV* value;
d83eddd0 82
e989c0df 83 if(items == 1){ /* reader */
d83eddd0 84 value = MOP_mg_get_slot(mg, self);
e989c0df 85 }
86 else if (items == 2){ /* writer */
d83eddd0 87 value = MOP_mg_set_slot(mg, self, ST(1));
e989c0df 88 }
89 else{
90 croak("expected exactly one or two argument");
91 }
92
93 ST(0) = value ? value : &PL_sv_undef;
94 XSRETURN(1);
95}
96
97
98XS(mop_xs_simple_reader)
99{
100 dVAR; dXSARGS;
101 dMOP_METHOD_COMMON; /* self, mg */
102 SV* value;
103
104 if (items != 1) {
105 croak("expected exactly one argument");
106 }
107
d83eddd0 108 value = MOP_mg_get_slot(mg, self);
e989c0df 109 ST(0) = value ? value : &PL_sv_undef;
110 XSRETURN(1);
111}
112
113XS(mop_xs_simple_writer)
114{
115 dVAR; dXSARGS;
116 dMOP_METHOD_COMMON; /* self, mg */
117
118 if (items != 2) {
119 croak("expected exactly two argument");
120 }
121
d83eddd0 122 ST(0) = MOP_mg_set_slot(mg, self, ST(1));
e989c0df 123 XSRETURN(1);
124}
125
126XS(mop_xs_simple_clearer)
127{
128 dVAR; dXSARGS;
129 dMOP_METHOD_COMMON; /* self, mg */
130 SV* value;
131
132 if (items != 1) {
133 croak("expected exactly one argument");
134 }
135
d83eddd0 136 value = MOP_mg_delete_slot(mg, self);
e989c0df 137 ST(0) = value ? value : &PL_sv_undef;
138 XSRETURN(1);
139}
140
141
142XS(mop_xs_simple_predicate)
143{
144 dVAR; dXSARGS;
145 dMOP_METHOD_COMMON; /* self, mg */
146
147 if (items != 1) {
148 croak("expected exactly one argument");
149 }
150
d83eddd0 151 ST(0) = boolSV( MOP_mg_has_slot(mg, self) );
e989c0df 152 XSRETURN(1);
153}
154
155
156XS(mop_xs_simple_predicate_for_metaclass)
157{
158 dVAR; dXSARGS;
159 dMOP_METHOD_COMMON; /* self, mg */
160 SV* value;
161
162 if (items != 1) {
163 croak("expected exactly one argument");
164 }
165
d83eddd0 166 value = MOP_mg_get_slot(mg, self);
e989c0df 167 ST(0) = boolSV( value && SvOK(value ));
168 XSRETURN(1);
206860b8 169}
170
171MODULE = Class::MOP::Method::Accessor PACKAGE = Class::MOP::Method::Accessor
172
173PROTOTYPES: DISABLE
174
175BOOT:
176 INSTALL_SIMPLE_READER_WITH_KEY(Method::Accessor, associated_attribute, attribute);
177 INSTALL_SIMPLE_READER(Method::Accessor, accessor_type);
178
179
180CV*
e989c0df 181_generate_accessor_method_xs(SV* self, void* instance_vtbl)
206860b8 182CODE:
e989c0df 183 RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_accessor, instance_vtbl);
206860b8 184OUTPUT:
185 RETVAL
186
187CV*
e989c0df 188_generate_reader_method_xs(SV* self, void* instance_vtbl)
206860b8 189CODE:
e989c0df 190 RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_reader, instance_vtbl);
206860b8 191OUTPUT:
192 RETVAL
193
194CV*
e989c0df 195_generate_writer_method_xs(SV* self, void* instance_vtbl)
206860b8 196CODE:
e989c0df 197 RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_writer, instance_vtbl);
206860b8 198OUTPUT:
199 RETVAL
200
201CV*
e989c0df 202_generate_predicate_method_xs(SV* self, void* instance_vtbl)
206860b8 203CODE:
e989c0df 204 RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_predicate, instance_vtbl);
206860b8 205OUTPUT:
206 RETVAL
207
208CV*
e989c0df 209_generate_clearer_method_xs(SV* self, void* instance_vtbl)
206860b8 210CODE:
e989c0df 211 RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_clearer, instance_vtbl);
206860b8 212OUTPUT:
213 RETVAL
214