From: Nicholas Clark <nick@ccl4.org>
Date: Sat, 21 May 2005 09:29:18 +0000 (+0000)
Subject: Move placeholders into a new rhash magic type.
X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=ca732855658630b07dee4aa9ea6ae952226bd828;p=p5sagit%2Fp5-mst-13.2.git

Move placeholders into a new rhash magic type.

p4raw-id: //depot/perl@24525
---

diff --git a/dump.c b/dump.c
index 1b565b3..f3d6657 100644
--- a/dump.c
+++ b/dump.c
@@ -890,6 +890,7 @@ Perl_gv_dump(pTHX_ GV *gv)
 static const struct { const char type; const char *name; } magic_names[] = {
 	{ PERL_MAGIC_sv,             "sv(\\0)" },
 	{ PERL_MAGIC_arylen,         "arylen(#)" },
+	{ PERL_MAGIC_rhash,          "rhash(%)" },
 	{ PERL_MAGIC_glob,           "glob(*)" },
 	{ PERL_MAGIC_pos,            "pos(.)" },
 	{ PERL_MAGIC_symtab,         "symtab(:)" },
diff --git a/embed.fnc b/embed.fnc
index c774a42..11c362e 100644
--- a/embed.fnc
+++ b/embed.fnc
@@ -1397,6 +1397,11 @@ sM	|HE*	|hv_fetch_common|HV* tb|SV* key_sv|const char* key|STRLEN klen|int flags
 Apd	|void	|hv_clear_placeholders|HV* hb
 
 Apd	|SV*	|hv_scalar	|HV* hv|
+
+Apo	|I32*	|hv_placeholders_p	|HV* hv
+Apo	|I32	|hv_placeholders_get	|HV* hv
+Apo	|void	|hv_placeholders_set	|HV* hv|I32 ph
+
 p	|SV*	|magic_scalarpack|HV* hv|MAGIC*	mg
 #ifdef PERL_IN_SV_C
 sMd	|SV*	|find_uninit_var|OP* obase|SV* uninit_sv|bool top
diff --git a/ext/Storable/Storable.xs b/ext/Storable/Storable.xs
index 87f94e1..68d8e26 100644
--- a/ext/Storable/Storable.xs
+++ b/ext/Storable/Storable.xs
@@ -107,6 +107,10 @@ typedef double NV;			/* Older perls lack the NV type */
 #define dVAR dNOOP
 #endif
 
+#ifndef HvPLACEHOLDERS_get
+#  define HvPLACEHOLDERS_get HvPLACEHOLDERS
+#endif
+
 #ifdef DEBUGME
 
 #ifndef DASSERT
@@ -2303,7 +2307,7 @@ static int store_hash(pTHX_ stcxt_t *cxt, HV *hv)
 
 		for (i = 0; i < len; i++) {
 #ifdef HAS_RESTRICTED_HASHES
-			int placeholders = (int)HvPLACEHOLDERS(hv);
+			int placeholders = (int)HvPLACEHOLDERS_get(hv);
 #endif
                         unsigned char flags = 0;
 			char *keyval;
diff --git a/global.sym b/global.sym
index d1cfb99..c982795 100644
--- a/global.sym
+++ b/global.sym
@@ -675,6 +675,9 @@ Perl_save_set_svflags
 Perl_hv_assert
 Perl_hv_clear_placeholders
 Perl_hv_scalar
+Perl_hv_placeholders_p
+Perl_hv_placeholders_get
+Perl_hv_placeholders_set
 Perl_gv_fetchpvn_flags
 Perl_gv_fetchsv
 Perl_savesvpv
diff --git a/hv.c b/hv.c
index 3f100e6..c12d20e 100644
--- a/hv.c
+++ b/hv.c
@@ -680,11 +680,11 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
 		    }
 		    /* LVAL fetch which actaully needs a store.  */
 		    val = NEWSV(61,0);
-		    xhv->xhv_placeholders--;
+		    HvPLACEHOLDERS(hv)--;
 		} else {
 		    /* store */
 		    if (val != &PL_sv_placeholder)
-			xhv->xhv_placeholders--;
+			HvPLACEHOLDERS(hv)--;
 		}
 		HeVAL(entry) = val;
 	    } else if (action & HV_FETCH_ISSTORE) {
@@ -764,7 +764,7 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
     *oentry = entry;
 
     if (val == &PL_sv_placeholder)
-	xhv->xhv_placeholders++;
+	HvPLACEHOLDERS(hv)++;
     if (masked_flags & HVhek_ENABLEHVKFLAGS)
 	HvHASKFLAGS_on(hv);
 
@@ -1022,7 +1022,7 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
 	    HeVAL(entry) = &PL_sv_placeholder;
 	    /* We'll be saving this slot, so the number of allocated keys
 	     * doesn't go down, but the number placeholders goes up */
-	    xhv->xhv_placeholders++; /* HvPLACEHOLDERS(hv)++ */
+	    HvPLACEHOLDERS(hv)++;
 	} else {
 	    *oentry = HeNEXT(entry);
 	    if (i && !*oentry)
@@ -1466,7 +1466,7 @@ Perl_hv_clear(pTHX_ HV *hv)
 		    }
 		    SvREFCNT_dec(HeVAL(entry));
 		    HeVAL(entry) = &PL_sv_placeholder;
-		    xhv->xhv_placeholders++; /* HvPLACEHOLDERS(hv)++ */
+		    HvPLACEHOLDERS(hv)++;
 		}
 	    }
 	}
@@ -1474,7 +1474,7 @@ Perl_hv_clear(pTHX_ HV *hv)
     }
 
     hfreeentries(hv);
-    xhv->xhv_placeholders = 0; /* HvPLACEHOLDERS(hv) = 0 */
+    HvPLACEHOLDERS_set(hv, 0);
     if (xhv->xhv_array /* HvARRAY(hv) */)
 	(void)memzero(xhv->xhv_array /* HvARRAY(hv) */,
 		      (xhv->xhv_max+1 /* HvMAX(hv)+1 */) * sizeof(HE*));
@@ -1615,7 +1615,7 @@ Perl_hv_undef(pTHX_ HV *hv)
     }
     xhv->xhv_max   = 7;	/* HvMAX(hv) = 7 (it's a normal hash) */
     xhv->xhv_array = 0;	/* HvARRAY(hv) = 0 */
-    xhv->xhv_placeholders = 0; /* HvPLACEHOLDERS(hv) = 0 */
+    HvPLACEHOLDERS_set(hv, 0);
 
     if (SvRMAGICAL(hv))
 	mg_clear((SV*)hv);
@@ -2126,6 +2126,46 @@ S_share_hek_flags(pTHX_ const char *str, I32 len, register U32 hash, int flags)
     return HeKEY_hek(entry);
 }
 
+I32 *
+Perl_hv_placeholders_p(pTHX_ HV *hv)
+{
+    dVAR;
+    MAGIC *mg = mg_find((SV*)hv, PERL_MAGIC_rhash);
+
+    if (!mg) {
+	mg = sv_magicext((SV*)hv, 0, PERL_MAGIC_rhash, 0, 0, 0);
+
+	if (!mg) {
+	    Perl_die(aTHX_ "panic: hv_placeholders_p");
+	}
+    }
+    return &(mg->mg_len);
+}
+
+
+I32
+Perl_hv_placeholders_get(pTHX_ HV *hv)
+{
+    dVAR;
+    MAGIC *mg = mg_find((SV*)hv, PERL_MAGIC_rhash);
+
+    return mg ? mg->mg_len : 0;
+}
+
+void
+Perl_hv_placeholders_set(pTHX_ HV *hv, IV ph)
+{
+    dVAR;
+    MAGIC *mg = mg_find((SV*)hv, PERL_MAGIC_rhash);
+
+    if (mg) {
+	mg->mg_len = ph;
+    } else if (ph) {
+	if (!sv_magicext((SV*)hv, 0, PERL_MAGIC_rhash, 0, 0, ph))
+	    Perl_die(aTHX_ "panic: hv_placeholders_set");
+    }
+    /* else we don't need to add magic to record 0 placeholders.  */
+}
 
 /*
 =for apidoc hv_assert
diff --git a/hv.h b/hv.h
index 7a6009b..da3e0e6 100644
--- a/hv.h
+++ b/hv.h
@@ -37,7 +37,6 @@ struct xpvhv {
     STRLEN	xhv_max;	/* subscript of last element of xhv_array */
     IV		xhv_keys;	/* how many elements in the array */
     NV		xnv_nv;		/* numeric value, if any */
-#define xhv_placeholders xnv_nv
     MAGIC*	xmg_magic;	/* magic for scalar array */
     HV*		xmg_stash;	/* class package */
 
@@ -186,21 +185,17 @@ C<SV*>.
 /* the number of keys (including any placeholers) */
 #define XHvTOTALKEYS(xhv)	((xhv)->xhv_keys)
 
-/* The number of placeholders in the enumerated-keys hash */
-#define XHvPLACEHOLDERS(xhv)	((xhv)->xhv_placeholders)
-
-/* the number of keys that exist() (i.e. excluding placeholders) */
-#define XHvUSEDKEYS(xhv)      (XHvTOTALKEYS(xhv) - (IV)XHvPLACEHOLDERS(xhv))
-
 /*
  * HvKEYS gets the number of keys that actually exist(), and is provided
  * for backwards compatibility with old XS code. The core uses HvUSEDKEYS
  * (keys, excluding placeholdes) and HvTOTALKEYS (including placeholders)
  */
-#define HvKEYS(hv)		XHvUSEDKEYS((XPVHV*)  SvANY(hv))
-#define HvUSEDKEYS(hv)		XHvUSEDKEYS((XPVHV*)  SvANY(hv))
+#define HvKEYS(hv)		HvUSEDKEYS(hv)
+#define HvUSEDKEYS(hv)		(HvTOTALKEYS(hv) - HvPLACEHOLDERS_get(hv))
 #define HvTOTALKEYS(hv)		XHvTOTALKEYS((XPVHV*)  SvANY(hv))
-#define HvPLACEHOLDERS(hv)	XHvPLACEHOLDERS((XPVHV*)  SvANY(hv))
+#define HvPLACEHOLDERS(hv)	(*Perl_hv_placeholders_p(aTHX_ (HV*)hv))
+#define HvPLACEHOLDERS_get(hv)	(SvMAGIC(hv) ? Perl_hv_placeholders_get(aTHX_ (HV*)hv) : 0)
+#define HvPLACEHOLDERS_set(hv,p)	Perl_hv_placeholders_set(aTHX_ (HV*)hv, p)
 
 #define HvSHAREKEYS(hv)		(SvFLAGS(hv) & SVphv_SHAREKEYS)
 #define HvSHAREKEYS_on(hv)	(SvFLAGS(hv) |= SVphv_SHAREKEYS)
diff --git a/perl.h b/perl.h
index d8d3878..22b6af5 100644
--- a/perl.h
+++ b/perl.h
@@ -3170,6 +3170,7 @@ Gid_t getegid (void);
 #define PERL_MAGIC_pos		  '.' /* pos() lvalue */
 #define PERL_MAGIC_backref	  '<' /* for weak ref data */
 #define PERL_MAGIC_symtab	  ':' /* extra data for symbol tables */
+#define PERL_MAGIC_rhash	  '%' /* extra data for restricted hashes */
 #define PERL_MAGIC_ext		  '~' /* Available for use by extensions */
 
 
diff --git a/proto.h b/proto.h
index 159ecf4..8f8ab0a 100644
--- a/proto.h
+++ b/proto.h
@@ -2311,6 +2311,11 @@ STATIC HE*	S_hv_fetch_common(pTHX_ HV* tb, SV* key_sv, const char* key, STRLEN k
 PERL_CALLCONV void	Perl_hv_clear_placeholders(pTHX_ HV* hb);
 
 PERL_CALLCONV SV*	Perl_hv_scalar(pTHX_ HV* hv);
+
+PERL_CALLCONV I32*	Perl_hv_placeholders_p(pTHX_ HV* hv);
+PERL_CALLCONV I32	Perl_hv_placeholders_get(pTHX_ HV* hv);
+PERL_CALLCONV void	Perl_hv_placeholders_set(pTHX_ HV* hv, I32 ph);
+
 PERL_CALLCONV SV*	Perl_magic_scalarpack(pTHX_ HV* hv, MAGIC*	mg);
 #ifdef PERL_IN_SV_C
 STATIC SV*	S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool top);
diff --git a/sv.c b/sv.c
index af471fb..49e02f2 100644
--- a/sv.c
+++ b/sv.c
@@ -1976,7 +1976,6 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
 	HvFILL(sv)	= 0;
 	HvMAX(sv)	= 0;
 	HvTOTALKEYS(sv)	= 0;
-	HvPLACEHOLDERS(sv) = 0;
 
 	/* Fall through...  */
 	if (0) {