Re: [PATCH hv.c] newHVhv shouldn't reset xhv_max so often
Abhijit Menon-Sen [Sat, 4 Aug 2001 16:16:03 +0000 (21:16 +0530)]
Message-ID: <20010804161603.C526@lustre.dyn.wiw.org>

p4raw-id: //depot/perl@11570

hv.c

diff --git a/hv.c b/hv.c
index 07bccd9..2962de3 100644 (file)
--- a/hv.c
+++ b/hv.c
@@ -1180,36 +1180,70 @@ Perl_newHV(pTHX)
 HV *
 Perl_newHVhv(pTHX_ HV *ohv)
 {
+    HV *hv = newHV();
     STRLEN hv_max, hv_fill;
-    register HV *hv = newHV();
 
     if (!ohv || (hv_fill = HvFILL(ohv)) == 0)
        return hv;
-
     hv_max = HvMAX(ohv);
-    while (hv_max && hv_max + 1 >= hv_fill * 2)
-       hv_max = hv_max / 2;    /* Is always 2^n-1 */
-    HvMAX(hv) = hv_max;
 
-#if 0
-    if (! SvTIED_mg((SV*)ohv, PERL_MAGIC_tied)) {
-       /* Quick way ???*/
+    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);
+       New(0, (char *)ents, PERL_HV_ARRAY_ALLOC_BYTES(hv_max+1), char);
+
+       /* 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)     = SvREFCNT_inc(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;
+           }
+       }
+
+       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;