Index: lib/Automake/Condition.pm =================================================================== RCS file: /cvs/automake/automake/lib/Automake/Condition.pm,v retrieving revision 1.2 diff -u -p -u -r1.2 Condition.pm --- lib/Automake/Condition.pm 23 Jan 2003 23:35:40 -0000 1.2 +++ lib/Automake/Condition.pm 29 Mar 2003 21:49:02 -0000 @@ -22,7 +22,7 @@ use Carp; require Exporter; use vars '@ISA', '@EXPORT_OK'; @ISA = qw/Exporter/; address@hidden = qw/TRUE FALSE reduce/; address@hidden = qw/TRUE FALSE reduce_and reduce_or/; =head1 NAME @@ -80,10 +80,18 @@ Automake::Condition - record a conjuncti # (Not in this example) if ($cond->implies_any ($other, $both)) { ... } - # Remove superfluous conditionals. - # (Returns @cons = ($both) in this example, because + # Remove superfluous conditionals assuming they will eventually + # be multiplied together. + # (Returns @conds = ($both) in this example, because # $other and $cond are implied by $both.) - @conds = Automake::Condition::reduce ($other, $both, $cond); + @conds = Automake::Condition::reduce_and ($other, $both, $cond); + + # Remove superfluous conditionals assuming they will eventually + # be summed together. + # (Returns @conds = ($cond, $other) in this example, because + # $both is a subset condition of $cond: $cond is true whenever $both + # is true.) + @conds = Automake::Condition::reduce_or ($other, $both, $cond); # Invert a Condition. This returns a list of Conditions. @conds = $both->not; @@ -504,16 +512,16 @@ The C<"FALSE"> conditional. use constant TRUE => new Automake::Condition "TRUE"; use constant FALSE => new Automake::Condition "FALSE"; -=item C +=item C -Filter a list of conditions so that only the exclusive ones are -retained. For example, if both C and -C are in the list, discard the latter. -If the input list is empty, return C<(TRUE)>. +Return a subset of @conds with the property that the conjunction of +the subset is the same as the conjunction of @conds. For example, if +both C and C are in the list, +discard the latter. If the input list is empty, return C<(TRUE)>. =cut -sub reduce (@) +sub reduce_and (@) { my (@conds) = @_; my @ret = (); @@ -533,6 +541,37 @@ sub reduce (@) } return TRUE if @ret == 0; + return @ret; +} + +=item C + +Return a subset of @conds with the property that the disjunction of +the subset is equivalent to the disjunction of @conds. For example, +if both C and C are in the list, +discard the former. If the input list is empty, return C<(FALSE)>. + +=cut + +sub reduce_or (@) +{ + my (@conds) = @_; + my @ret = (); + my $cond; + while (@conds > 0) + { + $cond = shift @conds; + + next + if $cond == FALSE; + return TRUE + if $cond == TRUE; + + push (@ret, $cond) + unless $cond->implies_any (@ret, @conds); + } + + return FALSE if @ret == 0; return @ret; } Index: lib/Automake/DisjConditions.pm =================================================================== RCS file: /cvs/automake/automake/lib/Automake/DisjConditions.pm,v retrieving revision 1.2 diff -u -p -u -r1.2 DisjConditions.pm --- lib/Automake/DisjConditions.pm 2 Feb 2003 10:09:25 -0000 1.2 +++ lib/Automake/DisjConditions.pm 29 Mar 2003 21:49:02 -0000 @@ -325,7 +325,7 @@ sub _multiply ($@) push @res, $selfcond->merge ($setcond); } } - return new Automake::DisjConditions @res; + return new Automake::DisjConditions (Automake::Condition::reduce_or @res); } sub multiply ($$) Index: lib/Automake/tests/Condition.pl =================================================================== RCS file: /cvs/automake/automake/lib/Automake/tests/Condition.pl,v retrieving revision 1.1 diff -u -p -u -r1.1 Condition.pl --- lib/Automake/tests/Condition.pl 19 Jan 2003 23:01:03 -0000 1.1 +++ lib/Automake/tests/Condition.pl 29 Mar 2003 21:49:02 -0000 @@ -90,9 +90,11 @@ sub test_true_when () return $failed; } -sub test_reduce () +sub test_reduce_and () { my @tests = (# If no conditions are given, TRUE should be returned + [[], ["TRUE"]], + # An empty condition is TRUE [[""], ["TRUE"]], # A single condition should be passed through unchanged [["FOO"], ["FOO"]], @@ -149,7 +151,7 @@ sub test_reduce () my @inconds = map { new Automake::Condition $_ } @$inref; my @outconds = map { (new Automake::Condition $_)->string } @$outref; my @res = - map { $_->string } (Automake::Condition::reduce (@inconds)); + map { $_->string } (Automake::Condition::reduce_and (@inconds)); my $result = join (",", sort @res); my $exresult = join (",", @outconds); @@ -164,7 +166,83 @@ sub test_reduce () return $failed; } -exit (test_basics || test_true_when || test_reduce); +sub test_reduce_or () +{ + my @tests = (# If no conditions are given, FALSE should be returned + [[], ["FALSE"]], + # An empty condition is TRUE + [[""], ["TRUE"]], + # A single condition should be passed through unchanged + [["FOO"], ["FOO"]], + [["FALSE"], ["FALSE"]], + [["TRUE"], ["TRUE"]], + # FALSE and TRUE should be discarded and overwhelm + # the result, respectively + [["FOO", "TRUE"], ["TRUE"]], + [["FOO", "FALSE"], ["FOO"]], + # Repetitions should be removed + [["FOO", "FOO"], ["FOO"]], + [["FALSE", "FOO", "FOO"], ["FOO"]], + [["FOO", "FALSE", "FOO"], ["FOO"]], + [["FOO", "FOO", "FALSE"], ["FOO"]], + # Two different conditions should be preserved, + # but FALSEs should be removed + [["FOO", "BAR"], ["BAR,FOO"]], + [["FALSE", "FOO", "BAR"], ["BAR,FOO"]], + [["FOO", "FALSE", "BAR"], ["BAR,FOO"]], + [["FOO", "BAR", "FALSE"], ["BAR,FOO"]], + # A condition implying another condition should be removed. + [["FOO BAR", "BAR"], ["BAR"]], + [["BAR", "FOO BAR"], ["BAR"]], + [["FALSE", "FOO BAR", "BAR"], ["BAR"]], + [["FOO BAR", "FALSE", "BAR"], ["BAR"]], + [["FOO BAR", "BAR", "FALSE"], ["BAR"]], + + [["BAR FOO", "BAR"], ["BAR"]], + [["BAR", "BAR FOO"], ["BAR"]], + [["FALSE", "BAR FOO", "BAR"], ["BAR"]], + [["BAR FOO", "FALSE", "BAR"], ["BAR"]], + [["BAR FOO", "BAR", "FALSE"], ["BAR"]], + + # Check that reduction happens even when there are + # two conditions to remove. + [["FOO", "FOO BAR", "BAR"], ["BAR,FOO"]], + [["FOO", "FOO BAR", "BAZ", "FOO BAZ"], ["BAZ,FOO"]], + [["FOO", "FOO BAR", "BAZ", "FOO BAZ", "FOO BAZ BAR"], + ["BAZ,FOO"]], + + # Duplicated condionals should be removed + [["FOO", "BAR", "BAR"], ["BAR,FOO"]], + + # Equivalent conditions in different forms should be + # reduced: which one is left is unfortunately order + # dependent. + [["BAR FOO", "FOO BAR"], ["FOO BAR"]], + [["FOO BAR", "BAR FOO"], ["BAR FOO"]]); + + my $failed = 0; + foreach (@tests) + { + my ($inref, $outref) = @$_; + my @inconds = map { new Automake::Condition $_ } @$inref; + my @outconds = map { (new Automake::Condition $_)->string } @$outref; + my @res = + map { $_->string } (Automake::Condition::reduce_or (@inconds)); + my $result = join (",", sort @res); + my $exresult = join (",", @outconds); + + if ($result ne $exresult) + { + print '"'.join(",", @$inref) . '" => "' . + $result . '" expected "' . + $exresult . '"' . "\n"; + $failed = 1; + } + } + return $failed; +} + +exit (test_basics || test_true_when || test_reduce_and || test_reduce_or); ### Setup "GNU" style for perl-mode and cperl-mode. ## Local Variables: Index: lib/Automake/tests/DisjConditions.pl =================================================================== RCS file: /cvs/automake/automake/lib/Automake/tests/DisjConditions.pl,v retrieving revision 1.2 diff -u -p -u -r1.2 DisjConditions.pl --- lib/Automake/tests/DisjConditions.pl 2 Feb 2003 10:09:25 -0000 1.2 +++ lib/Automake/tests/DisjConditions.pl 29 Mar 2003 21:49:02 -0000 @@ -55,8 +55,6 @@ sub test_invert () [[["COND1_TRUE", "COND2_TRUE"], ["COND3_FALSE", "COND2_TRUE"]], [["COND2_FALSE"], - ["COND2_FALSE", "COND3_TRUE"], - ["COND1_FALSE", "COND2_FALSE"], ["COND1_FALSE", "COND3_TRUE"]]], [[["COND1_TRUE", "COND2_TRUE"], @@ -246,9 +244,6 @@ sub test_simplify () } # Also exercize invert() while we are at it. - - # FIXME: Can't run invert() with too much conditions, this is too slow. - next if $#{$t->[0][0]} > 8; my $inv1 = $set->invert->simplify; my $inv2 = $sim->invert->simplify;