File Coverage

blib/lib/Quantum/Superpositions/Lazy/Operation/Logical.pm
Criterion Covered Total %
statement 55 55 100.0
branch 6 6 100.0
condition 11 15 73.3
subroutine 10 10 100.0
pod 0 3 0.0
total 82 89 92.1


line stmt bran cond sub pod time code
1             package Quantum::Superpositions::Lazy::Operation::Logical;
2              
3             our $VERSION = '1.11';
4              
5 15     15   161 use v5.24;
  15         51  
6 15     15   143 use warnings;
  15         35  
  15         316  
7 15     15   64 use Moo;
  15         63  
  15         105  
8 15     15   4748 use Quantum::Superpositions::Lazy::Superposition;
  15         52  
  15         554  
9 15     15   378 use Quantum::Superpositions::Lazy::Util qw(is_collapsible get_iterator);
  15         41  
  15         842  
10 15     15   96 use Types::Standard qw(Enum);
  15         307  
  15         500  
11              
12             my %types = (
13              
14             # type => number of parameters, code, forced reducer type
15             q{!} => [1, sub { !$_[0] }, "all"],
16              
17             q{==} => [2, sub { $_[0] == $_[1] }],
18             q{!=} => [2, sub { $_[0] != $_[1] }],
19             q{>} => [2, sub { $_[0] > $_[1] }],
20             q{>=} => [2, sub { $_[0] >= $_[1] }],
21             q{<} => [2, sub { $_[0] < $_[1] }],
22             q{<=} => [2, sub { $_[0] <= $_[1] }],
23              
24             q{eq} => [2, sub { $_[0] eq $_[1] }],
25             q{ne} => [2, sub { $_[0] ne $_[1] }],
26             q{gt} => [2, sub { $_[0] gt $_[1] }],
27             q{ge} => [2, sub { $_[0] ge $_[1] }],
28             q{lt} => [2, sub { $_[0] lt $_[1] }],
29             q{le} => [2, sub { $_[0] le $_[1] }],
30              
31             q{_compare} => [
32             [2,],
33             sub {
34             local $_ = shift;
35             my $sub = shift;
36             $sub->($_, @_);
37             }
38             ],
39             );
40              
41             # TODO: should "one" reducer run after every iterator pair
42             # or after an element is compared with the entire superposition?
43             my %reducer_types = (
44              
45             # type => short circuit value, code
46             q{all} => [0, sub { ($_[0] // 1) && $_[1] }],
47             q{any} => [1, sub { $_[0] || $_[1] }],
48             q{one} => [
49             undef,
50             sub {
51             my $val = $_[0] // ($_[1] ? 1 : undef);
52             $val -= ($_[1] ? 1 : 0) if defined $_[0] && $val;
53             return $val;
54             }
55             ],
56             );
57              
58             sub extract_state
59             {
60             my ($ref, $index) = @_;
61              
62             my $values = is_collapsible($ref) ? $ref->states : [$ref];
63              
64             return $values unless defined $index;
65             return $values->[$index];
66             }
67              
68 15     15   13980 use namespace::clean;
  15         54  
  15         94  
69              
70             with "Quantum::Superpositions::Lazy::Role::Operation";
71              
72             has "+sign" => (
73             is => "ro",
74             isa => Enum [keys %types],
75             required => 1,
76             );
77              
78             has "reducer" => (
79             is => "ro",
80             isa => Enum [keys %reducer_types],
81             writer => "set_reducer",
82             default => sub { $Quantum::Superpositions::Lazy::global_reducer_type },
83             );
84              
85             sub supported_types
86             {
87 15     15 0 43 my ($self) = @_;
88 15         89 return keys %types;
89             }
90              
91             sub run
92             {
93 80     80 0 176 my ($self, @parameters) = @_;
94              
95 80         298 my ($param_num, $code, $forced_reducer) = $types{$self->sign}->@*;
96 80         266 $self->_clear_parameters($param_num, @parameters);
97              
98 80         109 my $carry;
99 80   66     318 my $reducer = $reducer_types{$forced_reducer // $self->reducer};
100 80         176 my $iterator = get_iterator map { extract_state $_ } @parameters;
  164         313  
101              
102 80         201 while (my @params = $iterator->()) {
103              
104 3271         5172 @params = ($code->(@params));
105 3271         5115 unshift @params, $carry;
106              
107 3271         4983 $carry = $reducer->[1](@params);
108              
109             # short circuit if possible
110 3271 100 100     16954 return $carry if defined $reducer->[0] && !$carry eq !$reducer->[0];
111             }
112              
113 16         231 return !!$carry;
114             }
115              
116             sub valid_states
117             {
118 13     13 0 44 my ($self, @parameters) = @_;
119              
120 13         69 my ($param_num, $code, $forced_reducer) = $types{$self->sign}->@*;
121 13         69 $self->_clear_parameters($param_num, @parameters);
122              
123 13         26 my %results;
124 13   33     75 my $reducer = $reducer_types{$forced_reducer // $self->reducer};
125 13         30 my $iterator = get_iterator map { extract_state $_ } @parameters;
  26         68  
126              
127 13         69 while (my ($key_a, $val_a, @params) = $iterator->(1)) {
128 39529 100 66     143221 if (!defined $reducer->[0] || !defined $results{$key_a} || !$results{$key_a} ne !$reducer->[0]) {
      100        
129              
130 39394         72297 @params = map { $params[$_] } grep { $_ % 2 == 1 } keys @params;
  39394         81072  
  78788         148493  
131 39394         67276 @params = ($code->($val_a, @params));
132 39394         67182 unshift @params, $results{$key_a};
133              
134 39394         60037 $results{$key_a} = $reducer->[1](@params);
135             }
136             }
137              
138 13         26 my @carry;
139 13         11327 for my $key_a (keys %results) {
140 37710 100       80313 if ($results{$key_a}) {
141 30         73 push @carry, extract_state($parameters[0], $key_a);
142             }
143             }
144              
145 13         5503 return Quantum::Superpositions::Lazy::Superposition->new(
146             states => [@carry]
147             );
148             }
149              
150             1;
151