From: Florian Ragwitz Date: Wed, 11 Mar 2009 03:39:13 +0000 (+0100) Subject: Refactor how prehashed hash keys work. X-Git-Tag: 0.78_01~66 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=22932438751f5ca55563fc133b53f464dedbf3de;p=gitmo%2FClass-MOP.git Refactor how prehashed hash keys work. --- diff --git a/mop.c b/mop.c index 688634d..08e5349 100644 --- a/mop.c +++ b/mop.c @@ -201,3 +201,44 @@ mop_get_all_package_symbols (HV *stash, type_filter_t filter) mop_get_package_symbols (stash, filter, collect_all_symbols, ret); return ret; } + +/* the order of these has to match with those in mop.h */ +static struct { + const char *name; + const char *value; + SV *key; + U32 hash; +} prehashed_keys[key_last] = { + DECLARE_KEY(name), + DECLARE_KEY(package), + DECLARE_KEY(package_name), + DECLARE_KEY(body), + DECLARE_KEY_WITH_VALUE(package_cache_flag, "_package_cache_flag"), + DECLARE_KEY(methods), + DECLARE_KEY(VERSION), + DECLARE_KEY(ISA) +}; + +inline SV * +mop_prehashed_key_for (mop_prehashed_key_t key) +{ + return prehashed_keys[key].key; +} + +inline U32 +mop_prehashed_hash_for (mop_prehashed_key_t key) +{ + return prehashed_keys[key].hash; +} + +void +mop_prehash_keys () +{ + int i; + + for (i = 0; i < key_last; i++) { + const char *value = prehashed_keys[i].value; + prehashed_keys[i].key = newSVpv(value, strlen(value)); + PERL_HASH(prehashed_keys[i].hash, value, strlen(value)); + } +} diff --git a/mop.h b/mop.h index bdbff08..444f8ac 100644 --- a/mop.h +++ b/mop.h @@ -18,24 +18,27 @@ void mop_call_xs (pTHX_ void (*subaddr) (pTHX_ CV *), CV *cv, SV **mark); -#define DECLARE_KEY(name) SV *key_##name; U32 hash_##name; -#define NEEDS_KEY(name) extern SV *key_##name; extern U32 hash_##name; - -#define PREHASH_KEY_WITH_VALUE(name, value) do { \ - key_##name = newSVpvs(value); \ - PERL_HASH(hash_##name, value, sizeof(value) - 1); \ -} while (0) - -/* this is basically the same as the above macro, except that the value will be - * the stringified name. However, we can't just implement this in terms of - * PREHASH_KEY_WITH_VALUE as that'd cause macro expansion on the value of - * 'name' when it's being passed to the other macro. suggestions on how to make - * this more elegant would be much appreciated */ - -#define PREHASH_KEY(name) do { \ - key_##name = newSVpvs(#name); \ - PERL_HASH(hash_##name, #name, sizeof(#name) - 1); \ -} while (0) +#define DECLARE_KEY(name) { #name, #name, NULL, 0 } +#define DECLARE_KEY_WITH_VALUE(name, value) { #name, value, NULL, 0 } + +typedef enum { + KEY_name, + KEY_package, + KEY_package_name, + KEY_body, + KEY_package_cache_flag, + KEY_methods, + KEY_VERSION, + KEY_ISA, + key_last, +} mop_prehashed_key_t; + +#define KEY_FOR(name) mop_prehashed_key_for(KEY_ ##name) +#define HASH_FOR(name) mop_prehashed_hash_for(KEY_ ##name) + +void mop_prehash_keys (void); +inline SV *mop_prehashed_key_for (mop_prehashed_key_t key); +inline U32 mop_prehashed_hash_for (mop_prehashed_key_t key); extern SV *mop_method_metaclass; extern SV *mop_associated_metaclass; diff --git a/xs/Attribute.xs b/xs/Attribute.xs index 807e7e5..150fd05 100644 --- a/xs/Attribute.xs +++ b/xs/Attribute.xs @@ -1,7 +1,5 @@ #include "mop.h" -NEEDS_KEY(name); - MODULE = Class::MOP::Attribute PACKAGE = Class::MOP::Attribute PROTOTYPES: DISABLE @@ -16,7 +14,7 @@ name(self) die("Cannot call name as a class method"); } - if ( (he = hv_fetch_ent((HV *)SvRV(self), key_name, 0, hash_name)) ) + if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(name), 0, HASH_FOR(name))) ) XPUSHs(HeVAL(he)); else ST(0) = &PL_sv_undef; diff --git a/xs/Class.xs b/xs/Class.xs index c332b89..32bbde6 100644 --- a/xs/Class.xs +++ b/xs/Class.xs @@ -1,12 +1,5 @@ #include "mop.h" -NEEDS_KEY(name); -NEEDS_KEY(body); -NEEDS_KEY(methods); -NEEDS_KEY(package); -NEEDS_KEY(package_name); -NEEDS_KEY(package_cache_flag); - static void mop_update_method_map(pTHX_ SV *const self, SV *const class_name, HV *const stash, HV *const map) { @@ -41,7 +34,7 @@ mop_update_method_map(pTHX_ SV *const self, SV *const class_name, HV *const stas method_slot = *hv_fetch(map, method_name, method_name_len, TRUE); if ( SvOK(method_slot) ) { - SV *const body = mop_call0(aTHX_ method_slot, key_body); /* $method_object->body() */ + SV *const body = mop_call0(aTHX_ method_slot, KEY_FOR(body)); /* $method_object->body() */ if ( SvROK(body) && ((CV *) SvRV(body)) == cv ) { continue; } @@ -66,9 +59,9 @@ mop_update_method_map(pTHX_ SV *const self, SV *const class_name, HV *const stas mPUSHs(newRV_inc((SV *)cv)); PUSHs(mop_associated_metaclass); PUSHs(self); - PUSHs(key_package_name); + PUSHs(KEY_FOR(package_name)); PUSHs(class_name); - PUSHs(key_name); + PUSHs(KEY_FOR(name)); mPUSHs(newSVpv(method_name, method_name_len)); PUTBACK; @@ -93,11 +86,11 @@ get_method_map(self) SV *self PREINIT: HV *const obj = (HV *)SvRV(self); - SV *const class_name = HeVAL( hv_fetch_ent(obj, key_package, 0, hash_package) ); + SV *const class_name = HeVAL( hv_fetch_ent(obj, KEY_FOR(package), 0, HASH_FOR(package)) ); HV *const stash = gv_stashsv(class_name, 0); UV const current = mop_check_package_cache_flag(aTHX_ stash); - SV *const cache_flag = HeVAL( hv_fetch_ent(obj, key_package_cache_flag, TRUE, hash_package_cache_flag)); - SV *const map_ref = HeVAL( hv_fetch_ent(obj, key_methods, TRUE, hash_methods)); + SV *const cache_flag = HeVAL( hv_fetch_ent(obj, KEY_FOR(package_cache_flag), TRUE, HASH_FOR(package_cache_flag))); + SV *const map_ref = HeVAL( hv_fetch_ent(obj, KEY_FOR(methods), TRUE, HASH_FOR(methods))); PPCODE: /* in $self->{methods} does not yet exist (or got deleted) */ if ( !SvROK(map_ref) || SvTYPE(SvRV(map_ref)) != SVt_PVHV ) { diff --git a/xs/MOP.xs b/xs/MOP.xs index 5168786..f3a6384 100644 --- a/xs/MOP.xs +++ b/xs/MOP.xs @@ -8,15 +8,6 @@ find_method (const char *key, STRLEN keylen, SV *val, void *ud) return FALSE; } -DECLARE_KEY(name); -DECLARE_KEY(package); -DECLARE_KEY(package_name); -DECLARE_KEY(body); -DECLARE_KEY(package_cache_flag); -DECLARE_KEY(methods); -DECLARE_KEY(VERSION); -DECLARE_KEY(ISA); - SV *mop_method_metaclass; SV *mop_associated_metaclass; SV *mop_wrap; @@ -26,14 +17,7 @@ MODULE = Class::MOP PACKAGE = Class::MOP PROTOTYPES: DISABLE BOOT: - PREHASH_KEY(name); - PREHASH_KEY(body); - PREHASH_KEY(package); - PREHASH_KEY(package_name); - PREHASH_KEY(methods); - PREHASH_KEY(ISA); - PREHASH_KEY(VERSION); - PREHASH_KEY_WITH_VALUE(package_cache_flag, "_package_cache_flag"); + mop_prehash_keys(); mop_method_metaclass = newSVpvs("method_metaclass"); mop_wrap = newSVpvs("wrap"); @@ -78,8 +62,8 @@ is_class_loaded(klass=&PL_sv_undef) XSRETURN_NO; } - if (hv_exists_ent (stash, key_VERSION, hash_VERSION)) { - HE *version = hv_fetch_ent(stash, key_VERSION, 0, hash_VERSION); + if (hv_exists_ent (stash, KEY_FOR(VERSION), HASH_FOR(VERSION))) { + HE *version = hv_fetch_ent(stash, KEY_FOR(VERSION), 0, HASH_FOR(VERSION)); SV *version_sv; if (version && HeVAL(version) && (version_sv = GvSV(HeVAL(version)))) { if (SvROK(version_sv)) { @@ -95,8 +79,8 @@ is_class_loaded(klass=&PL_sv_undef) } } - if (hv_exists_ent (stash, key_ISA, hash_ISA)) { - HE *isa = hv_fetch_ent(stash, key_ISA, 0, hash_ISA); + if (hv_exists_ent (stash, KEY_FOR(ISA), HASH_FOR(ISA))) { + HE *isa = hv_fetch_ent(stash, KEY_FOR(ISA), 0, HASH_FOR(ISA)); if (isa && HeVAL(isa) && GvAV(HeVAL(isa))) { XSRETURN_YES; } diff --git a/xs/Method.xs b/xs/Method.xs index 18865bc..ba2c850 100644 --- a/xs/Method.xs +++ b/xs/Method.xs @@ -1,9 +1,5 @@ #include "mop.h" -NEEDS_KEY(name); -NEEDS_KEY(body); -NEEDS_KEY(package_name); - MODULE = Class::MOP::Method PACKAGE = Class::MOP::Method PROTOTYPES: DISABLE @@ -18,7 +14,7 @@ name(self) die("Cannot call name as a class method"); } - if ( (he = hv_fetch_ent((HV *)SvRV(self), key_name, 0, hash_name)) ) + if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(name), 0, HASH_FOR(name))) ) XPUSHs(HeVAL(he)); else ST(0) = &PL_sv_undef; @@ -33,7 +29,7 @@ package_name(self) die("Cannot call package_name as a class method"); } - if ( (he = hv_fetch_ent((HV *)SvRV(self), key_package_name, 0, hash_package_name)) ) + if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(package_name), 0, HASH_FOR(package_name))) ) XPUSHs(HeVAL(he)); else ST(0) = &PL_sv_undef; @@ -48,7 +44,7 @@ body(self) die("Cannot call body as a class method"); } - if ( (he = hv_fetch_ent((HV *)SvRV(self), key_body, 0, hash_body)) ) + if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(body), 0, HASH_FOR(body))) ) XPUSHs(HeVAL(he)); else ST(0) = &PL_sv_undef; diff --git a/xs/Package.xs b/xs/Package.xs index 9ec195c..eaac489 100644 --- a/xs/Package.xs +++ b/xs/Package.xs @@ -1,7 +1,5 @@ #include "mop.h" -NEEDS_KEY(package); - MODULE = Class::MOP::Package PACKAGE = Class::MOP::Package PROTOTYPES: DISABLE @@ -25,7 +23,7 @@ get_all_package_symbols(self, filter=TYPE_FILTER_NONE) PUTBACK; - if ( (he = hv_fetch_ent((HV *)SvRV(self), key_package, 0, hash_package)) ) { + if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(package), 0, HASH_FOR(package))) ) { stash = gv_stashsv(HeVAL(he), 0); } @@ -47,7 +45,7 @@ name(self) die("Cannot call name as a class method"); } - if ( (he = hv_fetch_ent((HV *)SvRV(self), key_package, 0, hash_package)) ) + if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(package), 0, HASH_FOR(package))) ) XPUSHs(HeVAL(he)); else ST(0) = &PL_sv_undef;