X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=xs-src%2FMouseAccessor.xs;h=998849a40eeb8f63e36145a8ca27da3b8b4e7191;hb=53142eda803bb80d2a4edb8b8c264a40390abf4b;hp=d3d046aa01d747deae0d53995821fea5c87ce1b7;hpb=fc65056916e1380327d40cce9e4fe06e4a97eae3;p=gitmo%2FMouse.git diff --git a/xs-src/MouseAccessor.xs b/xs-src/MouseAccessor.xs index d3d046a..998849a 100644 --- a/xs-src/MouseAccessor.xs +++ b/xs-src/MouseAccessor.xs @@ -14,16 +14,87 @@ static MGVTBL mouse_accessor_vtbl; /* MAGIC identity */ #define dMOUSE_self SV* const self = mouse_accessor_get_self(aTHX_ ax, items, cv) +/* simple instance slot accessor (or Mouse::Meta::Instance) */ + +SV* +mouse_instance_create(pTHX_ HV* const stash) { + SV* instance; + assert(stash); + assert(SvTYPE(stash) == SVt_PVHV); + instance = sv_bless( newRV_noinc((SV*)newHV()), stash ); + return sv_2mortal(instance); +} + +SV* +mouse_instance_clone(pTHX_ SV* const instance) { + SV* proto; + CHECK_INSTANCE(instance); + assert(SvOBJECT(SvRV(instance))); + + proto = newRV_noinc((SV*)newHVhv((HV*)SvRV(instance))); + sv_bless(proto, SvSTASH(SvRV(instance))); + return sv_2mortal(proto); +} + +bool +mouse_instance_has_slot(pTHX_ SV* const instance, SV* const slot) { + assert(slot); + CHECK_INSTANCE(instance); + return hv_exists_ent((HV*)SvRV(instance), slot, 0U); +} + +SV* +mouse_instance_get_slot(pTHX_ SV* const instance, SV* const slot) { + HE* he; + assert(slot); + CHECK_INSTANCE(instance); + he = hv_fetch_ent((HV*)SvRV(instance), slot, FALSE, 0U); + return he ? HeVAL(he) : NULL; +} + +SV* +mouse_instance_set_slot(pTHX_ SV* const instance, SV* const slot, SV* const value) { + HE* he; + SV* sv; + assert(slot); + assert(value); + CHECK_INSTANCE(instance); + he = hv_fetch_ent((HV*)SvRV(instance), slot, TRUE, 0U); + sv = HeVAL(he); + sv_setsv(sv, value); + SvSETMAGIC(sv); + return sv; +} + +SV* +mouse_instance_delete_slot(pTHX_ SV* const instance, SV* const slot) { + assert(instance); + assert(slot); + CHECK_INSTANCE(instance); + return hv_delete_ent((HV*)SvRV(instance), slot, 0, 0U); +} + +void +mouse_instance_weaken_slot(pTHX_ SV* const instance, SV* const slot) { + HE* he; + assert(slot); + CHECK_INSTANCE(instance); + he = hv_fetch_ent((HV*)SvRV(instance), slot, FALSE, 0U); + if(he){ + sv_rvweaken(HeVAL(he)); + } +} + +/* utilities */ + STATIC_INLINE SV* mouse_accessor_get_self(pTHX_ I32 const ax, I32 const items, CV* const cv) { if(items < 1){ croak("Too few arguments for %s", GvNAME(CvGV(cv))); } - /* NOTE: If self has GETMAGIC, $self->accessor will invoke GETMAGIC - * before calling methods, so SvGETMAGIC(self) is not necessarily needed here. + * before calling methods, so SvGETMAGIC(self) is not required here. */ - return ST(0); } @@ -37,12 +108,14 @@ mouse_accessor_generate(pTHX_ SV* const attr, XSUBADDR_t const accessor_impl){ xsub = newXS(NULL, accessor_impl, __FILE__); sv_2mortal((SV*)xsub); - mg = sv_magicext((SV*)xsub, MOUSE_xa_slot(xa), PERL_MAGIC_ext, &mouse_accessor_vtbl, (char*)xa, HEf_SVKEY); + mg = sv_magicext((SV*)xsub, MOUSE_xa_slot(xa), + PERL_MAGIC_ext, &mouse_accessor_vtbl, (char*)xa, HEf_SVKEY); MOUSE_mg_flags(mg) = (U16)MOUSE_xa_flags(xa); /* NOTE: - * although we use MAGIC for gc, we also store mg to CvXSUBANY for efficiency (gfx) + * although we use MAGIC for gc, we also store mg to + * CvXSUBANY for efficiency (gfx) */ CvXSUBANY(xsub).any_ptr = (void*)mg; @@ -50,17 +123,6 @@ mouse_accessor_generate(pTHX_ SV* const attr, XSUBADDR_t const accessor_impl){ } -#define PUSH_VALUE(value, flags) STMT_START { \ - if((flags) & MOUSEf_ATTR_SHOULD_AUTO_DEREF && GIMME_V == G_ARRAY){ \ - mouse_push_values(aTHX_ value, (flags)); \ - } \ - else{ \ - dSP; \ - XPUSHs(value ? value : &PL_sv_undef); \ - PUTBACK; \ - } \ - } STMT_END \ - /* pushes return values, does auto-deref if needed */ static void mouse_push_values(pTHX_ SV* const value, U16 const flags){ @@ -111,7 +173,19 @@ mouse_push_values(pTHX_ SV* const value, U16 const flags){ PUTBACK; } -static void +STATIC_INLINE void +mouse_push_value(pTHX_ SV* const value, U16 const flags) { + if(flags & MOUSEf_ATTR_SHOULD_AUTO_DEREF && GIMME_V == G_ARRAY){ + mouse_push_values(aTHX_ value, flags); + } + else{ + dSP; + XPUSHs(value ? value : &PL_sv_undef); + PUTBACK; + } +} + +STATIC_INLINE void mouse_attr_get(pTHX_ SV* const self, MAGIC* const mg){ U16 const flags = MOUSE_mg_flags(mg); SV* value; @@ -123,7 +197,7 @@ mouse_attr_get(pTHX_ SV* const self, MAGIC* const mg){ value = mouse_xa_set_default(aTHX_ MOUSE_mg_xa(mg), self); } - PUSH_VALUE(value, flags); + mouse_push_value(aTHX_ value, flags); } static void @@ -163,7 +237,7 @@ mouse_attr_set(pTHX_ SV* const self, MAGIC* const mg, SV* value){ assert(SvTYPE(value) != SVTYPEMASK); } - PUSH_VALUE(value, flags); + mouse_push_value(aTHX_ value, flags); } XS(XS_Mouse_accessor) @@ -183,7 +257,8 @@ XS(XS_Mouse_accessor) } else{ mouse_throw_error(MOUSE_mg_attribute(mg), NULL, - "Expected exactly one or two argument for an accessor"); + "Expected exactly one or two argument for an accessor of %"SVf, + MOUSE_mg_slot(mg)); } } @@ -196,7 +271,8 @@ XS(XS_Mouse_reader) if (items != 1) { mouse_throw_error(MOUSE_mg_attribute(mg), NULL, - "Cannot assign a value to a read-only accessor"); + "Cannot assign a value to a read-only accessor of %"SVf, + MOUSE_mg_slot(mg)); } SP -= items; /* PPCODE */ @@ -213,7 +289,8 @@ XS(XS_Mouse_writer) if (items != 2) { mouse_throw_error(MOUSE_mg_attribute(mg), NULL, - "Too few arguments for a write-only accessor"); + "Too few arguments for a write-only accessor of %"SVf, + MOUSE_mg_slot(mg)); } SP -= items; /* PPCODE */ @@ -232,24 +309,29 @@ mouse_accessor_get_mg(pTHX_ CV* const xsub){ */ CV* -mouse_simple_accessor_generate(pTHX_ const char* const fq_name, const char* const key, I32 const keylen, XSUBADDR_t const accessor_impl, void* const dptr, I32 const dlen){ +mouse_simple_accessor_generate(pTHX_ + const char* const fq_name, const char* const key, I32 const keylen, + XSUBADDR_t const accessor_impl, void* const dptr, I32 const dlen) { CV* const xsub = newXS((char*)fq_name, accessor_impl, __FILE__); SV* const slot = newSVpvn_share(key, keylen, 0U); MAGIC* mg; if(!fq_name){ - /* anonymous xsubs need sv_2mortal */ + /* anonymous xsubs need sv_2mortal() */ sv_2mortal((SV*)xsub); } - mg = sv_magicext((SV*)xsub, slot, PERL_MAGIC_ext, &mouse_accessor_vtbl, (char*)dptr, dlen); + mg = sv_magicext((SV*)xsub, slot, + PERL_MAGIC_ext, &mouse_accessor_vtbl, (char*)dptr, dlen); + SvREFCNT_dec(slot); /* sv_magicext() increases refcnt in mg_obj */ if(dlen == HEf_SVKEY){ SvREFCNT_dec(dptr); } /* NOTE: - * although we use MAGIC for gc, we also store mg to CvXSUBANY for efficiency (gfx) + * although we use MAGIC for gc, we also store mg to CvXSUBANY + * for efficiency (gfx) */ CvXSUBANY(xsub).any_ptr = (void*)mg; @@ -264,7 +346,8 @@ XS(XS_Mouse_simple_reader) SV* value; if (items != 1) { - croak("Expected exactly one argument for a reader for '%"SVf"'", MOUSE_mg_slot(mg)); + croak("Expected exactly one argument for a reader of %"SVf, + MOUSE_mg_slot(mg)); } value = get_slot(self, MOUSE_mg_slot(mg)); @@ -291,7 +374,8 @@ XS(XS_Mouse_simple_writer) SV* const slot = MOUSE_mg_slot((MAGIC*)XSANY.any_ptr); if (items != 2) { - croak("Expected exactly two argument for a writer for '%"SVf"'", slot); + croak("Expected exactly two argument for a writer of %"SVf, + slot); } ST(0) = set_slot(self, slot, ST(1)); @@ -306,7 +390,8 @@ XS(XS_Mouse_simple_clearer) SV* value; if (items != 1) { - croak("Expected exactly one argument for a clearer for '%"SVf"'", slot); + croak("Expected exactly one argument for a clearer of %"SVf, + slot); } value = delete_slot(self, slot); @@ -321,83 +406,66 @@ XS(XS_Mouse_simple_predicate) SV* const slot = MOUSE_mg_slot((MAGIC*)XSANY.any_ptr); if (items != 1) { - croak("Expected exactly one argument for a predicate for '%"SVf"'", slot); + croak("Expected exactly one argument for a predicate of %"SVf, slot); } ST(0) = boolSV( has_slot(self, slot) ); XSRETURN(1); } -/* simple instance slot accessor (or Mouse::Meta::Instance) */ - -SV* -mouse_instance_create(pTHX_ HV* const stash) { - SV* instance; - assert(stash); - assert(SvTYPE(stash) == SVt_PVHV); - instance = sv_bless( newRV_noinc((SV*)newHV()), stash ); - return sv_2mortal(instance); -} - -SV* -mouse_instance_clone(pTHX_ SV* const instance) { - SV* proto; - CHECK_INSTANCE(instance); - assert(SvOBJECT(SvRV(instance))); - - proto = newRV_noinc((SV*)newHVhv((HV*)SvRV(instance))); - sv_bless(proto, SvSTASH(SvRV(instance))); - return sv_2mortal(proto); -} - -bool -mouse_instance_has_slot(pTHX_ SV* const instance, SV* const slot) { - assert(slot); - CHECK_INSTANCE(instance); - return hv_exists_ent((HV*)SvRV(instance), slot, 0U); -} +/* Class::Data::Inheritable-like class accessor */ +XS(XS_Mouse_inheritable_class_accessor) { + dVAR; dXSARGS; + dMOUSE_self; + SV* const slot = MOUSE_mg_slot((MAGIC*)XSANY.any_ptr); + SV* value; + HV* stash; -SV* -mouse_instance_get_slot(pTHX_ SV* const instance, SV* const slot) { - HE* he; - assert(slot); - CHECK_INSTANCE(instance); - he = hv_fetch_ent((HV*)SvRV(instance), slot, FALSE, 0U); - return he ? HeVAL(he) : NULL; -} + if(items == 1){ /* reader */ + value = NULL; + } + else if (items == 2){ /* writer */ + value = ST(1); + } + else{ + croak("Expected exactly one or two argument for a class data accessor" + "of %"SVf, slot); + value = NULL; /* -Wuninitialized */ + } -SV* -mouse_instance_set_slot(pTHX_ SV* const instance, SV* const slot, SV* const value) { - HE* he; - SV* sv; - assert(slot); - assert(value); - CHECK_INSTANCE(instance); - he = hv_fetch_ent((HV*)SvRV(instance), slot, TRUE, 0U); - sv = HeVAL(he); - sv_setsv(sv, value); - SvSETMAGIC(sv); - return sv; -} + stash = mouse_get_namespace(aTHX_ self); + + if(!value) { /* reader */ + value = get_slot(self, slot); + if(!value) { + AV* const isa = mro_get_linear_isa(stash); + I32 const len = av_len(isa) + 1; + I32 i; + for(i = 1; i < len; i++) { + SV* const klass = MOUSE_av_at(isa, i); + SV* const meta = get_metaclass(klass); + if(!SvOK(meta)){ + continue; /* skip non-Mouse classes */ + } + value = get_slot(meta, slot); + if(value) { + break; + } + } + if(!value) { + value = &PL_sv_undef; + } + } + } + else { /* writer */ + set_slot(self, slot, value); + mro_method_changed_in(stash); + } -SV* -mouse_instance_delete_slot(pTHX_ SV* const instance, SV* const slot) { - assert(instance); - assert(slot); - CHECK_INSTANCE(instance); - return hv_delete_ent((HV*)SvRV(instance), slot, 0, 0U); + ST(0) = value; + XSRETURN(1); } -void -mouse_instance_weaken_slot(pTHX_ SV* const instance, SV* const slot) { - HE* he; - assert(slot); - CHECK_INSTANCE(instance); - he = hv_fetch_ent((HV*)SvRV(instance), slot, FALSE, 0U); - if(he){ - sv_rvweaken(HeVAL(he)); - } -} MODULE = Mouse::Meta::Method::Accessor::XS PACKAGE = Mouse::Meta::Method::Accessor::XS