diff options
author | Nicholas Clark <nick@ccl4.org> | 2008-09-12 00:19:51 +0000 |
---|---|---|
committer | Nicholas Clark <nick@ccl4.org> | 2008-09-12 00:19:51 +0000 |
commit | a49ba3fcbe357fbacf7b9898df08daa2cbdfc8c4 (patch) | |
tree | 43834e70391760038633daf86cecae00b95fef4e /universal.c | |
parent | c109477dfda0dedbe3c4ffa3d6074085d3b8497a (diff) | |
download | perl-a49ba3fcbe357fbacf7b9898df08daa2cbdfc8c4.tar.gz |
Create a direct lookup hash for ->isa() lookup, by retaining the
de-duping hash used by S_mro_get_linear_isa_dfs(). Provide a new
function Perl_get_isa_hash() to lazily retrieve this. (Which could
actually be static if S_isa_lookup() and Perl_sv_derived_from()
moved into mro.c.) Make S_isa_lookup() use this lookup hash in place
of a linear walk of the linear isa. This should turn isa lookups from
O(n) to O(1), which should make heavy users of ->isa() faster.
(eg PPI, and hence Perl Critic).
p4raw-id: //depot/perl@34354
Diffstat (limited to 'universal.c')
-rw-r--r-- | universal.c | 41 |
1 files changed, 19 insertions, 22 deletions
diff --git a/universal.c b/universal.c index 08dad15ab5..de928f7d13 100644 --- a/universal.c +++ b/universal.c @@ -40,35 +40,32 @@ STATIC bool S_isa_lookup(pTHX_ HV *stash, const char * const name) { dVAR; - AV* stash_linear_isa; - SV** svp; - const char *hvname; - I32 items; - const HV *const name_stash = gv_stashpv(name, 0); + const struct mro_meta *const meta = HvMROMETA(stash); + HV *const isa = meta->isa ? meta->isa : Perl_get_isa_hash(aTHX_ stash); + STRLEN len = strlen(name); + const HV *our_stash; PERL_ARGS_ASSERT_ISA_LOOKUP; - /* A stash/class can go by many names (ie. User == main::User), so - we compare the stash itself just in case */ - if ((const HV *)stash == name_stash) - return TRUE; - - hvname = HvNAME_get(stash); - - if (strEQ(hvname, name)) + if (hv_common(isa, NULL, name, len, 0 /* No "UTF-8" flag possible with only + a char * argument*/, + HV_FETCH_ISEXISTS, NULL, 0)) { + /* Direct name lookup worked. */ return TRUE; + } - if (strEQ(name, "UNIVERSAL")) - return TRUE; + /* A stash/class can go by many names (ie. User == main::User), so + we use the name in the stash itself, which is canonical. */ + our_stash = gv_stashpvn(name, len, 0); - stash_linear_isa = mro_get_linear_isa(stash); - svp = AvARRAY(stash_linear_isa) + 1; - items = AvFILLp(stash_linear_isa); - while (items--) { - SV* const basename_sv = *svp++; - HV* const basestash = gv_stashsv(basename_sv, 0); - if(name_stash == basestash || strEQ(name, SvPVX(basename_sv))) + if (our_stash) { + HEK *const canon_name = HvNAME_HEK(our_stash); + + if (hv_common(isa, NULL, HEK_KEY(canon_name), HEK_LEN(canon_name), + HEK_FLAGS(canon_name), + HV_FETCH_ISEXISTS, NULL, HEK_HASH(canon_name))) { return TRUE; + } } return FALSE; |