Clean up and document API for hashes
[p5sagit/p5-mst-13.2.git] / hv.c
diff --git a/hv.c b/hv.c
index 50d5881..ab6eac7 100644 (file)
--- a/hv.c
+++ b/hv.c
@@ -64,12 +64,12 @@ U32 hash;
     char *k;
     register HEK *hek;
     
-    New(54, k, sizeof(U32) + sizeof(I32) + len + 1, char);
+    New(54, k, HEK_BASESIZE + len + 1, char);
     hek = (HEK*)k;
-    Copy(str, HK_KEY(hek), len, char);
-    (HK_KEY(hek))[len] = '\0';
-    HK_LEN(hek) = len;
-    HK_HASH(hek) = hash;
+    Copy(str, HEK_KEY(hek), len, char);
+    *(HEK_KEY(hek) + len) = '\0';
+    HEK_LEN(hek) = len;
+    HEK_HASH(hek) = hash;
     return hek;
 }
 
@@ -77,7 +77,7 @@ void
 unshare_hek(hek)
 HEK *hek;
 {
-    unsharepvn(HK_KEY(hek),HK_LEN(hek),HK_HASH(hek));
+    unsharepvn(HEK_KEY(hek),HEK_LEN(hek),HEK_HASH(hek));
 }
 
 /* (klen == HEf_SVKEY) is special for MAGICAL hv entries, meaning key slot
@@ -127,7 +127,7 @@ I32 lval;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (memcmp(HeKEY(entry),key,klen))      /* is this it? */
+       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
            continue;
        return &HeVAL(entry);
     }
@@ -135,7 +135,7 @@ I32 lval;
     if (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME)) {
       char *gotenv;
 
-      gotenv = my_getenv(key);
+      gotenv = ENV_getenv(key);
       if (gotenv != NULL) {
         sv = newSVpv(gotenv,strlen(gotenv));
         return hv_store(hv,key,klen,sv,hash);
@@ -168,17 +168,19 @@ register U32 hash;
        return 0;
 
     if (SvRMAGICAL(hv) && mg_find((SV*)hv,'P')) {
-       HEK *hek;
-       Newz(74, hek, 1, HEK);
+       static HE mh;
+
        sv = sv_newmortal();
        keysv = sv_2mortal(newSVsv(keysv));
        mg_copy((SV*)hv, sv, (char*)keysv, HEf_SVKEY);
-       entry = &He;
-       HeVAL(entry) = sv;
-       HeKEY_hk(entry) = hek;
-       HeSVKEY_set(entry, keysv);
-       HeKLEN(entry) = HEf_SVKEY;      /* hent_key is holding an SV* */
-       return entry;
+       if (!HeKEY_hek(&mh)) {
+           char *k;
+           New(54, k, HEK_BASESIZE + sizeof(SV*), char);
+           HeKEY_hek(&mh) = (HEK*)k;
+       }
+       HeSVKEY_set(&mh, keysv);
+       HeVAL(&mh) = sv;
+       return &mh;
     }
 
     xhv = (XPVHV*)SvANY(hv);
@@ -204,7 +206,7 @@ register U32 hash;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (memcmp(HeKEY(entry),key,klen))      /* is this it? */
+       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
            continue;
        return entry;
     }
@@ -212,7 +214,7 @@ register U32 hash;
     if (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME)) {
       char *gotenv;
 
-      gotenv = my_getenv(key);
+      gotenv = ENV_getenv(key);
       if (gotenv != NULL) {
         sv = newSVpv(gotenv,strlen(gotenv));
         return hv_store_ent(hv,keysv,sv,hash);
@@ -245,14 +247,14 @@ register U32 hash;
     xhv = (XPVHV*)SvANY(hv);
     if (SvMAGICAL(hv)) {
        mg_copy((SV*)hv, val, key, klen);
-#ifndef OVERLOAD
-       if (!xhv->xhv_array)
-           return 0;
-#else
-       if (!xhv->xhv_array && (SvMAGIC(hv)->mg_type != 'A'
-                               || SvMAGIC(hv)->mg_moremagic))
-         return 0;
+       if (!xhv->xhv_array
+           && (SvMAGIC(hv)->mg_moremagic
+               || (SvMAGIC(hv)->mg_type != 'E'
+#ifdef OVERLOAD
+                   && SvMAGIC(hv)->mg_type != 'A'
 #endif /* OVERLOAD */
+                   )))
+           return 0;
     }
     if (!hash)
        PERL_HASH(hash, key, klen);
@@ -268,7 +270,7 @@ register U32 hash;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (memcmp(HeKEY(entry),key,klen))      /* is this it? */
+       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
            continue;
        SvREFCNT_dec(HeVAL(entry));
        HeVAL(entry) = val;
@@ -277,9 +279,9 @@ register U32 hash;
 
     entry = new_he();
     if (HvSHAREKEYS(hv))
-       HeKEY_hk(entry) = share_hek(key, klen, hash);
+       HeKEY_hek(entry) = share_hek(key, klen, hash);
     else                                       /* gotta do the real thing */
-       HeKEY_hk(entry) = save_hek(key, klen, hash);
+       HeKEY_hek(entry) = save_hek(key, klen, hash);
     HeVAL(entry) = val;
     HeNEXT(entry) = *oentry;
     *oentry = entry;
@@ -315,14 +317,14 @@ register U32 hash;
     if (SvMAGICAL(hv)) {
        keysv = sv_2mortal(newSVsv(keysv));
        mg_copy((SV*)hv, val, (char*)keysv, HEf_SVKEY);
-#ifndef OVERLOAD
-       if (!xhv->xhv_array)
-           return Nullhe;
-#else
-       if (!xhv->xhv_array && (SvMAGIC(hv)->mg_type != 'A'
-                               || SvMAGIC(hv)->mg_moremagic))
-         return Nullhe;
+       if (!xhv->xhv_array
+           && (SvMAGIC(hv)->mg_moremagic
+               || (SvMAGIC(hv)->mg_type != 'E'
+#ifdef OVERLOAD
+                   && SvMAGIC(hv)->mg_type != 'A'
 #endif /* OVERLOAD */
+                   )))
+         return Nullhe;
     }
 
     key = SvPV(keysv, klen);
@@ -341,7 +343,7 @@ register U32 hash;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (memcmp(HeKEY(entry),key,klen))      /* is this it? */
+       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
            continue;
        SvREFCNT_dec(HeVAL(entry));
        HeVAL(entry) = val;
@@ -350,9 +352,9 @@ register U32 hash;
 
     entry = new_he();
     if (HvSHAREKEYS(hv))
-       HeKEY_hk(entry) = share_hek(key, klen, hash);
+       HeKEY_hek(entry) = share_hek(key, klen, hash);
     else                                       /* gotta do the real thing */
-       HeKEY_hk(entry) = save_hek(key, klen, hash);
+       HeKEY_hek(entry) = save_hek(key, klen, hash);
     HeVAL(entry) = val;
     HeNEXT(entry) = *oentry;
     *oentry = entry;
@@ -408,7 +410,7 @@ I32 flags;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (memcmp(HeKEY(entry),key,klen))      /* is this it? */
+       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
            continue;
        *oentry = HeNEXT(entry);
        if (i && !*oentry)
@@ -420,7 +422,7 @@ I32 flags;
        if (entry == xhv->xhv_eiter)
            HvLAZYDEL_on(hv);
        else
-           he_free(entry, HvSHAREKEYS(hv));
+           he_free(hv, entry);
        --xhv->xhv_keys;
        return sv;
     }
@@ -470,7 +472,7 @@ U32 hash;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (memcmp(HeKEY(entry),key,klen))      /* is this it? */
+       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
            continue;
        *oentry = HeNEXT(entry);
        if (i && !*oentry)
@@ -482,7 +484,7 @@ U32 hash;
        if (entry == xhv->xhv_eiter)
            HvLAZYDEL_on(hv);
        else
-           he_free(entry, HvSHAREKEYS(hv));
+           he_free(hv, entry);
        --xhv->xhv_keys;
        return sv;
     }
@@ -524,7 +526,7 @@ U32 klen;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (memcmp(HeKEY(entry),key,klen))      /* is this it? */
+       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
            continue;
        return TRUE;
     }
@@ -571,7 +573,7 @@ U32 hash;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (memcmp(HeKEY(entry),key,klen))      /* is this it? */
+       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
            continue;
        return TRUE;
     }
@@ -743,38 +745,44 @@ newHV()
 }
 
 void
-he_free(hent, shared)
+he_free(hv, hent)
+HV *hv;
 register HE *hent;
-I32 shared;
 {
     if (!hent)
        return;
+    if (isGV(HeVAL(hent)) && GvCVu(HeVAL(hent)) && HvNAME(hv))
+       sub_generation++;       /* may be deletion of method from stash */
     SvREFCNT_dec(HeVAL(hent));
     if (HeKLEN(hent) == HEf_SVKEY) {
        SvREFCNT_dec(HeKEY_sv(hent));
-        Safefree(HeKEY_hk(hent));
-    } else if (shared)
-       unshare_hek(HeKEY_hk(hent));
+        Safefree(HeKEY_hek(hent));
+    }
+    else if (HvSHAREKEYS(hv))
+       unshare_hek(HeKEY_hek(hent));
     else
-       Safefree(HeKEY_hk(hent));
+       Safefree(HeKEY_hek(hent));
     del_he(hent);
 }
 
 void
-he_delayfree(hent, shared)
+he_delayfree(hv, hent)
+HV *hv;
 register HE *hent;
-I32 shared;
 {
     if (!hent)
        return;
+    if (isGV(HeVAL(hent)) && GvCVu(HeVAL(hent)) && HvNAME(hv))
+       sub_generation++;       /* may be deletion of method from stash */
     sv_2mortal(HeVAL(hent));   /* free between statements */
     if (HeKLEN(hent) == HEf_SVKEY) {
        sv_2mortal(HeKEY_sv(hent));
-       Safefree(HeKEY_hk(hent));
-    } else if (shared)
-       unshare_hek(HeKEY_hk(hent));
+       Safefree(HeKEY_hek(hent));
+    }
+    else if (HvSHAREKEYS(hv))
+       unshare_hek(HeKEY_hek(hent));
     else
-       Safefree(HeKEY_hk(hent));
+       Safefree(HeKEY_hek(hent));
     del_he(hent);
 }
 
@@ -805,7 +813,6 @@ HV *hv;
     register HE *ohent = Null(HE*);
     I32 riter;
     I32 max;
-    I32 shared;
 
     if (!hv)
        return;
@@ -816,12 +823,11 @@ HV *hv;
     max = HvMAX(hv);
     array = HvARRAY(hv);
     hent = array[0];
-    shared = HvSHAREKEYS(hv);
     for (;;) {
        if (hent) {
            ohent = hent;
            hent = HeNEXT(hent);
-           he_free(ohent, shared);
+           he_free(hv, ohent);
        }
        if (!hent) {
            if (++riter > max)
@@ -847,7 +853,7 @@ HV *hv;
        HvNAME(hv) = 0;
     }
     xhv->xhv_array = 0;
-    xhv->xhv_max = 7;          /* it's a normal associative array */
+    xhv->xhv_max = 7;          /* it's a normal hash */
     xhv->xhv_fill = 0;
     xhv->xhv_keys = 0;
 
@@ -859,14 +865,20 @@ I32
 hv_iterinit(hv)
 HV *hv;
 {
-    register XPVHV* xhv = (XPVHV*)SvANY(hv);
-    HE *entry = xhv->xhv_eiter;
+    register XPVHV* xhv;
+    HE *entry;
+
+    if (!hv)
+       croak("Bad hash");
+    xhv = (XPVHV*)SvANY(hv);
+    entry = xhv->xhv_eiter;
 #ifdef DYNAMIC_ENV_FETCH  /* set up %ENV for iteration */
-    if (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME)) prime_env_iter();
+    if (HvNAME(hv) && strEQ(HvNAME(hv), ENV_HV_NAME))
+       prime_env_iter();
 #endif
     if (entry && HvLAZYDEL(hv)) {      /* was deleted earlier? */
        HvLAZYDEL_off(hv);
-       he_free(entry, HvSHAREKEYS(hv));
+       he_free(hv, entry);
     }
     xhv->xhv_riter = -1;
     xhv->xhv_eiter = Null(HE*);
@@ -883,7 +895,7 @@ HV *hv;
     MAGIC* mg;
 
     if (!hv)
-       croak("Bad associative array");
+       croak("Bad hash");
     xhv = (XPVHV*)SvANY(hv);
     oldentry = entry = xhv->xhv_eiter;
 
@@ -894,11 +906,14 @@ HV *hv;
            SvREFCNT_dec(HeSVKEY(entry));       /* get rid of previous key */
        }
        else {
+           char *k;
            HEK *hek;
-           xhv->xhv_eiter = entry = new_he();  /* only one HE per MAGICAL hash */
+
+           xhv->xhv_eiter = entry = new_he();  /* one HE per MAGICAL hash */
            Zero(entry, 1, HE);
-           Newz(74, hek, 1, HEK);
-           HeKEY_hk(entry) = hek;
+           Newz(54, k, HEK_BASESIZE + sizeof(SV*), char);
+           hek = (HEK*)k;
+           HeKEY_hek(entry) = hek;
            HeKLEN(entry) = HEf_SVKEY;
        }
        magic_nextpack((SV*) hv,mg,key);
@@ -909,7 +924,7 @@ HV *hv;
         }
        if (HeVAL(entry))
            SvREFCNT_dec(HeVAL(entry));
-       Safefree(HeKEY_hk(entry));
+       Safefree(HeKEY_hek(entry));
        del_he(entry);
        xhv->xhv_eiter = Null(HE*);
        return Null(HE*);
@@ -930,7 +945,7 @@ HV *hv;
 
     if (oldentry && HvLAZYDEL(hv)) {           /* was deleted earlier? */
        HvLAZYDEL_off(hv);
-       he_free(oldentry, HvSHAREKEYS(hv));
+       he_free(hv, oldentry);
     }
 
     xhv->xhv_eiter = entry;
@@ -1008,7 +1023,7 @@ char* sv;
 I32 len;
 U32 hash;
 {
-    return share_hek(sv, len, hash)->hk_key;
+    return HEK_KEY(share_hek(sv, len, hash));
 }
 
 /* possibly free a shared string if no one has access to it
@@ -1039,14 +1054,14 @@ U32 hash;
            continue;
        if (HeKLEN(entry) != len)
            continue;
-       if (memcmp(HeKEY(entry),str,len))               /* is this it? */
+       if (memNE(HeKEY(entry),str,len))        /* is this it? */
            continue;
        found = 1;
        if (--HeVAL(entry) == Nullsv) {
            *oentry = HeNEXT(entry);
            if (i && !*oentry)
                xhv->xhv_fill--;
-           Safefree(HeKEY_hk(entry));
+           Safefree(HeKEY_hek(entry));
            del_he(entry);
            --xhv->xhv_keys;
        }
@@ -1086,14 +1101,14 @@ register U32 hash;
            continue;
        if (HeKLEN(entry) != len)
            continue;
-       if (memcmp(HeKEY(entry),str,len))               /* is this it? */
+       if (memNE(HeKEY(entry),str,len))        /* is this it? */
            continue;
        found = 1;
        break;
     }
     if (!found) {
        entry = new_he();
-       HeKEY_hk(entry) = save_hek(str, len, hash);
+       HeKEY_hek(entry) = save_hek(str, len, hash);
        HeVAL(entry) = Nullsv;
        HeNEXT(entry) = *oentry;
        *oentry = entry;
@@ -1106,7 +1121,7 @@ register U32 hash;
     }
 
     ++HeVAL(entry);                            /* use value slot as REFCNT */
-    return HeKEY_hk(entry);
+    return HeKEY_hek(entry);
 }