X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=hv.c;h=d5539209bbb0700d04e42e09a8da81cb9861db4d;hb=f3faeb53b75c95d2773d14d859d4fa9ca1594daa;hp=a08720e849d54aa208989799763ea487eca1b06c;hpb=77caf834c201d3982a815b3d51794b6e3a769c6d;p=p5sagit%2Fp5-mst-13.2.git diff --git a/hv.c b/hv.c index a08720e..d553920 100644 --- a/hv.c +++ b/hv.c @@ -1180,36 +1180,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;