This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
5.004_70 tweaks
[perl5.git] / hv.c
diff --git a/hv.c b/hv.c
index af5986e..784aadf 100644 (file)
--- a/hv.c
+++ b/hv.c
@@ -21,6 +21,13 @@ static void hfreeentries _((HV *hv));
 static HE* more_he _((void));
 #endif
 
+#if defined(STRANGE_MALLOC) || defined(MYMALLOC)
+#  define ARRAY_ALLOC_BYTES(size) ( (size)*sizeof(HE*) )
+#else
+#  define MALLOC_OVERHEAD 16
+#  define ARRAY_ALLOC_BYTES(size) ( (size)*sizeof(HE*)*2 - MALLOC_OVERHEAD )
+#endif
+
 STATIC HE*
 new_he(void)
 {
@@ -45,7 +52,7 @@ more_he(void)
 {
     register HE* he;
     register HE* heend;
-    he_root = (HE*)safemalloc(1008);
+    New(54, he_root, 1008/sizeof(HE), HE);
     he = he_root;
     heend = &he[1008 / sizeof(HE) - 1];
     while (he < heend) {
@@ -96,8 +103,8 @@ hv_fetch(HV *hv, char *key, U32 klen, I32 lval)
            dTHR;
            sv = sv_newmortal();
            mg_copy((SV*)hv, sv, key, klen);
-           Sv = sv;
-           return &Sv;
+           hv_fetch_sv = sv;
+           return &hv_fetch_sv;
        }
 #ifdef ENV_IS_CASELESS
        else if (mg_find((SV*)hv,'E')) {
@@ -121,7 +128,7 @@ hv_fetch(HV *hv, char *key, U32 klen, I32 lval)
                 || (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME))
 #endif
                                                                  )
-           Newz(503,xhv->xhv_array, sizeof(HE*) * (xhv->xhv_max + 1), char);
+           Newz(503,xhv->xhv_array, ARRAY_ALLOC_BYTES(xhv->xhv_max + 1), char);
        else
            return 0;
     }
@@ -142,7 +149,7 @@ hv_fetch(HV *hv, char *key, U32 klen, I32 lval)
     if (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME)) {
       char *gotenv;
 
-      if ((gotenv = ENV_getenv(key)) != Nullch) {
+      if ((gotenv = PerlEnv_getenv(key)) != Nullch) {
         sv = newSVpv(gotenv,strlen(gotenv));
         SvTAINTED_on(sv);
         return hv_store(hv,key,klen,sv,hash);
@@ -172,19 +179,18 @@ hv_fetch_ent(HV *hv, SV *keysv, I32 lval, register U32 hash)
 
     if (SvRMAGICAL(hv)) {
        if (mg_find((SV*)hv,'P')) {
-           static HE mh;
-
+           dTHR;
            sv = sv_newmortal();
            keysv = sv_2mortal(newSVsv(keysv));
            mg_copy((SV*)hv, sv, (char*)keysv, HEf_SVKEY);
-           if (!HeKEY_hek(&mh)) {
+           if (!HeKEY_hek(&hv_fetch_ent_mh)) {
                char *k;
                New(54, k, HEK_BASESIZE + sizeof(SV*), char);
-               HeKEY_hek(&mh) = (HEK*)k;
+               HeKEY_hek(&hv_fetch_ent_mh) = (HEK*)k;
            }
-           HeSVKEY_set(&mh, keysv);
-           HeVAL(&mh) = sv;
-           return &mh;
+           HeSVKEY_set(&hv_fetch_ent_mh, keysv);
+           HeVAL(&hv_fetch_ent_mh) = sv;
+           return &hv_fetch_ent_mh;
        }
 #ifdef ENV_IS_CASELESS
        else if (mg_find((SV*)hv,'E')) {
@@ -210,7 +216,7 @@ hv_fetch_ent(HV *hv, SV *keysv, I32 lval, register U32 hash)
                 || (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME))
 #endif
                                                                  )
-           Newz(503,xhv->xhv_array, sizeof(HE*) * (xhv->xhv_max + 1), char);
+           Newz(503,xhv->xhv_array, ARRAY_ALLOC_BYTES(xhv->xhv_max + 1), char);
        else
            return 0;
     }
@@ -234,7 +240,7 @@ hv_fetch_ent(HV *hv, SV *keysv, I32 lval, register U32 hash)
     if (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME)) {
       char *gotenv;
 
-      if ((gotenv = ENV_getenv(key)) != Nullch) {
+      if ((gotenv = PerlEnv_getenv(key)) != Nullch) {
         sv = newSVpv(gotenv,strlen(gotenv));
         SvTAINTED_on(sv);
         return hv_store_ent(hv,keysv,sv,hash);
@@ -300,7 +306,7 @@ hv_store(HV *hv, char *key, U32 klen, SV *val, register U32 hash)
        PERL_HASH(hash, key, klen);
 
     if (!xhv->xhv_array)
-       Newz(505, xhv->xhv_array, sizeof(HE**) * (xhv->xhv_max + 1), char);
+       Newz(505, xhv->xhv_array, ARRAY_ALLOC_BYTES(xhv->xhv_max + 1), char);
 
     oentry = &((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max];
     i = 1;
@@ -381,7 +387,7 @@ hv_store_ent(HV *hv, SV *keysv, SV *val, register U32 hash)
        PERL_HASH(hash, key, klen);
 
     if (!xhv->xhv_array)
-       Newz(505, xhv->xhv_array, sizeof(HE**) * (xhv->xhv_max + 1), char);
+       Newz(505, xhv->xhv_array, ARRAY_ALLOC_BYTES(xhv->xhv_max + 1), char);
 
     oentry = &((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max];
     i = 1;
@@ -666,59 +672,57 @@ hsplit(HV *hv)
     I32 oldsize = (I32) xhv->xhv_max + 1; /* sic(k) */
     register I32 newsize = oldsize * 2;
     register I32 i;
-    register HE **a;
-    register HE **b;
+    register char *a = xhv->xhv_array;
+    register HE **aep;
+    register HE **bep;
     register HE *entry;
     register HE **oentry;
-#ifndef STRANGE_MALLOC
-    I32 tmp;
-#endif
 
-    a = (HE**)xhv->xhv_array;
     nomemok = TRUE;
-#ifdef STRANGE_MALLOC
-    Renew(a, newsize, HE*);
+#if defined(STRANGE_MALLOC) || defined(MYMALLOC)
+    Renew(a, ARRAY_ALLOC_BYTES(newsize), char);
+    if (!a) {
+      nomemok = FALSE;
+      return;
+    }
 #else
-    i = newsize * sizeof(HE*);
 #define MALLOC_OVERHEAD 16
-    tmp = MALLOC_OVERHEAD;
-    while (tmp - MALLOC_OVERHEAD < i)
-       tmp += tmp;
-    tmp -= MALLOC_OVERHEAD;
-    tmp /= sizeof(HE*);
-    assert(tmp >= newsize);
-    New(2,a, tmp, HE*);
-    Copy(xhv->xhv_array, a, oldsize, HE*);
+    New(2, a, ARRAY_ALLOC_BYTES(newsize), char);
+    if (!a) {
+      nomemok = FALSE;
+      return;
+    }
+    Copy(xhv->xhv_array, a, oldsize * sizeof(HE*), char);
     if (oldsize >= 64) {
-       offer_nice_chunk(xhv->xhv_array,
-                        oldsize * sizeof(HE*) * 2 - MALLOC_OVERHEAD);
+       offer_nice_chunk(xhv->xhv_array, ARRAY_ALLOC_BYTES(oldsize));
     }
     else
        Safefree(xhv->xhv_array);
 #endif
 
     nomemok = FALSE;
-    Zero(&a[oldsize], oldsize, HE*);           /* zero 2nd half*/
+    Zero(&a[oldsize * sizeof(HE*)], (newsize-oldsize) * sizeof(HE*), char);    /* zero 2nd half*/
     xhv->xhv_max = --newsize;
-    xhv->xhv_array = (char*)a;
+    xhv->xhv_array = a;
+    aep = (HE**)a;
 
-    for (i=0; i<oldsize; i++,a++) {
-       if (!*a)                                /* non-existent */
+    for (i=0; i<oldsize; i++,aep++) {
+       if (!*aep)                              /* non-existent */
            continue;
-       b = a+oldsize;
-       for (oentry = a, entry = *a; entry; entry = *oentry) {
+       bep = aep+oldsize;
+       for (oentry = aep, entry = *aep; entry; entry = *oentry) {
            if ((HeHASH(entry) & newsize) != i) {
                *oentry = HeNEXT(entry);
-               HeNEXT(entry) = *b;
-               if (!*b)
+               HeNEXT(entry) = *bep;
+               if (!*bep)
                    xhv->xhv_fill++;
-               *b = entry;
+               *bep = entry;
                continue;
            }
            else
                oentry = &HeNEXT(entry);
        }
-       if (!*a)                                /* everything moved */
+       if (!*aep)                              /* everything moved */
            xhv->xhv_fill--;
     }
 }
@@ -731,7 +735,8 @@ hv_ksplit(HV *hv, IV newmax)
     register I32 newsize;
     register I32 i;
     register I32 j;
-    register HE **a;
+    register char *a;
+    register HE **aep;
     register HE *entry;
     register HE **oentry;
 
@@ -746,55 +751,56 @@ hv_ksplit(HV *hv, IV newmax)
     if (newsize < newmax)
        return;                                 /* overflow detection */
 
-    a = (HE**)xhv->xhv_array;
+    a = xhv->xhv_array;
     if (a) {
        nomemok = TRUE;
-#ifdef STRANGE_MALLOC
-       Renew(a, newsize, HE*);
+#if defined(STRANGE_MALLOC) || defined(MYMALLOC)
+       Renew(a, ARRAY_ALLOC_BYTES(newsize), char);
+        if (!a) {
+         nomemok = FALSE;
+         return;
+       }
 #else
-       i = newsize * sizeof(HE*);
-       j = MALLOC_OVERHEAD;
-       while (j - MALLOC_OVERHEAD < i)
-           j += j;
-       j -= MALLOC_OVERHEAD;
-       j /= sizeof(HE*);
-       assert(j >= newsize);
-       New(2, a, j, HE*);
-       Copy(xhv->xhv_array, a, oldsize, HE*);
+       New(2, a, ARRAY_ALLOC_BYTES(newsize), char);
+        if (!a) {
+         nomemok = FALSE;
+         return;
+       }
+       Copy(xhv->xhv_array, a, oldsize * sizeof(HE*), char);
        if (oldsize >= 64) {
-           offer_nice_chunk(xhv->xhv_array,
-                            oldsize * sizeof(HE*) * 2 - MALLOC_OVERHEAD);
+           offer_nice_chunk(xhv->xhv_array, ARRAY_ALLOC_BYTES(oldsize));
        }
        else
            Safefree(xhv->xhv_array);
 #endif
        nomemok = FALSE;
-       Zero(&a[oldsize], newsize-oldsize, HE*); /* zero 2nd half*/
+       Zero(&a[oldsize * sizeof(HE*)], (newsize-oldsize) * sizeof(HE*), char); /* zero 2nd half*/
     }
     else {
-       Newz(0, a, newsize, HE*);
+       Newz(0, a, ARRAY_ALLOC_BYTES(newsize), char);
     }
     xhv->xhv_max = --newsize;
-    xhv->xhv_array = (char*)a;
+    xhv->xhv_array = a;
     if (!xhv->xhv_fill)                                /* skip rest if no entries */
        return;
 
-    for (i=0; i<oldsize; i++,a++) {
-       if (!*a)                                /* non-existent */
+    aep = (HE**)a;
+    for (i=0; i<oldsize; i++,aep++) {
+       if (!*aep)                              /* non-existent */
            continue;
-       for (oentry = a, entry = *a; entry; entry = *oentry) {
+       for (oentry = aep, entry = *aep; entry; entry = *oentry) {
            if ((j = (HeHASH(entry) & newsize)) != i) {
                j -= i;
                *oentry = HeNEXT(entry);
-               if (!(HeNEXT(entry) = a[j]))
+               if (!(HeNEXT(entry) = aep[j]))
                    xhv->xhv_fill++;
-               a[j] = entry;
+               aep[j] = entry;
                continue;
            }
            else
                oentry = &HeNEXT(entry);
        }
-       if (!*a)                                /* everything moved */
+       if (!*aep)                              /* everything moved */
            xhv->xhv_fill--;
     }
 }
@@ -820,14 +826,56 @@ newHV(void)
     return hv;
 }
 
+HV *
+newHVhv(HV *ohv)
+{
+    register HV *hv;
+    register XPVHV* xhv;
+    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 */
+    ((XPVHV*)SvANY(hv))->xhv_max = hv_max;
+    if (!hv_fill)
+       return hv;
+
+#if 0
+    if (!SvRMAGICAL(ohv) || !mg_find((SV*)ohv,'P')) {
+       /* Quick way ???*/
+    } 
+    else 
+#endif
+    {
+       HE *entry;
+       I32 hv_riter = HvRITER(ohv);    /* current root of iterator */
+       HE *hv_eiter = HvEITER(ohv);    /* current entry of iterator */
+       
+       /* Slow way */
+       hv_iterinit(hv);
+       while (entry = hv_iternext(ohv)) {
+           hv_store(hv, HeKEY(entry), HeKLEN(entry), 
+                    SvREFCNT_inc(HeVAL(entry)), HeHASH(entry));
+       }
+       HvRITER(ohv) = hv_riter;
+       HvEITER(ohv) = hv_eiter;
+    }
+    
+    return hv;
+}
+
 void
 hv_free_ent(HV *hv, register HE *entry)
 {
+    SV *val;
+
     if (!entry)
        return;
-    if (isGV(HeVAL(entry)) && GvCVu(HeVAL(entry)) && HvNAME(hv))
+    val = HeVAL(entry);
+    if (val && isGV(val) && GvCVu(val) && HvNAME(hv))
        sub_generation++;       /* may be deletion of method from stash */
-    SvREFCNT_dec(HeVAL(entry));
+    SvREFCNT_dec(val);
     if (HeKLEN(entry) == HEf_SVKEY) {
        SvREFCNT_dec(HeKEY_sv(entry));
         Safefree(HeKEY_hek(entry));
@@ -950,7 +998,7 @@ hv_iterinit(HV *hv)
     }
     xhv->xhv_riter = -1;
     xhv->xhv_eiter = Null(HE*);
-    return xhv->xhv_fill;      /* should be xhv->xhv_keys? May change later */
+    return xhv->xhv_keys;      /* used to be xhv->xhv_fill before 5.004_65 */
 }
 
 HE *
@@ -998,7 +1046,7 @@ hv_iternext(HV *hv)
     }
 
     if (!xhv->xhv_array)
-       Newz(506,xhv->xhv_array, sizeof(HE*) * (xhv->xhv_max + 1), char);
+       Newz(506,xhv->xhv_array, ARRAY_ALLOC_BYTES(xhv->xhv_max + 1), char);
     if (entry)
        entry = HeNEXT(entry);
     while (!entry) {