influence blocker implementation
authorJoey Hess <joey@gnu.kitenet.net>
Tue, 13 Oct 2009 18:37:14 +0000 (14:37 -0400)
committerJoey Hess <joey@gnu.kitenet.net>
Tue, 13 Oct 2009 18:37:14 +0000 (14:37 -0400)
This avoids unnecessary influences being recorded from pagespecs
such as "link(done) and bugs/*", when a page cannot ever possibly
match.

A pagespec term that returns a value without influence is an influence
blocker. If such a blocker has a false value (possibly due to being
negated) and is ANDed with another term, it blocks that term's influence
from propigating out.

If the term is ORed, or has a true value, it does not block influence.
(Consider "link(done) or bugs/*" and "link(done) and !nosuchpage")

In the implementation in merge_influence, I had to be careful to never
negate $this or $other when testing if they are an influence blocker,
since negation mutates the object. Thus the slightly weird if statement.

IkiWiki.pm

index 2847c7e0f92b8d0266316041829a810a7a3f94ee..ac01ea4180c25224892ba8a5cfa1d807df67c1af 100644 (file)
@@ -2071,7 +2071,7 @@ use overload (
        '""'    => sub { $_[0][0] },
        '0+'    => sub { 0 },
        '!'     => sub { bless $_[0], 'IkiWiki::SuccessReason'},
-       '&'     => sub { $_[0]->merge_influences($_[1]); $_[0] },
+       '&'     => sub { $_[0]->merge_influences($_[1], 1); $_[0] },
        '|'     => sub { $_[1]->merge_influences($_[0]); $_[1] },
        fallback => 1,
 );
@@ -2084,7 +2084,7 @@ use overload (
        '""'    => sub { $_[0][0] },
        '0+'    => sub { 1 },
        '!'     => sub { bless $_[0], 'IkiWiki::FailReason'},
-       '&'     => sub { $_[1]->merge_influences($_[0]); $_[1] },
+       '&'     => sub { $_[1]->merge_influences($_[0], 1); $_[1] },
        '|'     => sub { $_[0]->merge_influences($_[1]); $_[0] },
        fallback => 1,
 );
@@ -2110,8 +2110,20 @@ sub influences_static {
 sub merge_influences {
        my $this=shift;
        my $other=shift;
-       foreach my $influence (keys %{$other->[1]}) {
-               $this->[1]{$influence} |= $other->[1]{$influence};
+       my $anded=shift;
+
+       if (! $anded || (($this || %{$this->[1]}) &&
+                       ($other || %{$other->[1]}))) {
+               foreach my $influence (keys %{$other->[1]}) {
+                       $this->[1]{$influence} |= $other->[1]{$influence};
+               }
+       }
+       else {
+               # influence blocker
+               print STDERR "merging $this and $other; found influence blocker\n";
+               $this->[1]={};
+               $this->[2]=1;
+               return;
        }
 }