This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Use a union for storing the shared hash key reference count, rather
[perl5.git] / hv.h
diff --git a/hv.h b/hv.h
index ddbdd80..fd0cf2e 100644 (file)
--- a/hv.h
+++ b/hv.h
@@ -8,15 +8,17 @@
  *
  */
 
-/* typedefs to eliminate some typing */
-typedef struct he HE;
-typedef struct hek HEK;
-
 /* entry in hash value chain */
 struct he {
+    /* Keep hent_next first in this structure, because sv_free_arenas take
+       advantage of this to share code between the he arenas and the SV
+       body arenas  */
     HE         *hent_next;     /* next entry in chain */
     HEK                *hent_hek;      /* hash key */
-    SV         *hent_val;      /* scalar value that was hashed */
+    union {
+       SV      *hent_val;      /* scalar value that was hashed */
+       Size_t  hent_refcount;  /* references for this shared hash key */
+    } he_valu;
 };
 
 /* hash key -- defined separately for use as shared pointer */
@@ -29,12 +31,17 @@ struct hek {
        is UTF-8 */
 };
 
+struct shared_he {
+    struct he shared_he_he;
+    struct hek shared_he_hek;
+};
 
 /* Subject to change.
    Don't access this directly.
 */
 struct xpvhv_aux {
-    char       *xhv_name;      /* name, if a symbol table */
+    HEK                *xhv_name;      /* name, if a symbol table */
+    AV         *xhv_backreferences; /* back references for weak references */
     HE         *xhv_eiter;     /* current entry of iterator */
     I32                xhv_riter;      /* current root of iterator */
 };
@@ -42,26 +49,19 @@ struct xpvhv_aux {
 /* hash structure: */
 /* This structure must match the beginning of struct xpvmg in sv.h. */
 struct xpvhv {
-    IV         for_rent;
+    NV         xnv_nv;         /* numeric value, if any */
     STRLEN     xhv_fill;       /* how full xhv_array currently is */
     STRLEN     xhv_max;        /* subscript of last element of xhv_array */
     union {
-       struct {
-           void *xnv_p1;
-           union {
-               void *xnv_p2;
-               IV xnv_i2;      /* how many elements in the array */
-           }   xnv_u2;
-       }       xnv_s;
-       NV      xnvu_nv;        /* numeric value, if any */
-    }          xnv_u;
+       IV      xivu_iv;        /* integer value or pv offset */
+       UV      xivu_uv;
+       void *  xivu_p1;
+    }          xiv_u;
     MAGIC*     xmg_magic;      /* magic for scalar array */
     HV*                xmg_stash;      /* class package */
-    /* list of pm's for this package is now stored in symtab magic.  */
 };
 
-#define xhv_aux xnv_u.xnv_s.xnv_p1
-#define xhv_keys xnv_u.xnv_s.xnv_u2.xnv_i2
+#define xhv_keys xiv_u.xivu_iv
 
 #if 0
 typedef struct xpvhv xpvhv_allocated;
@@ -70,15 +70,10 @@ typedef struct {
     STRLEN     xhv_fill;       /* how full xhv_array currently is */
     STRLEN     xhv_max;        /* subscript of last element of xhv_array */
     union {
-       NV      xnvu_nv;        /* numeric value, if any */
-       struct {
-           void *xnv_p1;
-           union {
-               void *xnv_p2;
-               IV xnv_i2;      /* how many elements in the array */
-           }   xnv_u2;
-       }       xnv_s;
-    }          xnv_u;
+       IV      xivu_iv;        /* integer value or pv offset */
+       UV      xivu_uv;
+       void *  xivu_p1;
+    }          xiv_u;
     MAGIC*     xmg_magic;      /* magic for scalar array */
     HV*                xmg_stash;      /* class package */
 } xpvhv_allocated;
@@ -91,7 +86,7 @@ typedef struct {
 /* The use of a temporary pointer and the casting games
  * is needed to serve the dual purposes of
  * (a) the hashed data being interpreted as "unsigned char" (new since 5.8,
- *     a "char" can be either signed or signed, depending on the compiler)
+ *     a "char" can be either signed or unsigned, depending on the compiler)
  * (b) catering for old code that uses a "char"
  *
  * The "hash seed" feature was added in Perl 5.8.1 to perturb the results
@@ -112,7 +107,7 @@ typedef struct {
 #endif
 #define PERL_HASH(hash,str,len) \
      STMT_START        { \
-       register const char *s_PeRlHaSh_tmp = str; \
+       register const char * const s_PeRlHaSh_tmp = str; \
        register const unsigned char *s_PeRlHaSh = (const unsigned char *)s_PeRlHaSh_tmp; \
        register I32 i_PeRlHaSh = len; \
        register U32 hash_PeRlHaSh = PERL_HASH_SEED; \
@@ -130,7 +125,7 @@ typedef struct {
 #ifdef PERL_HASH_INTERNAL_ACCESS
 #define PERL_HASH_INTERNAL(hash,str,len) \
      STMT_START        { \
-       register const char *s_PeRlHaSh_tmp = str; \
+       register const char * const s_PeRlHaSh_tmp = str; \
        register const unsigned char *s_PeRlHaSh = (const unsigned char *)s_PeRlHaSh_tmp; \
        register I32 i_PeRlHaSh = len; \
        register U32 hash_PeRlHaSh = PL_rehash_seed; \
@@ -161,7 +156,8 @@ Null HV pointer.
 =head1 Hash Manipulation Functions
 
 =for apidoc Am|char*|HvNAME|HV* stash
-Returns the package name of a stash.  See C<SvSTASH>, C<CvSTASH>.
+Returns the package name of a stash, or NULL if C<stash> isn't a stash.
+See C<SvSTASH>, C<CvSTASH>.
 
 =for apidoc Am|void*|HeKEY|HE* he
 Returns the actual pointer stored in the key slot of the hash entry. The
@@ -213,22 +209,27 @@ C<SV*>.
 
 
 #define Nullhv Null(HV*)
-#define HvARRAY(hv)    (*(HE***)&((hv)->sv_u.sv_array))
+#define HvARRAY(hv)    ((hv)->sv_u.svu_hash)
 #define HvFILL(hv)     ((XPVHV*)  SvANY(hv))->xhv_fill
 #define HvMAX(hv)      ((XPVHV*)  SvANY(hv))->xhv_max
+/* This quite intentionally does no flag checking first. That's your
+   responsibility.  */
+#define HvAUX(hv)      ((struct xpvhv_aux*)&(HvARRAY(hv)[HvMAX(hv)+1]))
 #define HvRITER(hv)    (*Perl_hv_riter_p(aTHX_ (HV*)(hv)))
 #define HvEITER(hv)    (*Perl_hv_eiter_p(aTHX_ (HV*)(hv)))
 #define HvRITER_set(hv,r)      Perl_hv_riter_set(aTHX_ (HV*)(hv), r)
 #define HvEITER_set(hv,e)      Perl_hv_eiter_set(aTHX_ (HV*)(hv), e)
-#define HvRITER_get(hv)        (((XPVHV *)SvANY(hv))->xhv_aux ? \
-                        ((struct xpvhv_aux*)((XPVHV *)SvANY(hv))->xhv_aux)->xhv_riter : -1)
-#define HvEITER_get(hv)        (((XPVHV *)SvANY(hv))->xhv_aux ? \
-                        ((struct xpvhv_aux *)((XPVHV *)SvANY(hv))->xhv_aux)->xhv_eiter : 0)
-#define HvNAME(hv)     (*Perl_hv_name_p(aTHX_ (HV*)hv))
+#define HvRITER_get(hv)        (SvOOK(hv) ? HvAUX(hv)->xhv_riter : -1)
+#define HvEITER_get(hv)        (SvOOK(hv) ? HvAUX(hv)->xhv_eiter : 0)
+#define HvNAME(hv)     HvNAME_get(hv)
 /* FIXME - all of these should use a UTF8 aware API, which should also involve
    getting the length. */
-#define HvNAME_get(hv) (((XPVHV *)SvANY(hv))->xhv_aux ? \
-                        ((struct xpvhv_aux *)((XPVHV *)SvANY(hv))->xhv_aux)->xhv_name : 0)
+/* This macro may go away without notice.  */
+#define HvNAME_HEK(hv) (SvOOK(hv) ? HvAUX(hv)->xhv_name : 0)
+#define HvNAME_get(hv) ((SvOOK(hv) && (HvAUX(hv)->xhv_name)) \
+                        ? HEK_KEY(HvAUX(hv)->xhv_name) : 0)
+#define HvNAMELEN_get(hv)      ((SvOOK(hv) && (HvAUX(hv)->xhv_name)) \
+                                ? HEK_LEN(HvAUX(hv)->xhv_name) : 0)
 
 /* the number of keys (including any placeholers) */
 #define XHvTOTALKEYS(xhv)      ((xhv)->xhv_keys)
@@ -293,7 +294,7 @@ C<SV*>.
 #define HeKREHASH(he)  HEK_REHASH(HeKEY_hek(he))
 #define HeKLEN_UTF8(he)  (HeKUTF8(he) ? -HeKLEN(he) : HeKLEN(he))
 #define HeKFLAGS(he)  HEK_FLAGS(HeKEY_hek(he))
-#define HeVAL(he)              (he)->hent_val
+#define HeVAL(he)              (he)->he_valu.hent_val
 #define HeHASH(he)             HEK_HASH(HeKEY_hek(he))
 #define HePV(he,lp)            ((HeKLEN(he) == HEf_SVKEY) ?            \
                                 SvPV(HeKEY_sv(he),lp) :                \
@@ -363,10 +364,20 @@ C<SV*>.
 /* Flags for hv_iternext_flags.  */
 #define HV_ITERNEXT_WANTPLACEHOLDERS   0x01    /* Don't skip placeholders.  */
 
+#define hv_iternext(hv)        hv_iternext_flags(hv, 0)
+#define hv_magic(hv, gv, how) sv_magic((SV*)(hv), (SV*)(gv), how, Nullch, 0)
+
 /* available as a function in hv.c */
 #define Perl_sharepvn(sv, len, hash) HEK_KEY(share_hek(sv, len, hash))
 #define sharepvn(sv, len, hash)             Perl_sharepvn(sv, len, hash)
 
+#define share_hek_hek(hek)                                             \
+    (++(((struct shared_he *)(((char *)hek)                            \
+                             - STRUCT_OFFSET(struct shared_he,         \
+                                             shared_he_hek)))          \
+       ->shared_he_he.he_valu.hent_refcount),                          \
+     hek)
+
 /*
  * Local variables:
  * c-indentation-style: bsd