X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=hv.c;h=11992f45727253d45b9a00e563be0f0f96cd86b6;hb=29a5dc09a8a3b3561aa738ed5a47775ecf7d811e;hp=76180f2d8acc5b515d811262c755d965903e37f2;hpb=25716404fbbde2ca91832aab8c9157aafcdcc7e8;p=p5sagit%2Fp5-mst-13.2.git diff --git a/hv.c b/hv.c index 76180f2..11992f4 100644 --- a/hv.c +++ b/hv.c @@ -99,7 +99,7 @@ Perl_unshare_hek(pTHX_ HEK *hek) #if defined(USE_ITHREADS) HE * -Perl_he_dup(pTHX_ HE *e, bool shared, clone_params* param) +Perl_he_dup(pTHX_ HE *e, bool shared, CLONE_PARAMS* param) { HE *ret; @@ -126,6 +126,25 @@ Perl_he_dup(pTHX_ HE *e, bool shared, clone_params* param) } #endif /* USE_ITHREADS */ +static void +Perl_hv_notallowed(pTHX_ bool is_utf8, const char *key, I32 klen, + const char *keysave) +{ + SV *sv = sv_newmortal(); + if (key == keysave) { + sv_setpvn(sv, key, klen); + } + else { + /* Need to free saved eventually assign to mortal SV */ + SV *sv = sv_newmortal(); + sv_usepvn(sv, (char *) key, klen); + } + if (is_utf8) { + SvUTF8_on(sv); + } + Perl_croak(aTHX_ "Attempt to access to key '%_' in fixed hash",sv); +} + /* (klen == HEf_SVKEY) is special for MAGICAL hv entries, meaning key slot * contains an SV* */ @@ -135,7 +154,7 @@ Perl_he_dup(pTHX_ HE *e, bool shared, clone_params* param) Returns the SV which corresponds to the specified key in the hash. The C is the length of the key. If C is set then the fetch will be part of a store. Check that the return value is non-null before -dereferencing it to a C. +dereferencing it to an C. See L for more information on how to use this function on tied hashes. @@ -199,7 +218,7 @@ Perl_hv_fetch(pTHX_ HV *hv, const char *key, I32 klen, I32 lval) return 0; } - if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT)) { + if (is_utf8) { STRLEN tmplen = klen; /* Just casting the &klen to (STRLEN) won't work well * if STRLEN and I32 are of different widths. --jhi */ @@ -237,6 +256,9 @@ Perl_hv_fetch(pTHX_ HV *hv, const char *key, I32 klen, I32 lval) } } #endif + if (SvREADONLY(hv)) { + Perl_hv_notallowed(aTHX_ is_utf8, key, klen, keysave); + } if (lval) { /* gonna assign to this, so it better be there */ sv = NEWSV(61,0); if (key != keysave) { /* must be is_utf8 == 0 */ @@ -252,7 +274,7 @@ Perl_hv_fetch(pTHX_ HV *hv, const char *key, I32 klen, I32 lval) return 0; } -/* returns a HE * structure with the all fields set */ +/* returns an HE * structure with the all fields set */ /* note that hent_val will be a mortal sv for MAGICAL hashes */ /* =for apidoc hv_fetch_ent @@ -333,7 +355,7 @@ Perl_hv_fetch_ent(pTHX_ HV *hv, SV *keysv, I32 lval, register U32 hash) keysave = key = SvPV(keysv, klen); is_utf8 = (SvUTF8(keysv)!=0); - if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT)) + if (is_utf8) key = (char*)bytes_from_utf8((U8*)key, &klen, &is_utf8); if (!hash) @@ -365,6 +387,9 @@ Perl_hv_fetch_ent(pTHX_ HV *hv, SV *keysv, I32 lval, register U32 hash) } } #endif + if (SvREADONLY(hv)) { + Perl_hv_notallowed(aTHX_ is_utf8, key, klen, keysave); + } if (key != keysave) Safefree(key); if (lval) { /* gonna assign to this, so it better be there */ @@ -447,7 +472,7 @@ Perl_hv_store(pTHX_ HV *hv, const char *key, I32 klen, SV *val, register U32 has #endif } } - if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT)) { + if (is_utf8) { STRLEN tmplen = klen; /* See the note in hv_fetch(). --jhi */ key = (char*)bytes_from_utf8((U8*)key, &tmplen, &is_utf8); @@ -482,6 +507,10 @@ Perl_hv_store(pTHX_ HV *hv, const char *key, I32 klen, SV *val, register U32 has return &HeVAL(entry); } + if (SvREADONLY(hv)) { + Perl_hv_notallowed(aTHX_ is_utf8, key, klen, keysave); + } + entry = new_HE(); if (HvSHAREKEYS(hv)) HeKEY_hek(entry) = share_hek(key, is_utf8?-klen:klen, hash); @@ -565,7 +594,7 @@ Perl_hv_store_ent(pTHX_ HV *hv, SV *keysv, SV *val, register U32 hash) keysave = key = SvPV(keysv, klen); is_utf8 = (SvUTF8(keysv) != 0); - if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT)) + if (is_utf8) key = (char*)bytes_from_utf8((U8*)key, &klen, &is_utf8); if (!hash) @@ -596,6 +625,10 @@ Perl_hv_store_ent(pTHX_ HV *hv, SV *keysv, SV *val, register U32 hash) return entry; } + if (SvREADONLY(hv)) { + Perl_hv_notallowed(aTHX_ is_utf8, key, klen, keysave); + } + entry = new_HE(); if (HvSHAREKEYS(hv)) HeKEY_hek(entry) = share_hek(key, is_utf8?-(I32)klen:klen, hash); @@ -675,13 +708,17 @@ Perl_hv_delete(pTHX_ HV *hv, const char *key, I32 klen, I32 flags) if (!xhv->xhv_array /* !HvARRAY(hv) */) return Nullsv; - if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT)) { + if (is_utf8) { STRLEN tmplen = klen; /* See the note in hv_fetch(). --jhi */ key = (char*)bytes_from_utf8((U8*)key, &tmplen, &is_utf8); klen = tmplen; } + if (SvREADONLY(hv)) { + Perl_hv_notallowed(aTHX_ is_utf8, key, klen, keysave); + } + PERL_HASH(hash, key, klen); /* oentry = &(HvARRAY(hv))[hash & (I32) HvMAX(hv)]; */ @@ -779,9 +816,13 @@ Perl_hv_delete_ent(pTHX_ HV *hv, SV *keysv, I32 flags, U32 hash) keysave = key = SvPV(keysv, klen); is_utf8 = (SvUTF8(keysv) != 0); - if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT)) + if (is_utf8) key = (char*)bytes_from_utf8((U8*)key, &klen, &is_utf8); + if (SvREADONLY(hv)) { + Perl_hv_notallowed(aTHX_ is_utf8, key, klen, keysave); + } + if (!hash) PERL_HASH(hash, key, klen); @@ -869,7 +910,7 @@ Perl_hv_exists(pTHX_ HV *hv, const char *key, I32 klen) return 0; #endif - if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT)) { + if (is_utf8) { STRLEN tmplen = klen; /* See the note in hv_fetch(). --jhi */ key = (char*)bytes_from_utf8((U8*)key, &tmplen, &is_utf8); @@ -966,7 +1007,7 @@ Perl_hv_exists_ent(pTHX_ HV *hv, SV *keysv, U32 hash) keysave = key = SvPV(keysv, klen); is_utf8 = (SvUTF8(keysv) != 0); - if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT)) + if (is_utf8) key = (char*)bytes_from_utf8((U8*)key, &klen, &is_utf8); if (!hash) PERL_HASH(hash, key, klen); @@ -1180,36 +1221,72 @@ Perl_newHV(pTHX) HV * Perl_newHVhv(pTHX_ HV *ohv) { - register HV *hv; - STRLEN hv_max = ohv ? HvMAX(ohv) : 0; - STRLEN hv_fill = ohv ? HvFILL(ohv) : 0; - - hv = newHV(); - while (hv_max && hv_max + 1 >= hv_fill * 2) - hv_max = hv_max / 2; /* Is always 2^n-1 */ - HvMAX(hv) = hv_max; - if (!hv_fill) + HV *hv = newHV(); + STRLEN hv_max, hv_fill; + + if (!ohv || (hv_fill = HvFILL(ohv)) == 0) return hv; + hv_max = HvMAX(ohv); + + if (!SvMAGICAL((SV *)ohv)) { + /* It's an ordinary hash, so copy it fast. AMS 20010804 */ + int i, shared = !!HvSHAREKEYS(ohv); + HE **ents, **oents = (HE **)HvARRAY(ohv); + char *a; + New(0, a, PERL_HV_ARRAY_ALLOC_BYTES(hv_max+1), char); + ents = (HE**)a; + + /* In each bucket... */ + for (i = 0; i <= hv_max; i++) { + HE *prev = NULL, *ent = NULL, *oent = oents[i]; + + if (!oent) { + ents[i] = NULL; + continue; + } + + /* Copy the linked list of entries. */ + for (oent = oents[i]; oent; oent = HeNEXT(oent)) { + U32 hash = HeHASH(oent); + char *key = HeKEY(oent); + STRLEN len = HeKLEN_UTF8(oent); + + ent = new_HE(); + HeVAL(ent) = newSVsv(HeVAL(oent)); + HeKEY_hek(ent) = shared ? share_hek(key, len, hash) + : save_hek(key, len, hash); + if (prev) + HeNEXT(prev) = ent; + else + ents[i] = ent; + prev = ent; + HeNEXT(ent) = NULL; + } + } -#if 0 - if (! SvTIED_mg((SV*)ohv, PERL_MAGIC_tied)) { - /* Quick way ???*/ + HvMAX(hv) = hv_max; + HvFILL(hv) = hv_fill; + HvKEYS(hv) = HvKEYS(ohv); + HvARRAY(hv) = ents; } - else -#endif - { + else { + /* Iterate over ohv, copying keys and values one at a time. */ HE *entry; - I32 hv_riter = HvRITER(ohv); /* current root of iterator */ - HE *hv_eiter = HvEITER(ohv); /* current entry of iterator */ - - /* Slow way */ + I32 riter = HvRITER(ohv); + HE *eiter = HvEITER(ohv); + + /* Can we use fewer buckets? (hv_max is always 2^n-1) */ + while (hv_max && hv_max + 1 >= hv_fill * 2) + hv_max = hv_max / 2; + HvMAX(hv) = hv_max; + hv_iterinit(ohv); while ((entry = hv_iternext(ohv))) { hv_store(hv, HeKEY(entry), HeKLEN_UTF8(entry), newSVsv(HeVAL(entry)), HeHASH(entry)); } - HvRITER(ohv) = hv_riter; - HvEITER(ohv) = hv_eiter; + HvRITER(ohv) = riter; + HvEITER(ohv) = eiter; } return hv; @@ -1584,14 +1661,11 @@ Perl_unsharepvn(pTHX_ const char *str, I32 len, U32 hash) const char *save = str; if (len < 0) { - len = -len; + STRLEN tmplen = -len; is_utf8 = TRUE; - if (!(PL_hints & HINT_UTF8_DISTINCT)) { - STRLEN tmplen = len; - /* See the note in hv_fetch(). --jhi */ - str = (char*)bytes_from_utf8((U8*)str, &tmplen, &is_utf8); - len = tmplen; - } + /* See the note in hv_fetch(). --jhi */ + str = (char*)bytes_from_utf8((U8*)str, &tmplen, &is_utf8); + len = tmplen; } /* what follows is the moral equivalent of: @@ -1647,14 +1721,11 @@ Perl_share_hek(pTHX_ const char *str, I32 len, register U32 hash) const char *save = str; if (len < 0) { - len = -len; + STRLEN tmplen = -len; is_utf8 = TRUE; - if (!(PL_hints & HINT_UTF8_DISTINCT)) { - STRLEN tmplen = len; - /* See the note in hv_fetch(). --jhi */ - str = (char*)bytes_from_utf8((U8*)str, &tmplen, &is_utf8); - len = tmplen; - } + /* See the note in hv_fetch(). --jhi */ + str = (char*)bytes_from_utf8((U8*)str, &tmplen, &is_utf8); + len = tmplen; } /* what follows is the moral equivalent of: