X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=hv.c;h=158b0b652b032c97ba4f1530dc871024f8ce7f63;hb=7c04078ea21d9035bc412dbd7b8edf35773a2c43;hp=7115332c921e1b47f3e6ff1fc00e4e25fbf72846;hpb=8167a60add3f75b2a48bb3ae0fdd7f9d853bcbdd;p=p5sagit%2Fp5-mst-13.2.git diff --git a/hv.c b/hv.c index 7115332..158b0b6 100644 --- a/hv.c +++ b/hv.c @@ -80,6 +80,7 @@ S_more_he(pTHX) STATIC HEK * S_save_hek_flags(pTHX_ const char *str, I32 len, U32 hash, int flags) { + int flags_masked = flags & HVhek_MASK; char *k; register HEK *hek; @@ -89,7 +90,10 @@ S_save_hek_flags(pTHX_ const char *str, I32 len, U32 hash, int flags) HEK_KEY(hek)[len] = 0; HEK_LEN(hek) = len; HEK_HASH(hek) = hash; - HEK_FLAGS(hek) = (unsigned char)flags; + HEK_FLAGS(hek) = (unsigned char)flags_masked; + + if (flags & HVhek_FREEKEY) + Safefree(str); return hek; } @@ -381,6 +385,8 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, return 0; if (keysv) { + if (flags & HVhek_FREEKEY) + Safefree(key); key = SvPV(keysv, klen); flags = 0; is_utf8 = (SvUTF8(keysv) != 0); @@ -437,25 +443,28 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, U32 i; for (i = 0; i < klen; ++i) if (isLOWER(key[i])) { - const char *keysave = key; - /* Will need to free this, so set FREEKEY flag - on call to hv_fetch_common. */ - key = savepvn(key,klen); - key = (const char*)strupr((char*)key); - - if (flags & HVhek_FREEKEY) - Safefree(keysave); - - /* This isn't strictly the same as the old hv_fetch - magic, which made a call to hv_fetch, followed - by a call to hv_store if that failed and lvalue - was true. - Which I believe could have been done by simply - passing the lvalue through to the first hv_fetch. - So I will do that here. */ - return hv_fetch_common(hv, Nullsv, key, klen, - HVhek_FREEKEY, - action, Nullsv, 0); + /* Would be nice if we had a routine to do the + copy and upercase in a single pass through. */ + char *nkey = strupr(savepvn(key,klen)); + /* Note that this fetch is for nkey (the uppercased + key) whereas the store is for key (the original) */ + entry = hv_fetch_common(hv, Nullsv, nkey, klen, + HVhek_FREEKEY, /* free nkey */ + 0 /* non-LVAL fetch */, + Nullsv /* no value */, + 0 /* compute hash */); + if (!entry && (action & HV_FETCH_LVALUE)) { + /* This call will free key if necessary. + Do it this way to encourage compiler to tail + call optimise. */ + entry = hv_fetch_common(hv, keysv, key, klen, + flags, HV_FETCH_ISSTORE, + NEWSV(61,0), hash); + } else { + if (flags & HVhek_FREEKEY) + Safefree(key); + } + return entry; } } #endif @@ -873,6 +882,8 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, return Nullsv; if (keysv) { + if (k_flags & HVhek_FREEKEY) + Safefree(key); key = SvPV(keysv, klen); k_flags = 0; is_utf8 = (SvUTF8(keysv) != 0); @@ -949,7 +960,6 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, } else { PERL_HASH(hash, key, klen); } - PERL_HASH(hash, key, klen); } masked_flags = (k_flags & HVhek_MASK); @@ -2076,7 +2086,7 @@ S_share_hek_flags(pTHX_ const char *str, I32 len, register U32 hash, int flags) } if (!found) { entry = new_HE(); - HeKEY_hek(entry) = save_hek_flags(str, len, hash, flags); + HeKEY_hek(entry) = save_hek_flags(str, len, hash, flags_masked); HeVAL(entry) = Nullsv; HeNEXT(entry) = *oentry; *oentry = entry;