diff options
author | Nicholas Clark <nick@ccl4.org> | 2008-12-26 18:26:53 +0000 |
---|---|---|
committer | Nicholas Clark <nick@ccl4.org> | 2008-12-27 21:12:12 +0000 |
commit | a3e6e81e81213c31f0612471c427044481a95287 (patch) | |
tree | ee301f51042968614e037f30ee494f770446607d /mro.c | |
parent | 123892d916359369839f3896f283189be71dc32c (diff) | |
download | perl-a3e6e81e81213c31f0612471c427044481a95287.tar.gz |
Add Perl_mro_register() to register Method Resolution Orders,
Perl_mro_get_from_name() to retrieve MROs by name, and PL_registered_mros to
store them in. Abolish the static array of mros, and instead register the dfs
and c3 MRO structures.
Diffstat (limited to 'mro.c')
-rw-r--r-- | mro.c | 73 |
1 files changed, 44 insertions, 29 deletions
@@ -35,16 +35,12 @@ struct mro_alg { U32 hash; /* or 0 */ }; -/* First one is the default */ -static struct mro_alg mros[] = { - {S_mro_get_linear_isa_dfs, "dfs", 3, 0, 0}, - {S_mro_get_linear_isa_c3, "c3", 2, 0, 0} -}; +static const struct mro_alg dfs_alg = + {S_mro_get_linear_isa_dfs, "dfs", 3, 0, 0}; -#define NUMBER_OF_MROS (sizeof(mros)/sizeof(struct mro_alg)) +static const struct mro_alg c3_alg = + {S_mro_get_linear_isa_c3, "c3", 2, 0, 0}; -#define dfs_alg (&mros[0]) -#define c3_alg (&mros[1]) SV * Perl_mro_get_private_data(pTHX_ struct mro_meta *const smeta, @@ -96,16 +92,35 @@ Perl_mro_set_private_data(pTHX_ struct mro_meta *const smeta, return data; } -static const struct mro_alg * -S_get_mro_from_name(pTHX_ const char *const name) { - const struct mro_alg *algo = mros; - const struct mro_alg *const end = mros + NUMBER_OF_MROS; - while (algo < end) { - if(strEQ(name, algo->name)) - return algo; - ++algo; +const struct mro_alg * +Perl_mro_get_from_name(pTHX_ SV *name) { + SV **data; + + PERL_ARGS_ASSERT_MRO_GET_FROM_NAME; + + data = Perl_hv_common(aTHX_ PL_registered_mros, name, NULL, 0, 0, + HV_FETCH_JUST_SV, NULL, 0); + if (!data) + return NULL; + assert(SvTYPE(*data) == SVt_IV); + assert(SvIOK(*data)); + return INT2PTR(const struct mro_alg *, SvUVX(*data)); +} + +void +Perl_mro_register(pTHX_ const struct mro_alg *mro) { + SV *wrapper = newSVuv(PTR2UV(mro)); + + PERL_ARGS_ASSERT_MRO_REGISTER; + + + if (!Perl_hv_common(aTHX_ PL_registered_mros, NULL, + mro->name, mro->length, mro->kflags, + HV_FETCH_ISSTORE, wrapper, mro->hash)) { + SvREFCNT_dec(wrapper); + Perl_croak(aTHX_ "panic: hv_store() failed in mro_register() " + "for '%.*s' %d", (int) mro->length, mro->name, mro->kflags); } - return NULL; } struct mro_meta* @@ -120,7 +135,7 @@ Perl_mro_meta_init(pTHX_ HV* stash) HvAUX(stash)->xhv_mro_meta = newmeta; newmeta->cache_gen = 1; newmeta->pkg_gen = 1; - newmeta->mro_which = mros; + newmeta->mro_which = &dfs_alg; return newmeta; } @@ -231,7 +246,7 @@ S_mro_get_linear_isa_dfs(pTHX_ HV *stash, U32 level) meta = HvMROMETA(stash); /* return cache if valid */ - if((retval = MUTABLE_AV(MRO_GET_PRIVATE_DATA(meta, dfs_alg)))) { + if((retval = MUTABLE_AV(MRO_GET_PRIVATE_DATA(meta, &dfs_alg)))) { return retval; } @@ -337,7 +352,7 @@ S_mro_get_linear_isa_dfs(pTHX_ HV *stash, U32 level) and we do so by replacing it completely */ SvREADONLY_on(retval); - return MUTABLE_AV(Perl_mro_set_private_data(aTHX_ meta, dfs_alg, + return MUTABLE_AV(Perl_mro_set_private_data(aTHX_ meta, &dfs_alg, MUTABLE_SV(retval))); } @@ -382,7 +397,7 @@ S_mro_get_linear_isa_c3(pTHX_ HV* stash, U32 level) meta = HvMROMETA(stash); /* return cache if valid */ - if((retval = MUTABLE_AV(MRO_GET_PRIVATE_DATA(meta, c3_alg)))) { + if((retval = MUTABLE_AV(MRO_GET_PRIVATE_DATA(meta, &c3_alg)))) { return retval; } @@ -555,7 +570,7 @@ S_mro_get_linear_isa_c3(pTHX_ HV* stash, U32 level) and we do so by replacing it completely */ SvREADONLY_on(retval); - return MUTABLE_AV(Perl_mro_set_private_data(aTHX_ meta, c3_alg, + return MUTABLE_AV(Perl_mro_set_private_data(aTHX_ meta, &c3_alg, MUTABLE_SV(retval))); return retval; } @@ -826,6 +841,9 @@ Perl_boot_core_mro(pTHX) dVAR; static const char file[] = __FILE__; + Perl_mro_register(aTHX_ &dfs_alg); + Perl_mro_register(aTHX_ &c3_alg); + newXSproto("mro::get_linear_isa", XS_mro_get_linear_isa, file, "$;$"); newXSproto("mro::set_mro", XS_mro_set_mro, file, "$$"); newXSproto("mro::get_mro", XS_mro_get_mro, file, "$"); @@ -858,10 +876,9 @@ XS(XS_mro_get_linear_isa) { XSRETURN(1); } else if(items > 1) { - const char* const which = SvPV_nolen(ST(1)); - const struct mro_alg *const algo = S_get_mro_from_name(aTHX_ which); + const struct mro_alg *const algo = Perl_mro_get_from_name(aTHX_ ST(1)); if (!algo) - Perl_croak(aTHX_ "Invalid mro name: '%s'", which); + Perl_croak(aTHX_ "Invalid mro name: '%"SVf"'", ST(1)); RETVAL = algo->resolve(aTHX_ class_stash, 0); } else { @@ -878,7 +895,6 @@ XS(XS_mro_set_mro) dVAR; dXSARGS; SV* classname; - const char* whichstr; const struct mro_alg *which; HV* class_stash; struct mro_meta* meta; @@ -887,14 +903,13 @@ XS(XS_mro_set_mro) croak_xs_usage(cv, "classname, type"); classname = ST(0); - whichstr = SvPV_nolen(ST(1)); class_stash = gv_stashsv(classname, GV_ADD); if(!class_stash) Perl_croak(aTHX_ "Cannot create class: '%"SVf"'!", SVfARG(classname)); meta = HvMROMETA(class_stash); - which = S_get_mro_from_name(aTHX_ whichstr); + which = Perl_mro_get_from_name(aTHX_ ST(1)); if (!which) - Perl_croak(aTHX_ "Invalid mro name: '%s'", whichstr); + Perl_croak(aTHX_ "Invalid mro name: '%"SVf"'", ST(1)); if(meta->mro_which != which) { meta->mro_which = which; |