In hsplit, if a normal hash has placeholders then clear them before
Nicholas Clark [Fri, 27 Feb 2004 10:41:39 +0000 (10:41 +0000)]
splitting. We can do this safely because Storable ensures hsplit is
not called while it builds restricted hashes (actually any hashes)
This change may not make things faster, but now we have the choice.

p4raw-id: //depot/perl@22393

ext/Storable/t/restrict.t
hv.c

index 9359f21..58c1004 100644 (file)
@@ -38,7 +38,7 @@ sub BEGIN {
 use Storable qw(dclone);
 use Hash::Util qw(lock_hash unlock_value);
 
-print "1..16\n";
+print "1..50\n";
 
 my %hash = (question => '?', answer => 42, extra => 'junk', undef => undef);
 lock_hash %hash;
@@ -100,4 +100,23 @@ for $Storable::canonical (0, 1) {
   testit (\%hash);
   my $object = \%hash;
   # bless {}, "Restrict_Test";
+
+  my %hash2;
+  $hash2{"k$_"} = "v$_" for 0..16;
+  lock_hash %hash2;
+  for (0..16) {
+    unlock_value %hash2, "k$_";
+    delete $hash2{"k$_"};
+  }
+  my $copy = dclone \%hash2;
+
+  for (0..16) {
+    my $k = "k$_";
+    eval { $copy->{$k} = undef } ;
+    unless (ok ++$test, !$@, "Can assign to reserved key '$k'?") {
+      my $diag = $@;
+      $diag =~ s/\n.*\z//s;
+      print "# \$\@: $diag\n";
+    }
+  }
 }
diff --git a/hv.c b/hv.c
index 28c04de..cebf2f9 100644 (file)
--- a/hv.c
+++ b/hv.c
@@ -1038,11 +1038,6 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
 STATIC void
 S_hsplit(pTHX_ HV *hv)
 {
-    /* Can't make this clear any placeholders first for non-restricted hashes,
-       as Storable rebuilds restricted hashes by putting in all the
-       placeholders (first) before turning on the readonly flag.  Hence midway
-       through restoring the hash there are placeholders which need to remain
-       even though the hash isn't (currently) flagged as restricted. */
     register XPVHV* xhv = (XPVHV*)SvANY(hv);
     I32 oldsize = (I32) xhv->xhv_max+1; /* HvMAX(hv)+1 (sick) */
     register I32 newsize = oldsize * 2;
@@ -1055,6 +1050,17 @@ S_hsplit(pTHX_ HV *hv)
     int longest_chain = 0;
     int was_shared;
 
+    /*PerlIO_printf(PerlIO_stderr(), "hsplit called for %p which had %d\n",
+      hv, (int) oldsize);*/
+
+    if (HvPLACEHOLDERS(hv) && !SvREADONLY(hv)) {
+      /* Can make this clear any placeholders first for non-restricted hashes,
+        even though Storable rebuilds restricted hashes by putting in all the
+        placeholders (first) before turning on the readonly flag, because
+        Storable always pre-splits the hash.  */
+      hv_clear_placeholders(hv);
+    }
+              
     PL_nomemok = TRUE;
 #if defined(STRANGE_MALLOC) || defined(MYMALLOC)
     Renew(a, PERL_HV_ARRAY_ALLOC_BYTES(newsize), char);