STATIC U32 sn_hash_list = 0;
STATIC U32 sn_hash_exit = 0;
+STATIC U32 sn_hash_die = 0;
/* --- XS ------------------------------------------------------------------ */
{
PERL_HASH(sn_hash_list, "list", 4);
PERL_HASH(sn_hash_exit, "exit", 4);
+ PERL_HASH(sn_hash_die, "die", 3);
}
void
PREINIT:
HV *res[3];
SV *val;
- SV *exit1, *list1;
+ SV *kexit, *klist, *kdie;
SV *temp;
HE *key, *old;
I32 i;
I32 n = 0, o;
I32 j, n1, n2;
- NV pl = 0, pe = 0;
+ NV pe = 0, pd = 0, pl = 0;
sn_combcache *cache = NULL;
I32 cachelen = 1;
CODE:
temp = sv_2mortal(newSViv(0));
for (i = 0; i < items; ++i) {
SV *cur = ST(i);
- NV pe1 = 0, pl1 = 0;
+ NV pe1 = 0, pd1 = 0, pd2, pl1 = 0;
if (!SvOK(cur))
continue;
if (!SvROK(cur)) {
res[o] = newHV();
else
hv_clear(res[o]);
- exit1 = hv_delete((HV *) cur, "exit", 4, 0);
+ kexit = hv_delete((HV *) cur, "exit", 4, 0);
n1 = hv_iterinit((HV *) cur);
- if (exit1) {
+ if (kexit) {
if (!n1) {
- pe = 1;
+ pe = 1 - pd;
pl = 0;
n = o;
break;
}
- pe1 = SvNV(exit1);
+ pe1 = SvNV(kexit);
}
- list1 = hv_delete((HV *) cur, "list", 4, 0);
- if (list1) {
+ kdie = hv_delete((HV *) cur, "die", 3, 0);
+ if (kdie) {
if (n1 == 1) {
- pl = 1 - pe;
+ pd = 1 - pe;
+ pl = 0;
+ n = o;
+ break;
+ }
+ --n1;
+ pd1 = SvNV(kdie);
+ }
+ klist = hv_delete((HV *) cur, "list", 4, 0);
+ if (klist) {
+ if (n1 == 1) {
+ pl = 1 - (pe + pd);
n = o;
break;
}
- pl1 = SvNV(list1);
+ pl1 = SvNV(klist);
}
- pl = pl1 * (1 - pe) + pl * (1 - pe1) - pl * pl1;
- pe = pe + (1 - pe) * pe1;
- n2 = hv_iterinit(res[n]);
+ pl = pl1 * (1 - (pd + pe)) + pl * (1 - (pd1 + pe1)) - pl * pl1;
+ pd2 = pd1 * (1 - pe) + pd - pd * pd1;
+ pe = pe1 * (1 - pd) + pe - pe * pe1;
+ pd = pd2;
+ n2 = hv_iterinit(res[n]);
if (!n2) {
cache[0].k = 0;
cache[0].v = 1;
SvREFCNT_dec(res[2]);
if (pe)
sn_store(res[n], "exit", 4, newSVnv(pe), sn_hash_exit);
+ if (pd)
+ sn_store(res[n], "die", 3, newSVnv(pd), sn_hash_die);
if (pl)
sn_store(res[n], "list", 4, newSVnv(pl), sn_hash_list);
if (n == 1)
use strict;
use warnings;
-use Test::More tests => 41;
+use Test::More tests => 60;
use Sub::Nary;
my $h12 = { 1 => 0.5, 2 => 0.5 };
my $h1l = { 1 => 0.5, list => 0.5 };
my $h1e = { 1 => 0.5, exit => 0.5 };
+my $h1d = { 1 => 0.5, die => 0.5 };
my $h1le = { 1 => 0.25, list => 0.25, exit => 0.5 };
+my $h12e = { 1 => 0.25, 2 => 0.25, exit => 0.5 };
+my $h1ld = { 1 => 0.25, list => 0.25, die => 0.5 };
+my $h12d = { 1 => 0.25, 2 => 0.25, die => 0.5 };
my @tests = (
[ [ ], undef ],
[ [ 'exit', 1 ], 'exit' ],
[ [ { %$h1e }, 1 ], { exit => 0.5, 2 => 0.5 } ],
[ [ { %$h1e }, { %$h1e } ], { exit => 0.75, 2 => 0.25 } ],
+
[ [ { %$h1e }, { %$h1l } ], { exit => 0.5, list => 0.25, 2 => 0.25 } ],
[ [ { %$h1l }, { %$h1e } ], { exit => 0.5, list => 0.25, 2 => 0.25 } ],
[ [ { %$h1l }, { %$h1le } ], { exit => 0.5, list => 0.375, 2 => 0.125 } ],
[ [ { %$h1e }, { %$h1le } ], { exit => 0.75, list => 0.125, 2 => 0.125 } ],
+ [ [ 'die' ], 'die' ],
+ [ [ 'die', 2 ], 'die' ],
+ [ [ { %$h1d }, 2 ], { die => 0.5, 3 => 0.5 } ],
+ [ [ { %$h1d }, 1 ], { die => 0.5, 2 => 0.5 } ],
+ [ [ { %$h1d }, { %$h1d } ], { die => 0.75, 2 => 0.25 } ],
+
+ [ [ { %$h1d }, { %$h1l } ], { die => 0.5, list => 0.25, 2 => 0.25 } ],
+ [ [ { %$h1l }, { %$h1d } ], { die => 0.5, list => 0.25, 2 => 0.25 } ],
+ [ [ { %$h1l }, { %$h1ld } ], { die => 0.5, list => 0.375, 2 => 0.125 } ],
+ [ [ { %$h1d }, { %$h1ld } ], { die => 0.75, list => 0.125, 2 => 0.125 } ],
+
+ [ [ { %$h1e }, { %$h1d } ], { exit => 0.5, die => 0.25, 2 => 0.25 } ],
+ [ [ { %$h1d }, { %$h1e } ], { exit => 0.25, die => 0.5, 2 => 0.25 } ],
+ [ [ { %$h1e }, { %$h1ld } ], { exit => 0.5, die => 0.25,
+ list => 0.125, 2 => 0.125 } ],
+ [ [ { %$h1d }, { %$h1le } ], { exit => 0.25, die => 0.5,
+ list => 0.125, 2 => 0.125 } ],
+
+ [ [ { %$h12d }, { %$h1le } ], { exit => 0.25, die => 0.5,
+ list => 0.125, 2 => 0.0625, 3 => 0.0625 } ],
+ [ [ { %$h12e }, { %$h1ld } ], { exit => 0.5, die => 0.25,
+ list => 0.125, 2 => 0.0625, 3 => 0.0625 } ],
+ [ [ { %$h1ld }, { %$h12e } ], { exit => 0.25, die => 0.5,
+ list => 0.125, 2 => 0.0625, 3 => 0.0625 } ],
+ [ [ { %$h1le }, { %$h12d } ], { exit => 0.5, die => 0.25,
+ list => 0.125, 2 => 0.0625, 3 => 0.0625 } ],
+
+ [ [ { %$h1ld }, { %$h1le } ], { exit => 0.25, die => 0.5,
+ list => 0.1875, 2 => 0.0625 } ],
+ [ [ { %$h1le }, { %$h1ld } ], { exit => 0.5, die => 0.25,
+ list => 0.1875, 2 => 0.0625 } ],
+
[ [ $h1l, $h1l ], { 2 => 0.25, list => 0.5 } ], # Side effects
);
--- /dev/null
+#!perl -T
+
+use strict;
+use warnings;
+
+use Test::More tests => 12;
+
+use Sub::Nary;
+
+my $sn = Sub::Nary->new();
+
+my ($x, $y);
+
+sub dies {
+ if ($x) {
+ die do { return 3, 4 if $y }
+ }
+ @_[0 .. 2];
+}
+
+my @tests = (
+ [ sub { die }, { die => 1 } ],
+ [ sub { die 1 }, { die => 1 } ],
+ [ sub { if ($x) { die } }, { die => 0.5, 1 => 0.5 } ],
+ [ sub { if (die) { return 1, 2 } }, { die => 1 } ],
+ [ sub { die do { return 3, 4 } }, { 2 => 1 } ],
+ [ sub { $x ? die($y ? die : return(2, 3)) : 4 },
+ { die => 0.25, 2 => 0.25, 1 => 0.5 } ],
+
+ [ \&dies, { die => 0.25, 2 => 0.25, 3 => 0.5 } ],
+ [ sub { dies(), do { $x ? @_ : 1 } }, { die => 0.25, 3 => 0.125, 4 => 0.25,
+ list => (0.25 + 0.5) * 0.5 } ],
+ [ sub { dies(), 1, do { $x ? @_ : 1 } },
+ { die => 0.25, 4 => 0.125, 5 => 0.25, list => (0.25 + 0.5) * 0.5 } ],
+
+ [ sub { eval "1, do { die }, 3" }, 'list' ],
+ [ sub { eval { die } }, { 0 => 1 } ],
+ [ sub { eval { $x ? die : (4, 5) } }, { 0 => 0.5, 2 => 0.5 } ],
+);
+
+my $i = 1;
+for (@tests) {
+ my $r = $sn->nary($_->[0]);
+ my $exp = ref $_->[1] ? $_->[1] : { $_->[1] => 1 };
+ is_deeply($r, $exp, 'die test ' . $i);
+ ++$i;
+}