return CALL_FPTR(oi.old_pp)(aTHX);
}
-/* ... pp_root (exists,delete) ............................................. */
+/* ... pp_root (exists,delete,keys,values) ................................. */
-STATIC OP *a_pp_root(pTHX) {
+STATIC OP *a_pp_root_unop(pTHX) {
+ a_op_info oi;
+ dSP;
+
+ if (!a_defined(TOPs)) {
+ POPs;
+ /* Can only be reached by keys or values */
+ if (GIMME_V == G_SCALAR) {
+ dTARGET;
+ PUSHi(0);
+ }
+ RETURN;
+ }
+
+ a_map_fetch(PL_op, &oi);
+
+ return CALL_FPTR(oi.old_pp)(aTHX);
+}
+
+STATIC OP *a_pp_root_binop(pTHX) {
a_op_info oi;
dSP;
STATIC OP *(*a_old_ck_exists)(pTHX_ OP *) = 0;
STATIC OP *(*a_old_ck_delete)(pTHX_ OP *) = 0;
+STATIC OP *(*a_old_ck_keys) (pTHX_ OP *) = 0;
+STATIC OP *(*a_old_ck_values)(pTHX_ OP *) = 0;
STATIC OP *a_ck_root(pTHX_ OP *o) {
OP * (*old_ck)(pTHX_ OP *o) = 0;
+ OP * (*new_pp)(pTHX) = 0;
bool enabled = FALSE;
UV hint = a_hint();
switch (o->op_type) {
case OP_EXISTS:
old_ck = a_old_ck_exists;
+ new_pp = a_pp_root_binop;
enabled = hint & A_HINT_EXISTS;
break;
case OP_DELETE:
old_ck = a_old_ck_delete;
+ new_pp = a_pp_root_binop;
enabled = hint & A_HINT_DELETE;
break;
+ case OP_KEYS:
+ old_ck = a_old_ck_keys;
+ new_pp = a_pp_root_unop;
+ enabled = hint & A_HINT_FETCH;
+ break;
+ case OP_VALUES:
+ old_ck = a_old_ck_values;
+ new_pp = a_pp_root_unop;
+ enabled = hint & A_HINT_FETCH;
+ break;
}
o = CALL_FPTR(old_ck)(aTHX_ o);
if (enabled) {
a_map_set_root(o, hint | A_HINT_DEREF);
a_map_store(o, o->op_ppaddr, hint);
- o->op_ppaddr = a_pp_root;
+ o->op_ppaddr = new_pp;
} else {
a_map_set_root(o, 0);
}
PL_check[OP_PADANY] = MEMBER_TO_FPTR(a_ck_padany);
a_old_ck_padsv = PL_check[OP_PADSV];
PL_check[OP_PADSV] = MEMBER_TO_FPTR(a_ck_padsv);
+
a_old_ck_aelem = PL_check[OP_AELEM];
PL_check[OP_AELEM] = MEMBER_TO_FPTR(a_ck_deref);
a_old_ck_helem = PL_check[OP_HELEM];
PL_check[OP_HELEM] = MEMBER_TO_FPTR(a_ck_deref);
a_old_ck_rv2sv = PL_check[OP_RV2SV];
PL_check[OP_RV2SV] = MEMBER_TO_FPTR(a_ck_deref);
+
a_old_ck_rv2av = PL_check[OP_RV2AV];
PL_check[OP_RV2AV] = MEMBER_TO_FPTR(a_ck_rv2xv);
a_old_ck_rv2hv = PL_check[OP_RV2HV];
PL_check[OP_RV2HV] = MEMBER_TO_FPTR(a_ck_rv2xv);
+
a_old_ck_exists = PL_check[OP_EXISTS];
PL_check[OP_EXISTS] = MEMBER_TO_FPTR(a_ck_root);
a_old_ck_delete = PL_check[OP_DELETE];
PL_check[OP_DELETE] = MEMBER_TO_FPTR(a_ck_root);
+ a_old_ck_keys = PL_check[OP_KEYS];
+ PL_check[OP_KEYS] = MEMBER_TO_FPTR(a_ck_root);
+ a_old_ck_values = PL_check[OP_VALUES];
+ PL_check[OP_VALUES] = MEMBER_TO_FPTR(a_ck_root);
stash = gv_stashpvn(__PACKAGE__, __PACKAGE_LEN__, 1);
newCONSTSUB(stash, "A_HINT_STRICT", newSVuv(A_HINT_STRICT));
--- /dev/null
+#!perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 6 * 3 * 56;
+
+use lib 't/lib';
+use autovivification::TestCases;
+
+while (<DATA>) {
+ 1 while chomp;
+ next unless /#/;
+ testcase_ok($_, '%');
+}
+
+__DATA__
+
+--- keys ---
+
+$x # keys %$x # '', 0, { }
+$x # keys %$x # '', 0, undef #
+$x # keys %$x # '', 0, undef # +fetch
+$x # keys %$x # '', 0, { } # +exists
+$x # keys %$x # '', 0, { } # +delete
+$x # keys %$x # '', 0, { } # +store
+
+$x # keys %$x # qr/^Reference vivification forbidden/, undef, undef # +strict +fetch
+$x # keys %$x # '', 0, { } # +strict +exists
+$x # keys %$x # '', 0, { } # +strict +delete
+$x # keys %$x # '', 0, { } # +strict +store
+
+$x # [ keys %$x ] # '', [ ], { }
+$x # [ keys %$x ] # '', [ ], undef #
+$x # [ keys %$x ] # '', [ ], undef # +fetch
+$x # [ keys %$x ] # '', [ ], { } # +exists +delete +store
+
+$x # keys %{$x->{a}} # '', 0, { a => { } }
+$x # keys %{$x->{a}} # '', 0, undef #
+$x # keys %{$x->{a}} # '', 0, undef # +fetch
+$x # keys %{$x->{a}} # '', 0, { a => { } } # +exists
+$x # keys %{$x->{a}} # '', 0, { a => { } } # +delete
+$x # keys %{$x->{a}} # '', 0, { a => { } } # +store
+
+$x # keys %{$x->{a}} # qr/^Reference vivification forbidden/, undef, undef # +strict +fetch
+$x # keys %{$x->{a}} # '', 0, { a => { } } # +strict +exists
+$x # keys %{$x->{a}} # '', 0, { a => { } } # +strict +delete
+$x # keys %{$x->{a}} # '', 0, { a => { } } # +strict +store
+
+$x # [ keys %{$x->{a}} ] # '', [ ], { a => { } }
+$x # [ keys %{$x->{a}} ] # '', [ ], undef #
+$x # [ keys %{$x->{a}} ] # '', [ ], undef # +fetch
+$x # [ keys %{$x->{a}} ] # '', [ ], { a => { } } # +exists +delete +store
+
+--- values ---
+
+$x # values %$x # '', 0, { }
+$x # values %$x # '', 0, undef #
+$x # values %$x # '', 0, undef # +fetch
+$x # values %$x # '', 0, { } # +exists
+$x # values %$x # '', 0, { } # +delete
+$x # values %$x # '', 0, { } # +store
+
+$x # values %$x # qr/^Reference vivification forbidden/, undef, undef # +strict +fetch
+$x # values %$x # '', 0, { } # +strict +exists
+$x # values %$x # '', 0, { } # +strict +delete
+$x # values %$x # '', 0, { } # +strict +store
+
+$x # [ values %$x ] # '', [ ], { }
+$x # [ values %$x ] # '', [ ], undef #
+$x # [ values %$x ] # '', [ ], undef # +fetch
+$x # [ values %$x ] # '', [ ], { } # +exists +delete +store
+
+$x # values %{$x->{a}} # '', 0, { a => { } }
+$x # values %{$x->{a}} # '', 0, undef #
+$x # values %{$x->{a}} # '', 0, undef # +fetch
+$x # values %{$x->{a}} # '', 0, { a => { } } # +exists
+$x # values %{$x->{a}} # '', 0, { a => { } } # +delete
+$x # values %{$x->{a}} # '', 0, { a => { } } # +store
+
+$x # values %{$x->{a}} # qr/^Reference vivification forbidden/, undef, undef # +strict +fetch
+$x # values %{$x->{a}} # '', 0, { a => { } } # +strict +exists
+$x # values %{$x->{a}} # '', 0, { a => { } } # +strict +delete
+$x # values %{$x->{a}} # '', 0, { a => { } } # +strict +store
+
+$x # [ values %{$x->{a}} ] # '', [ ], { a => { } }
+$x # [ values %{$x->{a}} ] # '', [ ], undef #
+$x # [ values %{$x->{a}} ] # '', [ ], undef # +fetch
+$x # [ values %{$x->{a}} ] # '', [ ], { a => { } } # +exists +delete +store