LC_COLLATE.
[p5sagit/p5-mst-13.2.git] / hv.c
diff --git a/hv.c b/hv.c
index a2ddf7b..9547f2c 100644 (file)
--- a/hv.c
+++ b/hv.c
@@ -102,7 +102,7 @@ I32 lval;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (bcmp(HeKEY(entry),key,klen))        /* is this it? */
+       if (memcmp(HeKEY(entry),key,klen))      /* is this it? */
            continue;
        return &HeVAL(entry);
     }
@@ -142,28 +142,18 @@ register U32 hash;
     if (!hv)
        return 0;
 
-    xhv = (XPVHV*)SvANY(hv);
-
     if (SvRMAGICAL(hv) && mg_find((SV*)hv,'P')) {
-       if (!(entry = xhv->xhv_eiter)) {
-           xhv->xhv_eiter = entry = new_he();  /* only one HE per MAGICAL hash */
-           Zero(entry, 1, HE);
-           HeKLEN(entry) = HEf_SVKEY;          /* hent_key is holding an SV* */
-       }
-       else if ((sv = HeSVKEY(entry)))
-           SvREFCNT_dec(sv);
        sv = sv_newmortal();
+       keysv = sv_2mortal(newSVsv(keysv));
        mg_copy((SV*)hv, sv, (char*)keysv, HEf_SVKEY);
+       entry = &He;
        HeVAL(entry) = sv;
-       HeKEY(entry) = (char*)SvREFCNT_inc(keysv);
+       HeKEY(entry) = (char*)keysv;
+       HeKLEN(entry) = HEf_SVKEY;              /* hent_key is holding an SV* */
        return entry;
     }
 
-    key = SvPV(keysv, klen);
-    
-    if (!hash)
-       PERL_HASH(hash, key, klen);
-
+    xhv = (XPVHV*)SvANY(hv);
     if (!xhv->xhv_array) {
        if (lval 
 #ifdef DYNAMIC_ENV_FETCH  /* if it's an %ENV lookup, we may get it on the fly */
@@ -175,13 +165,18 @@ register U32 hash;
            return 0;
     }
 
+    key = SvPV(keysv, klen);
+    
+    if (!hash)
+       PERL_HASH(hash, key, klen);
+
     entry = ((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max];
     for (; entry; entry = HeNEXT(entry)) {
        if (HeHASH(entry) != hash)              /* strings can't be equal */
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (bcmp(HeKEY(entry),key,klen))        /* is this it? */
+       if (memcmp(HeKEY(entry),key,klen))      /* is this it? */
            continue;
        return entry;
     }
@@ -245,7 +240,7 @@ register U32 hash;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (bcmp(HeKEY(entry),key,klen))        /* is this it? */
+       if (memcmp(HeKEY(entry),key,klen))      /* is this it? */
            continue;
        SvREFCNT_dec(HeVAL(entry));
        HeVAL(entry) = val;
@@ -292,6 +287,7 @@ register U32 hash;
 
     xhv = (XPVHV*)SvANY(hv);
     if (SvMAGICAL(hv)) {
+       keysv = sv_2mortal(newSVsv(keysv));
        mg_copy((SV*)hv, val, (char*)keysv, HEf_SVKEY);
 #ifndef OVERLOAD
        if (!xhv->xhv_array)
@@ -319,7 +315,7 @@ register U32 hash;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (bcmp(HeKEY(entry),key,klen))        /* is this it? */
+       if (memcmp(HeKEY(entry),key,klen))      /* is this it? */
            continue;
        SvREFCNT_dec(HeVAL(entry));
        HeVAL(entry) = val;
@@ -388,7 +384,7 @@ I32 flags;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (bcmp(HeKEY(entry),key,klen))        /* is this it? */
+       if (memcmp(HeKEY(entry),key,klen))      /* is this it? */
            continue;
        *oentry = HeNEXT(entry);
        if (i && !*oentry)
@@ -398,7 +394,7 @@ I32 flags;
        else
            sv = sv_mortalcopy(HeVAL(entry));
        if (entry == xhv->xhv_eiter)
-           HeKLEN(entry) = HEf_LAZYDEL;
+           HvLAZYDEL_on(hv);
        else
            he_free(entry, HvSHAREKEYS(hv));
        --xhv->xhv_keys;
@@ -450,7 +446,7 @@ U32 hash;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (bcmp(HeKEY(entry),key,klen))        /* is this it? */
+       if (memcmp(HeKEY(entry),key,klen))      /* is this it? */
            continue;
        *oentry = HeNEXT(entry);
        if (i && !*oentry)
@@ -460,7 +456,7 @@ U32 hash;
        else
            sv = sv_mortalcopy(HeVAL(entry));
        if (entry == xhv->xhv_eiter)
-           HeKLEN(entry) = HEf_LAZYDEL;
+           HvLAZYDEL_on(hv);
        else
            he_free(entry, HvSHAREKEYS(hv));
        --xhv->xhv_keys;
@@ -504,7 +500,7 @@ U32 klen;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (bcmp(HeKEY(entry),key,klen))        /* is this it? */
+       if (memcmp(HeKEY(entry),key,klen))      /* is this it? */
            continue;
        return TRUE;
     }
@@ -530,6 +526,7 @@ U32 hash;
     if (SvRMAGICAL(hv)) {
        if (mg_find((SV*)hv,'P')) {
            sv = sv_newmortal();
+           keysv = sv_2mortal(newSVsv(keysv));
            mg_copy((SV*)hv, sv, (char*)keysv, HEf_SVKEY); 
            magic_existspack(sv, mg_find(sv, 'p'));
            return SvTRUE(sv);
@@ -550,7 +547,7 @@ U32 hash;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (bcmp(HeKEY(entry),key,klen))        /* is this it? */
+       if (memcmp(HeKEY(entry),key,klen))      /* is this it? */
            continue;
        return TRUE;
     }
@@ -622,6 +619,84 @@ HV *hv;
     }
 }
 
+void
+hv_ksplit(hv, newmax)
+HV *hv;
+IV newmax;
+{
+    register XPVHV* xhv = (XPVHV*)SvANY(hv);
+    I32 oldsize = (I32) xhv->xhv_max + 1; /* sic(k) */
+    register I32 newsize;
+    register I32 i;
+    register I32 j;
+    register HE **a;
+    register HE *entry;
+    register HE **oentry;
+
+    newsize = (I32) newmax;                    /* possible truncation here */
+    if (newsize != newmax || newmax <= oldsize)
+       return;
+    while ((newsize & (1 + ~newsize)) != newsize) {
+       newsize &= ~(newsize & (1 + ~newsize)); /* get proper power of 2 */
+    }
+    if (newsize < newmax)
+       newsize *= 2;
+    if (newsize < newmax)
+       return;                                 /* overflow detection */
+
+    a = (HE**)xhv->xhv_array;
+    if (a) {
+       nomemok = TRUE;
+#ifdef STRANGE_MALLOC
+       Renew(a, newsize, HE*);
+#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*);
+       if (oldsize >= 64 && !nice_chunk) {
+           nice_chunk = (char*)xhv->xhv_array;
+           nice_chunk_size = oldsize * sizeof(HE*) * 2 - MALLOC_OVERHEAD;
+       }
+       else
+           Safefree(xhv->xhv_array);
+#endif
+       nomemok = FALSE;
+       Zero(&a[oldsize], newsize-oldsize, HE*); /* zero 2nd half*/
+    }
+    else {
+       Newz(0, a, newsize, HE*);
+    }
+    xhv->xhv_max = --newsize;
+    xhv->xhv_array = (char*)a;
+    if (!xhv->xhv_fill)                                /* skip rest if no entries */
+       return;
+
+    for (i=0; i<oldsize; i++,a++) {
+       if (!*a)                                /* non-existent */
+           continue;
+       for (oentry = a, entry = *a; entry; entry = *oentry) {
+           if ((j = (HeHASH(entry) & newsize)) != i) {
+               j -= i;
+               *oentry = HeNEXT(entry);
+               if (!(HeNEXT(entry) = a[j]))
+                   xhv->xhv_fill++;
+               a[j] = entry;
+               continue;
+           }
+           else
+               oentry = &HeNEXT(entry);
+       }
+       if (!*a)                                /* everything moved */
+           xhv->xhv_fill--;
+    }
+}
+
 HV *
 newHV()
 {
@@ -760,8 +835,13 @@ HV *hv;
 {
     register XPVHV* xhv = (XPVHV*)SvANY(hv);
     HE *entry = xhv->xhv_eiter;
-    if (entry && HeKLEN(entry) == HEf_LAZYDEL) /* was deleted earlier? */
+#ifdef DYNAMIC_ENV_FETCH  /* set up %ENV for iteration */
+    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));
+    }
     xhv->xhv_riter = -1;
     xhv->xhv_eiter = Null(HE*);
     return xhv->xhv_fill;
@@ -783,16 +863,18 @@ HV *hv;
 
     if (SvRMAGICAL(hv) && (mg = mg_find((SV*)hv,'P'))) {
        SV *key = sv_newmortal();
-       if (entry)
+       if (entry) {
            sv_setsv(key, HeSVKEY_force(entry));
+           SvREFCNT_dec(HeSVKEY(entry));       /* get rid of previous key */
+       }
        else {
-           xhv->xhv_eiter = entry = new_he();   /* only one HE per MAGICAL hash */
+           xhv->xhv_eiter = entry = new_he();  /* only one HE per MAGICAL hash */
            Zero(entry, 1, HE);
            HeKLEN(entry) = HEf_SVKEY;
        }
        magic_nextpack((SV*) hv,mg,key);
         if (SvOK(key)) {
-           SvREFCNT_dec(HeSVKEY(entry));
+           /* force key to stay around until next time */
            HeKEY(entry) = (char*)SvREFCNT_inc(key);
            return entry;                       /* beware, hent_val is not set */
         }
@@ -816,8 +898,10 @@ HV *hv;
        entry = ((HE**)xhv->xhv_array)[xhv->xhv_riter];
     }
 
-    if (oldentry && HeKLEN(oldentry) == HEf_LAZYDEL)   /* was deleted earlier? */
+    if (oldentry && HvLAZYDEL(hv)) {           /* was deleted earlier? */
+       HvLAZYDEL_off(hv);
        he_free(oldentry, HvSHAREKEYS(hv));
+    }
 
     xhv->xhv_eiter = entry;
     return entry;
@@ -915,7 +999,7 @@ register U32 hash;
            continue;
        if (HeKLEN(entry) != len)
            continue;
-       if (bcmp(HeKEY(entry),str,len))         /* is this it? */
+       if (memcmp(HeKEY(entry),str,len))               /* is this it? */
            continue;
        found = 1;
        break;
@@ -968,7 +1052,7 @@ register U32 hash;
            continue;
        if (HeKLEN(entry) != len)
            continue;
-       if (bcmp(HeKEY(entry),str,len))         /* is this it? */
+       if (memcmp(HeKEY(entry),str,len))               /* is this it? */
            continue;
        found = 1;
        if (--HeVAL(entry) == Nullsv) {