Skip another file in the VERSION comparison program
[p5sagit/p5-mst-13.2.git] / hv.c
diff --git a/hv.c b/hv.c
index 98cdc31..c394e73 100644 (file)
--- a/hv.c
+++ b/hv.c
@@ -1094,7 +1094,7 @@ S_hsplit(pTHX_ HV *hv)
       return;
     }
     if (SvOOK(hv)) {
-       Copy(&a[oldsize * sizeof(HE*)], &a[newsize * sizeof(HE*)], 1, struct xpvhv_aux);
+       Move(&a[oldsize * sizeof(HE*)], &a[newsize * sizeof(HE*)], 1, struct xpvhv_aux);
     }
 #else
     Newx(a, PERL_HV_ARRAY_ALLOC_BYTES(newsize)
@@ -1985,6 +1985,7 @@ Perl_hv_kill_backrefs(pTHX_ HV *hv) {
     if (av) {
        HvAUX(hv)->xhv_backreferences = 0;
        Perl_sv_kill_backrefs(aTHX_ (SV*) hv, av);
+       SvREFCNT_dec(av);
     }
 }
 
@@ -2686,49 +2687,53 @@ Perl_refcounted_he_fetch(pTHX_ const struct refcounted_he *chain, SV *keysv,
     /* Just to be awkward, if you're using this interface the UTF-8-or-not-ness
        of your key has to exactly match that which is stored.  */
     SV *value = &PL_sv_placeholder;
-    bool is_utf8;
 
-    if (keysv) {
-       if (flags & HVhek_FREEKEY)
-           Safefree(key);
-       key = SvPV_const(keysv, klen);
-       flags = 0;
-       is_utf8 = (SvUTF8(keysv) != 0);
-    } else {
-       is_utf8 = ((flags & HVhek_UTF8) ? TRUE : FALSE);
-    }
+    if (chain) {
+       /* No point in doing any of this if there's nothing to find.  */
+       bool is_utf8;
 
-    if (!hash) {
-       if (keysv && (SvIsCOW_shared_hash(keysv))) {
-            hash = SvSHARED_HASH(keysv);
-        } else {
-            PERL_HASH(hash, key, klen);
-        }
-    }
+       if (keysv) {
+           if (flags & HVhek_FREEKEY)
+               Safefree(key);
+           key = SvPV_const(keysv, klen);
+           flags = 0;
+           is_utf8 = (SvUTF8(keysv) != 0);
+       } else {
+           is_utf8 = ((flags & HVhek_UTF8) ? TRUE : FALSE);
+       }
+
+       if (!hash) {
+           if (keysv && (SvIsCOW_shared_hash(keysv))) {
+               hash = SvSHARED_HASH(keysv);
+           } else {
+               PERL_HASH(hash, key, klen);
+           }
+       }
 
-    for (; chain; chain = chain->refcounted_he_next) {
+       for (; chain; chain = chain->refcounted_he_next) {
 #ifdef USE_ITHREADS
-       if (hash != chain->refcounted_he_hash)
-           continue;
-       if (klen != chain->refcounted_he_keylen)
-           continue;
-       if (memNE(REF_HE_KEY(chain),key,klen))
-           continue;
-       if (!!is_utf8 != !!(chain->refcounted_he_data[0] & HVhek_UTF8))
-           continue;
+           if (hash != chain->refcounted_he_hash)
+               continue;
+           if (klen != chain->refcounted_he_keylen)
+               continue;
+           if (memNE(REF_HE_KEY(chain),key,klen))
+               continue;
+           if (!!is_utf8 != !!(chain->refcounted_he_data[0] & HVhek_UTF8))
+               continue;
 #else
-       if (hash != HEK_HASH(chain->refcounted_he_hek))
-           continue;
-       if (klen != (STRLEN)HEK_LEN(chain->refcounted_he_hek))
-           continue;
-       if (memNE(HEK_KEY(chain->refcounted_he_hek),key,klen))
-           continue;
-       if (!!is_utf8 != !!HEK_UTF8(chain->refcounted_he_hek))
-           continue;
+           if (hash != HEK_HASH(chain->refcounted_he_hek))
+               continue;
+           if (klen != (STRLEN)HEK_LEN(chain->refcounted_he_hek))
+               continue;
+           if (memNE(HEK_KEY(chain->refcounted_he_hek),key,klen))
+               continue;
+           if (!!is_utf8 != !!HEK_UTF8(chain->refcounted_he_hek))
+               continue;
 #endif
 
-       value = sv_2mortal(refcounted_he_value(chain));
-       break;
+           value = sv_2mortal(refcounted_he_value(chain));
+           break;
+       }
     }
 
     if (flags & HVhek_FREEKEY)
@@ -2751,21 +2756,18 @@ struct refcounted_he *
 Perl_refcounted_he_new(pTHX_ struct refcounted_he *const parent,
                       SV *const key, SV *const value) {
     dVAR;
-    struct refcounted_he *he;
     STRLEN key_len;
     const char *key_p = SvPV_const(key, key_len);
     STRLEN value_len = 0;
     const char *value_p = NULL;
     char value_type;
     char flags;
-    STRLEN key_offset;
-    U32 hash;
     bool is_utf8 = SvUTF8(key) ? TRUE : FALSE;
 
     if (SvPOK(value)) {
        value_type = HVrhek_PV;
     } else if (SvIOK(value)) {
-       value_type = HVrhek_IV;
+       value_type = SvUOK((SV*)value) ? HVrhek_UV : HVrhek_IV;
     } else if (value == &PL_sv_placeholder) {
        value_type = HVrhek_delete;
     } else if (!SvOK(value)) {
@@ -2775,13 +2777,42 @@ Perl_refcounted_he_new(pTHX_ struct refcounted_he *const parent,
     }
 
     if (value_type == HVrhek_PV) {
+       /* Do it this way so that the SvUTF8() test is after the SvPV, in case
+          the value is overloaded, and doesn't yet have the UTF-8flag set.  */
        value_p = SvPV_const(value, value_len);
-       key_offset = value_len + 2;
-    } else {
-       value_len = 0;
-       key_offset = 1;
+       if (SvUTF8(value))
+           value_type = HVrhek_PV_UTF8;
+    }
+    flags = value_type;
+
+    if (is_utf8) {
+       /* Hash keys are always stored normalised to (yes) ISO-8859-1.
+          As we're going to be building hash keys from this value in future,
+          normalise it now.  */
+       key_p = (char*)bytes_from_utf8((const U8*)key_p, &key_len, &is_utf8);
+       flags |= is_utf8 ? HVhek_UTF8 : HVhek_WASUTF8;
     }
 
+    return refcounted_he_new_common(parent, key_p, key_len, flags, value_type,
+                                   ((value_type == HVrhek_PV
+                                     || value_type == HVrhek_PV_UTF8) ?
+                                    (void *)value_p : (void *)value),
+                                   value_len);
+}
+
+struct refcounted_he *
+S_refcounted_he_new_common(pTHX_ struct refcounted_he *const parent,
+                          const char *const key_p, const STRLEN key_len,
+                          const char flags, char value_type,
+                          const void *value, const STRLEN value_len) {
+    dVAR;
+    struct refcounted_he *he;
+    U32 hash;
+    const bool is_pv = value_type == HVrhek_PV || value_type == HVrhek_PV_UTF8;
+    STRLEN key_offset = is_pv ? value_len + 2 : 1;
+
+    PERL_ARGS_ASSERT_REFCOUNTED_HE_NEW_COMMON;
+
 #ifdef USE_ITHREADS
     he = (struct refcounted_he*)
        PerlMemShared_malloc(sizeof(struct refcounted_he) - 1
@@ -2793,33 +2824,17 @@ Perl_refcounted_he_new(pTHX_ struct refcounted_he *const parent,
                             + key_offset);
 #endif
 
-
     he->refcounted_he_next = parent;
 
-    if (value_type == HVrhek_PV) {
-       Copy(value_p, he->refcounted_he_data + 1, value_len + 1, char);
+    if (is_pv) {
+       Copy((char *)value, he->refcounted_he_data + 1, value_len + 1, char);
        he->refcounted_he_val.refcounted_he_u_len = value_len;
-       /* Do it this way so that the SvUTF8() test is after the SvPV, in case
-          the value is overloaded, and doesn't yet have the UTF-8flag set.  */
-       if (SvUTF8(value))
-           value_type = HVrhek_PV_UTF8;
     } else if (value_type == HVrhek_IV) {
-       if (SvUOK(value)) {
-           he->refcounted_he_val.refcounted_he_u_uv = SvUVX(value);
-           value_type = HVrhek_UV;
-       } else {
-           he->refcounted_he_val.refcounted_he_u_iv = SvIVX(value);
-       }
+       he->refcounted_he_val.refcounted_he_u_iv = SvIVX((SV *)value);
+    } else if (value_type == HVrhek_UV) {
+       he->refcounted_he_val.refcounted_he_u_uv = SvUVX((SV *)value);
     }
-    flags = value_type;
 
-    if (is_utf8) {
-       /* Hash keys are always stored normalised to (yes) ISO-8859-1.
-          As we're going to be building hash keys from this value in future,
-          normalise it now.  */
-       key_p = (char*)bytes_from_utf8((const U8*)key_p, &key_len, &is_utf8);
-       flags |= is_utf8 ? HVhek_UTF8 : HVhek_WASUTF8;
-    }
     PERL_HASH(hash, key_p, key_len);
 
 #ifdef USE_ITHREADS
@@ -2894,6 +2909,12 @@ Perl_fetch_cop_label(pTHX_ struct refcounted_he *const chain, STRLEN *len,
     if (*HEK_KEY(chain->refcounted_he_hek) != ':')
        return NULL;
 #endif
+    /* Stop anyone trying to really mess us up by adding their own value for
+       ':' into %^H  */
+    if ((chain->refcounted_he_data[0] & HVrhek_typemask) != HVrhek_PV
+       && (chain->refcounted_he_data[0] & HVrhek_typemask) != HVrhek_PV_UTF8)
+       return NULL;
+
     if (len)
        *len = chain->refcounted_he_val.refcounted_he_u_len;
     if (flags) {
@@ -2903,6 +2924,18 @@ Perl_fetch_cop_label(pTHX_ struct refcounted_he *const chain, STRLEN *len,
     return chain->refcounted_he_data + 1;
 }
 
+/* As newSTATEOP currently gets passed plain char* labels, we will only provide
+   that interface. Once it works out how to pass in length and UTF-8 ness, this
+   function will need superseding.  */
+struct refcounted_he *
+Perl_store_cop_label(pTHX_ struct refcounted_he *const chain, const char *label)
+{
+    PERL_ARGS_ASSERT_STORE_COP_LABEL;
+
+    return refcounted_he_new_common(chain, ":", 1, HVrhek_PV, HVrhek_PV,
+                                   label, strlen(label));
+}
+
 /*
 =for apidoc hv_assert