summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embed.fnc5
-rw-r--r--embed.h2
-rw-r--r--ext/XS/APItest/APItest.xs22
-rw-r--r--ext/XS/APItest/Makefile.PL9
-rw-r--r--ext/XS/APItest/t/hash.t32
-rw-r--r--hv.c18
-rw-r--r--proto.h5
7 files changed, 79 insertions, 14 deletions
diff --git a/embed.fnc b/embed.fnc
index 3f012d2c61..779cecb28d 100644
--- a/embed.fnc
+++ b/embed.fnc
@@ -1141,7 +1141,10 @@ sanR |HEK* |save_hek_flags |NN const char *str|I32 len|U32 hash|int flags
sn |void |hv_magic_check |NN HV *hv|NN bool *needs_copy|NN bool *needs_store
s |void |unshare_hek_or_pvn|NULLOK const HEK* hek|NULLOK const char* str|I32 len|U32 hash
sR |HEK* |share_hek_flags|NN const char* sv|I32 len|U32 hash|int flags
-sR |SV* |hv_magic_uvar_xkey|NN HV* hv|NN SV* keysv|int action
+sR |SV* |hv_magic_uvar_xkey|NN HV* hv|NULLOK SV* keysv \
+ |NULLOK const char *const key \
+ |const STRLEN klen |const int k_flags \
+ |int action
rs |void |hv_notallowed |int flags|NN const char *key|I32 klen|NN const char *msg
sn |struct xpvhv_aux*|hv_auxinit|NN HV *hv
sM |SV* |hv_delete_common|NULLOK HV* tb|NULLOK SV* keysv|NULLOK const char* key \
diff --git a/embed.h b/embed.h
index 18ab10b290..9c79026159 100644
--- a/embed.h
+++ b/embed.h
@@ -3423,7 +3423,7 @@
#define hv_magic_check S_hv_magic_check
#define unshare_hek_or_pvn(a,b,c,d) S_unshare_hek_or_pvn(aTHX_ a,b,c,d)
#define share_hek_flags(a,b,c,d) S_share_hek_flags(aTHX_ a,b,c,d)
-#define hv_magic_uvar_xkey(a,b,c) S_hv_magic_uvar_xkey(aTHX_ a,b,c)
+#define hv_magic_uvar_xkey(a,b,c,d,e,f) S_hv_magic_uvar_xkey(aTHX_ a,b,c,d,e,f)
#define hv_notallowed(a,b,c,d) S_hv_notallowed(aTHX_ a,b,c,d)
#define hv_auxinit S_hv_auxinit
#define hv_delete_common(a,b,c,d,e,f,g) S_hv_delete_common(aTHX_ a,b,c,d,e,f,g)
diff --git a/ext/XS/APItest/APItest.xs b/ext/XS/APItest/APItest.xs
index da865e693d..96efd9bf77 100644
--- a/ext/XS/APItest/APItest.xs
+++ b/ext/XS/APItest/APItest.xs
@@ -195,8 +195,12 @@ rot13_key(pTHX_ IV action, SV *field) {
return 0;
}
+#include "const-c.inc"
+
MODULE = XS::APItest:Hash PACKAGE = XS::APItest::Hash
+INCLUDE: const-xs.inc
+
void
rot13_hash(hash)
HV *hash
@@ -227,17 +231,31 @@ exists(hash, key_sv)
RETVAL
SV *
-delete(hash, key_sv)
+delete(hash, key_sv, flags = 0)
PREINIT:
STRLEN len;
const char *key;
INPUT:
HV *hash
SV *key_sv
+ I32 flags;
CODE:
key = SvPV(key_sv, len);
/* It's already mortal, so need to increase reference count. */
- RETVAL = SvREFCNT_inc(hv_delete(hash, key, UTF8KLEN(key_sv, len), 0));
+ RETVAL
+ = SvREFCNT_inc(hv_delete(hash, key, UTF8KLEN(key_sv, len), flags));
+ OUTPUT:
+ RETVAL
+
+SV *
+delete_ent(hash, key_sv, flags = 0)
+ INPUT:
+ HV *hash
+ SV *key_sv
+ I32 flags;
+ CODE:
+ /* It's already mortal, so need to increase reference count. */
+ RETVAL = SvREFCNT_inc(hv_delete_ent(hash, key_sv, flags, 0));
OUTPUT:
RETVAL
diff --git a/ext/XS/APItest/Makefile.PL b/ext/XS/APItest/Makefile.PL
index 76aa60ac35..05bcfb06dc 100644
--- a/ext/XS/APItest/Makefile.PL
+++ b/ext/XS/APItest/Makefile.PL
@@ -1,5 +1,6 @@
use 5.008;
use ExtUtils::MakeMaker;
+use ExtUtils::Constant 0.11 'WriteConstants';
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
WriteMakefile(
@@ -17,6 +18,14 @@ WriteMakefile(
# Un-comment this if you add C files to link with later:
# 'OBJECT' => '$(O_FILES)', # link all the C files too
MAN3PODS => {}, # Pods will be built by installman.
+ realclean => {FILES => 'const-c.inc const-xs.inc'},
+);
+
+WriteConstants(
+ PROXYSUBS => 1,
+ NAME => 'XS::APItest',
+ NAMES => [qw(HV_DELETE HV_DISABLE_UVAR_XKEY G_DISCARD HV_FETCH_ISSTORE
+ HV_FETCH_ISEXISTS HV_FETCH_LVALUE HV_FETCH_JUST_SV)],
);
sub MY::install { "install ::\n" };
diff --git a/ext/XS/APItest/t/hash.t b/ext/XS/APItest/t/hash.t
index 4af7f88ad6..949f175e0a 100644
--- a/ext/XS/APItest/t/hash.t
+++ b/ext/XS/APItest/t/hash.t
@@ -18,7 +18,7 @@ use utf8;
use Tie::Hash;
use Test::More 'no_plan';
-use_ok('XS::APItest');
+BEGIN {use_ok('XS::APItest')};
sub preform_test;
sub test_present;
@@ -95,7 +95,7 @@ foreach my $in ("", "N", "a\0b") {
is ($got, $in, "test_share_unshare_pvn");
}
-{
+if ($] > 5.009) {
my %hash;
XS::APItest::Hash::rot13_hash(\%hash);
$hash{a}++; @hash{qw(p i e)} = (2, 4, 8);
@@ -105,6 +105,34 @@ foreach my $in ("", "N", "a\0b") {
"uvar magic called exactly once on store");
is($hash{i}, 4);
+
+ is(delete $hash{a}, 1);
+
+ is(keys %hash, 3);
+ @keys = sort keys %hash;
+ is("@keys", join(' ', sort(rot13(qw(p i e)))));
+
+ is (XS::APItest::Hash::delete_ent (\%hash, 'p',
+ XS::APItest::HV_DISABLE_UVAR_XKEY),
+ undef, "Deleting a known key with conversion disabled fails (ent)");
+ is(keys %hash, 3);
+
+ is (XS::APItest::Hash::delete_ent (\%hash, 'p', 0),
+ 2, "Deleting a known key with conversion enabled works (ent)");
+ is(keys %hash, 2);
+ @keys = sort keys %hash;
+ is("@keys", join(' ', sort(rot13(qw(i e)))));
+
+ is (XS::APItest::Hash::delete (\%hash, 'i',
+ XS::APItest::HV_DISABLE_UVAR_XKEY),
+ undef, "Deleting a known key with conversion disabled fails");
+ is(keys %hash, 2);
+
+ is (XS::APItest::Hash::delete (\%hash, 'i', 0),
+ 4, "Deleting a known key with conversion enabled works");
+ is(keys %hash, 1);
+ @keys = sort keys %hash;
+ is("@keys", join(' ', sort(rot13(qw(e)))));
}
exit;
diff --git a/hv.c b/hv.c
index 634d0e63d5..8394a0e5b1 100644
--- a/hv.c
+++ b/hv.c
@@ -426,7 +426,7 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
if (keysv) {
if (SvSMAGICAL(hv) && SvGMAGICAL(hv)
&& !(action & HV_DISABLE_UVAR_XKEY)) {
- keysv = hv_magic_uvar_xkey(hv, keysv, action);
+ keysv = hv_magic_uvar_xkey(hv, keysv, 0, 0, 0, action);
/* If a fetch-as-store fails on the fetch, then the action is to
recurse once into "hv_store". If we didn't do this, then that
recursive call would call the key conversion routine again.
@@ -966,10 +966,10 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
if (!hv)
return NULL;
+ if (SvSMAGICAL(hv) && SvGMAGICAL(hv)
+ && !(d_flags & HV_DISABLE_UVAR_XKEY))
+ keysv = hv_magic_uvar_xkey(hv, keysv, key, klen, k_flags, HV_DELETE);
if (keysv) {
- if (SvSMAGICAL(hv) && SvGMAGICAL(hv)
- && !(d_flags & HV_DISABLE_UVAR_XKEY))
- keysv = hv_magic_uvar_xkey(hv, keysv, HV_DELETE);
if (k_flags & HVhek_FREEKEY)
Safefree(key);
key = SvPV_const(keysv, klen);
@@ -2533,13 +2533,21 @@ S_share_hek_flags(pTHX_ const char *str, I32 len, register U32 hash, int flags)
}
STATIC SV *
-S_hv_magic_uvar_xkey(pTHX_ HV* hv, SV* keysv, int action)
+S_hv_magic_uvar_xkey(pTHX_ HV* hv, SV* keysv, const char *const key,
+ const STRLEN klen, const int k_flags, int action)
{
MAGIC* mg;
if ((mg = mg_find((SV*)hv, PERL_MAGIC_uvar))) {
struct ufuncs * const uf = (struct ufuncs *)mg->mg_ptr;
if (uf->uf_set == NULL) {
SV* obj = mg->mg_obj;
+
+ if (!keysv) {
+ keysv = sv_2mortal(newSVpvn(key, klen));
+ if (k_flags & HVhek_UTF8)
+ SvUTF8_on(keysv);
+ }
+
mg->mg_obj = keysv; /* pass key */
uf->uf_index = action; /* pass action */
magic_getuvar((SV*)hv, mg);
diff --git a/proto.h b/proto.h
index 4c1e6a1100..cc9e27ded6 100644
--- a/proto.h
+++ b/proto.h
@@ -3044,10 +3044,9 @@ STATIC HEK* S_share_hek_flags(pTHX_ const char* sv, I32 len, U32 hash, int flags
__attribute__warn_unused_result__
__attribute__nonnull__(pTHX_1);
-STATIC SV* S_hv_magic_uvar_xkey(pTHX_ HV* hv, SV* keysv, int action)
+STATIC SV* S_hv_magic_uvar_xkey(pTHX_ HV* hv, SV* keysv, const char *const key, const STRLEN klen, const int k_flags, int action)
__attribute__warn_unused_result__
- __attribute__nonnull__(pTHX_1)
- __attribute__nonnull__(pTHX_2);
+ __attribute__nonnull__(pTHX_1);
STATIC void S_hv_notallowed(pTHX_ int flags, const char *key, I32 klen, const char *msg)
__attribute__noreturn__