From: gfx Date: Sun, 15 Nov 2009 04:33:22 +0000 (+0900) Subject: XS constructor X-Git-Tag: 0.40_06~21 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=gitmo%2FMouse.git;a=commitdiff_plain;h=aa2d2e2c0621cdcb8b2ec7cf49beb3a9de11803c XS constructor --- diff --git a/lib/Mouse/Object.pm b/lib/Mouse/Object.pm index 5f09e0a..0f01499 100644 --- a/lib/Mouse/Object.pm +++ b/lib/Mouse/Object.pm @@ -24,20 +24,6 @@ sub new { return $self; } -sub BUILDARGS { - my $class = shift; - - if (scalar @_ == 1) { - (ref($_[0]) eq 'HASH') - || $class->meta->throw_error("Single parameters to new() must be a HASH ref"); - - return {%{$_[0]}}; - } - else { - return {@_}; - } -} - sub DESTROY { my $self = shift; diff --git a/lib/Mouse/PurePerl.pm b/lib/Mouse/PurePerl.pm index a999394..a6f1be4 100644 --- a/lib/Mouse/PurePerl.pm +++ b/lib/Mouse/PurePerl.pm @@ -337,7 +337,23 @@ sub compile_type_constraint{ return; } +package + Mouse::Object; + + +sub BUILDARGS { + my $class = shift; + if (scalar @_ == 1) { + (ref($_[0]) eq 'HASH') + || $class->meta->throw_error("Single parameters to new() must be a HASH ref"); + + return {%{$_[0]}}; + } + else { + return {@_}; + } +} 1; __END__ diff --git a/mouse.h b/mouse.h index a7a5986..3056eeb 100644 --- a/mouse.h +++ b/mouse.h @@ -72,12 +72,12 @@ bool mouse_is_class_loaded(pTHX_ SV*); #define mcall0s(invocant, m) mcall0((invocant), sv_2mortal(newSVpvs_share(m))) #define mcall1s(invocant, m, arg1) mcall1((invocant), sv_2mortal(newSVpvs_share(m)), (arg1)) -#define get_metaclass_by_name(name) mouse_get_metaclass_by_name(aTHX_ name) +#define get_metaclass(name) mouse_get_metaclass(aTHX_ name) SV* mouse_call0(pTHX_ SV *const self, SV *const method); SV* mouse_call1(pTHX_ SV *const self, SV *const method, SV* const arg1); -SV* mouse_get_metaclass_by_name(pTHX_ SV* const metaclass_name); +SV* mouse_get_metaclass(pTHX_ SV* metaclass_name); GV* mouse_stash_fetch(pTHX_ HV* const stash, const char* const name, I32 const namelen, I32 const create); #define stash_fetch(s, n, l, c) mouse_stash_fetch(aTHX_ (s), (n), (l), (c)) diff --git a/xs-src/Mouse.xs b/xs-src/Mouse.xs index 7580f7a..7cc9f34 100644 --- a/xs-src/Mouse.xs +++ b/xs-src/Mouse.xs @@ -10,13 +10,27 @@ SV* mouse_get_attribute_list; #define MOUSE_xc_gen(a) MOUSE_av_at((a), MOUSE_XC_GEN) +#define MOUSE_xc_stash(a) ( (HV*)MOUSE_av_at((a), MOUSE_XC_STASH) ) #define MOUSE_xc_attrall(a) ( (AV*)MOUSE_av_at((a), MOUSE_XC_ATTRALL) ) #define MOUSE_xc_buildall(a) ( (AV*)MOUSE_av_at((a), MOUSE_XC_BUILDALL) ) #define MOUSE_xc_demolishall(a) ( (AV*)MOUSE_av_at((a), MOUSE_XC_DEOLISHALL) ) +enum mouse_xc_flags_t { + MOUSEf_XC_IS_IMMUTABLE = 0x0001, + MOUSEf_XC_IS_ANON = 0x0002, + MOUSEf_XC_HAS_BUILDARGS = 0x0004, + + MOUSEf_XC_mask = 0xFFFF /* not used */ +}; + /* Mouse XS Metaclass object */ enum mouse_xc_ix_t{ MOUSE_XC_GEN, /* class generation */ + MOUSE_XC_STASH, /* symbol table hash */ + MOUSE_XC_FLAGS, + + MOUSE_XC_BUILDARGS, /* Custom BUILDARGS */ + MOUSE_XC_ATTRALL, /* all the attributes */ MOUSE_XC_BUILDALL, /* all the BUILD methods */ MOUSE_XC_DEMOLISHALL, /* all the DEMOLISH methods */ @@ -53,11 +67,23 @@ mouse_class_push_attribute_list(pTHX_ SV* const metaclass, AV* const attrall, HV } } +static int +mouse_class_has_custom_buildargs(pTHX_ HV* const stash) { + XS(XS_Mouse__Object_BUILDARGS); /* prototype */ + + GV* const buildargs = gv_fetchmeth_autoload(stash, "BUILDARGS", sizeof("BUILDARGS")-1, 0); + CV* const cv = GvCV(buildargs); + + assert(cv); + return CvXSUB(cv) == XS_Mouse__Object_BUILDARGS; +} + static void mouse_class_update_xc(pTHX_ SV* const metaclass PERL_UNUSED_DECL, HV* const stash, AV* const xc) { AV* const linearized_isa = mro_get_linear_isa(stash); I32 const len = AvFILLp(linearized_isa); I32 i; + U32 flags = 0x00; AV* const attrall = newAV(); AV* const buildall = newAV(); AV* const demolishall = newAV(); @@ -78,6 +104,14 @@ mouse_class_update_xc(pTHX_ SV* const metaclass PERL_UNUSED_DECL, HV* const stas /* update */ + if(SvTRUEx( mcall0s(metaclass, "is_immutable") )){ + flags |= MOUSEf_XC_IS_IMMUTABLE; + } + + if(mouse_class_has_custom_buildargs(aTHX_ stash)){ + flags |= MOUSEf_XC_HAS_BUILDARGS; + } + av_store(xc, MOUSE_XC_ATTRALL, (SV*)attrall); av_store(xc, MOUSE_XC_BUILDALL, (SV*)buildall); av_store(xc, MOUSE_XC_DEMOLISHALL, (SV*)demolishall); @@ -98,7 +132,7 @@ mouse_class_update_xc(pTHX_ SV* const metaclass PERL_UNUSED_DECL, HV* const stas } /* ATTRIBUTES */ - meta = get_metaclass_by_name(klass); + meta = get_metaclass(klass); if(!SvOK(meta)){ continue; /* skip non-Mouse classes */ } @@ -126,28 +160,31 @@ mouse_get_xc(pTHX_ SV* const metaclass) { mg = mouse_mg_find(aTHX_ SvRV(metaclass), &mouse_xc_vtbl, 0x00); if(!mg){ SV* const package = get_slot(metaclass, mouse_package); + STRLEN len; + const char* const pv = SvPV_const(package, len); - stash = gv_stashsv(package, TRUE); + stash = gv_stashpvn(pv, len, TRUE); xc = newAV(); - mg = sv_magicext(SvRV(metaclass), (SV*)xc, PERL_MAGIC_ext, &mouse_xc_vtbl, (char*)stash, HEf_SVKEY); + mg = sv_magicext(SvRV(metaclass), (SV*)xc, PERL_MAGIC_ext, &mouse_xc_vtbl, pv, len); SvREFCNT_dec(xc); /* refcnt++ in sv_magicext */ av_extend(xc, MOUSE_XC_last - 1); + av_store(xc, MOUSE_XC_GEN, newSViv(0)); + av_store(xc, MOUSE_XC_STASH, (SV*)stash); + SvREFCNT_inc_simple_void_NN(stash); } else{ - stash = (HV*)MOUSE_mg_ptr(mg); xc = (AV*)MOUSE_mg_obj(mg); - assert(stash); - assert(SvTYPE(stash) == SVt_PVAV); - assert(xc); assert(SvTYPE(xc) == SVt_PVAV); } - gen = MOUSE_xc_gen(xc); + gen = MOUSE_xc_gen(xc); + stash = MOUSE_xc_stash(xc); + if(SvUV(gen) != mro_get_pkg_gen(stash)){ mouse_class_update_xc(aTHX_ metaclass, stash, xc); } @@ -161,6 +198,44 @@ mouse_get_all_attributes(pTHX_ SV* const metaclass) { return MOUSE_xc_attrall(xc); } +HV* +mouse_build_args(aTHX_ SV* metaclass, SV* const klass, I32 const start, I32 const items, I32 const ax) { + HV* args; + if((items - start) == 1){ + SV* const args_ref = ST(start); + if(!IsHashRef(args_ref)){ + if(!metaclass){ metaclass = get_metaclass(klass); } + mouse_throw_error(metaclass, NULL, "Single parameters to new() must be a HASH ref"); + } + args = newHVhv((HV*)SvRV(args_ref)); + sv_2mortal((SV*)args); + } + else{ + I32 i; + + args = newHV(); + sv_2mortal((SV*)args); + + if( ((items - start) % 2) != 0 ){ + if(!metaclass){ metaclass = get_metaclass(klass); } + mouse_throw_error(metaclass, NULL, "Odd number of parameters to new()"); + } + + for(i = start; i < items; i += 2){ + (void)hv_store_ent(args, ST(i), newSVsv(ST(i+1)), 0U); + } + + } + return args; +} + +void +mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const args, bool const invoke_triggers) { + AV* const xc = mouse_get_xc(aTHX_ meta); + + // TODO +} + MODULE = Mouse PACKAGE = Mouse PROTOTYPES: DISABLE @@ -177,6 +252,7 @@ BOOT: MOUSE_CALL_BOOT(Mouse__Util); MOUSE_CALL_BOOT(Mouse__Util__TypeConstraints); MOUSE_CALL_BOOT(Mouse__Meta__Method__Accessor__XS); + MOUSE_CALL_BOOT(Mouse__Meta__Attribute); MODULE = Mouse PACKAGE = Mouse::Meta::Module @@ -293,53 +369,38 @@ PPCODE: } } +SV* +new_object_(SV* meta, ...) +CODE: +{ + HV* const args = mouse_build_args(aTHX_ meta, NULL, 1, items, ax); + AV* const xc = mouse_get_xc(aTHX_ meta); + RETVAL = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc)); + mouse_class_initialize_object(aTHX_ meta, RETVAL, args, TRUE); +} + + +void +_initialize_object_(SV* meta, SV* object, HV* args, bool invoke_triggers = TRUE) +CODE: +{ + mouse_class_initialize_object(aTHX_ meta, object, args, invoke_triggers); +} + MODULE = Mouse PACKAGE = Mouse::Meta::Role BOOT: INSTALL_SIMPLE_READER_WITH_KEY(Role, get_roles, roles); INSTALL_SIMPLE_PREDICATE_WITH_KEY(Role, is_anon_role, anon_serial_id); -MODULE = Mouse PACKAGE = Mouse::Meta::Attribute +MODULE = Mouse PACKAGE = Mouse::Object -BOOT: - /* readers */ - INSTALL_SIMPLE_READER(Attribute, name); - INSTALL_SIMPLE_READER(Attribute, associated_class); - INSTALL_SIMPLE_READER(Attribute, accessor); - INSTALL_SIMPLE_READER(Attribute, reader); - INSTALL_SIMPLE_READER(Attribute, writer); - INSTALL_SIMPLE_READER(Attribute, predicate); - INSTALL_SIMPLE_READER(Attribute, clearer); - INSTALL_SIMPLE_READER(Attribute, handles); - - INSTALL_SIMPLE_READER_WITH_KEY(Attribute, _is_metadata, is); - INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_required, required); - INSTALL_SIMPLE_READER(Attribute, default); - INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_lazy, lazy); - INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_lazy_build, lazy_build); - INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_weak_ref, weak_ref); - INSTALL_SIMPLE_READER(Attribute, init_arg); - INSTALL_SIMPLE_READER(Attribute, type_constraint); - INSTALL_SIMPLE_READER(Attribute, trigger); - INSTALL_SIMPLE_READER(Attribute, builder); - INSTALL_SIMPLE_READER_WITH_KEY(Attribute, should_auto_deref, auto_deref); - INSTALL_SIMPLE_READER_WITH_KEY(Attribute, should_coerce, coerce); - INSTALL_SIMPLE_READER(Attribute, documentation); - - /* predicates */ - INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_accessor, accessor); - INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_reader, reader); - INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_writer, writer); - INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_predicate, predicate); - INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_clearer, clearer); - INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_handles, handles); - - INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_default, default); - INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_type_constraint, type_constraint); - INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_trigger, trigger); - INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_builder, builder); - INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_documentation, documentation); - - newCONSTSUB(gv_stashpvs("Mouse::Meta::Attribute", TRUE), "accessor_metaclass", - newSVpvs("Mouse::Meta::Method::Accessor::XS")); +HV* +BUILDARGS(SV* klass, ...) +CODE: +{ + RETVAL = mouse_build_args(aTHX_ NULL, klass, 1, items, ax); +} +OUTPUT: + RETVAL diff --git a/xs-src/MouseAccessor.xs b/xs-src/MouseAccessor.xs index d2ae129..aa87df3 100644 --- a/xs-src/MouseAccessor.xs +++ b/xs-src/MouseAccessor.xs @@ -467,6 +467,7 @@ XS(XS_Mouse_simple_predicate) SV* mouse_instance_create(pTHX_ HV* const stash) { assert(stash); + assert(SvTYPE(stash) == SVt_PVHV); return sv_bless( newRV_noinc((SV*)newHV()), stash ); } diff --git a/xs-src/MouseAttribute.xs b/xs-src/MouseAttribute.xs new file mode 100644 index 0000000..f4d4ea4 --- /dev/null +++ b/xs-src/MouseAttribute.xs @@ -0,0 +1,49 @@ +#define NEED_newSVpvn_flags_GLOBAL +#include "mouse.h" + +MODULE = Mouse::Meta::Attribute PACKAGE = Mouse::Meta::Attribute + +PROTOTYPES: DISABLE + +BOOT: + /* readers */ + INSTALL_SIMPLE_READER(Attribute, name); + INSTALL_SIMPLE_READER(Attribute, associated_class); + INSTALL_SIMPLE_READER(Attribute, accessor); + INSTALL_SIMPLE_READER(Attribute, reader); + INSTALL_SIMPLE_READER(Attribute, writer); + INSTALL_SIMPLE_READER(Attribute, predicate); + INSTALL_SIMPLE_READER(Attribute, clearer); + INSTALL_SIMPLE_READER(Attribute, handles); + + INSTALL_SIMPLE_READER_WITH_KEY(Attribute, _is_metadata, is); + INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_required, required); + INSTALL_SIMPLE_READER(Attribute, default); + INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_lazy, lazy); + INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_lazy_build, lazy_build); + INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_weak_ref, weak_ref); + INSTALL_SIMPLE_READER(Attribute, init_arg); + INSTALL_SIMPLE_READER(Attribute, type_constraint); + INSTALL_SIMPLE_READER(Attribute, trigger); + INSTALL_SIMPLE_READER(Attribute, builder); + INSTALL_SIMPLE_READER_WITH_KEY(Attribute, should_auto_deref, auto_deref); + INSTALL_SIMPLE_READER_WITH_KEY(Attribute, should_coerce, coerce); + INSTALL_SIMPLE_READER(Attribute, documentation); + + /* predicates */ + INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_accessor, accessor); + INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_reader, reader); + INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_writer, writer); + INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_predicate, predicate); + INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_clearer, clearer); + INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_handles, handles); + + INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_default, default); + INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_type_constraint, type_constraint); + INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_trigger, trigger); + INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_builder, builder); + INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_documentation, documentation); + + newCONSTSUB(gv_stashpvs("Mouse::Meta::Attribute", TRUE), "accessor_metaclass", + newSVpvs("Mouse::Meta::Method::Accessor::XS")); + diff --git a/xs-src/MouseTypeConstraints.xs b/xs-src/MouseTypeConstraints.xs index 6f69f2f..741e679 100644 --- a/xs-src/MouseTypeConstraints.xs +++ b/xs-src/MouseTypeConstraints.xs @@ -149,21 +149,11 @@ mouse_tc_RoleName(pTHX_ SV* const data PERL_UNUSED_DECL, SV* const sv) { assert(sv); if(is_class_loaded(sv)){ int ok; - SV* meta; - dSP; ENTER; SAVETMPS; - PUSHMARK(SP); - XPUSHs(sv); - PUTBACK; - call_pv("Mouse::Util::get_metaclass_by_name", G_SCALAR); - SPAGAIN; - meta = POPs; - PUTBACK; - - ok = is_an_instance_of("Mouse::Meta::Role", meta); + ok = is_an_instance_of("Mouse::Meta::Role", get_metaclass(sv)); FREETMPS; LEAVE; diff --git a/xs-src/MouseUtil.xs b/xs-src/MouseUtil.xs index 2e7f50b..c1d4d91 100644 --- a/xs-src/MouseUtil.xs +++ b/xs-src/MouseUtil.xs @@ -197,11 +197,19 @@ mouse_call1 (pTHX_ SV *const self, SV *const method, SV* const arg1) } SV* -mouse_get_metaclass_by_name(pTHX_ SV* const metaclass_name){ +mouse_get_metaclass(pTHX_ SV* metaclass_name){ CV* const get_metaclass = get_cvs("Mouse::Util::get_metaclass_by_name", TRUE); SV* metaclass; dSP; + assert(metaclass_name); + if(IsObject(metaclass_name)){ + HV* const stash = SvSTASH(metaclass_name); + + metaclass_name = newSVpvn_share(HvNAME_get(stash), HvNAMELEN_get(stash), 0U); + sv_2mortal(metaclass_name); + } + PUSHMARK(SP); XPUSHs(metaclass_name); PUTBACK;