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             $Quantum::Superpositions::Lazy::Operation::Logical::VERSION = '1.12';
3 15     15   152 use v5.24;
  15         45  
4 15     15   114 use warnings;
  15         31  
  15         351  
5 15     15   76 use Moo;
  15         73  
  15         92  
6 15     15   4592 use Quantum::Superpositions::Lazy::Superposition;
  15         42  
  15         549  
7 15     15   382 use Quantum::Superpositions::Lazy::Util qw(is_collapsible get_iterator);
  15         34  
  15         822  
8 15     15   101 use Types::Standard qw(Enum);
  15         279  
  15         125  
9              
10             my %types = (
11              
12             # type => number of parameters, code, forced reducer type
13             q{!} => [1, sub { !$_[0] }, "all"],
14              
15             q{==} => [2, sub { $_[0] == $_[1] }],
16             q{!=} => [2, sub { $_[0] != $_[1] }],
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              
22             q{eq} => [2, sub { $_[0] eq $_[1] }],
23             q{ne} => [2, sub { $_[0] ne $_[1] }],
24             q{gt} => [2, sub { $_[0] gt $_[1] }],
25             q{ge} => [2, sub { $_[0] ge $_[1] }],
26             q{lt} => [2, sub { $_[0] lt $_[1] }],
27             q{le} => [2, sub { $_[0] le $_[1] }],
28              
29             q{_compare} => [
30             [2,],
31             sub {
32             local $_ = shift;
33             my $sub = shift;
34             $sub->($_, @_);
35             }
36             ],
37             );
38              
39             # TODO: should "one" reducer run after every iterator pair
40             # or after an element is compared with the entire superposition?
41             my %reducer_types = (
42              
43             # type => short circuit value, code
44             q{all} => [0, sub { ($_[0] // 1) && $_[1] }],
45             q{any} => [1, sub { $_[0] || $_[1] }],
46             q{one} => [
47             undef,
48             sub {
49             my $val = $_[0] // ($_[1] ? 1 : undef);
50             $val -= ($_[1] ? 1 : 0) if defined $_[0] && $val;
51             return $val;
52             }
53             ],
54             );
55              
56             sub extract_state
57             {
58             my ($ref, $index) = @_;
59              
60             my $values = is_collapsible($ref) ? $ref->states : [$ref];
61              
62             return $values unless defined $index;
63             return $values->[$index];
64             }
65              
66 15     15   13756 use namespace::clean;
  15         40  
  15         118  
67              
68             with "Quantum::Superpositions::Lazy::Role::Operation";
69              
70             has "+sign" => (
71             is => "ro",
72             isa => Enum [keys %types],
73             required => 1,
74             );
75              
76             has "reducer" => (
77             is => "ro",
78             isa => Enum [keys %reducer_types],
79             writer => "set_reducer",
80             default => sub { $Quantum::Superpositions::Lazy::global_reducer_type },
81             );
82              
83             sub supported_types
84             {
85 15     15 0 46 my ($self) = @_;
86 15         95 return keys %types;
87             }
88              
89             sub run
90             {
91 80     80 0 172 my ($self, @parameters) = @_;
92              
93 80         264 my ($param_num, $code, $forced_reducer) = $types{$self->sign}->@*;
94 80         282 $self->_clear_parameters($param_num, @parameters);
95              
96 80         125 my $carry;
97 80   66     304 my $reducer = $reducer_types{$forced_reducer // $self->reducer};
98 80         181 my $iterator = get_iterator map { extract_state $_ } @parameters;
  164         299  
99              
100 80         208 while (my @params = $iterator->()) {
101              
102 2282         3527 @params = ($code->(@params));
103 2282         3526 unshift @params, $carry;
104              
105 2282         3840 $carry = $reducer->[1](@params);
106              
107             # short circuit if possible
108 2282 100 100     13847 return $carry if defined $reducer->[0] && !$carry eq !$reducer->[0];
109             }
110              
111 16         280 return !!$carry;
112             }
113              
114             sub valid_states
115             {
116 13     13 0 41 my ($self, @parameters) = @_;
117              
118 13         80 my ($param_num, $code, $forced_reducer) = $types{$self->sign}->@*;
119 13         72 $self->_clear_parameters($param_num, @parameters);
120              
121 13         23 my %results;
122 13   33     78 my $reducer = $reducer_types{$forced_reducer // $self->reducer};
123 13         32 my $iterator = get_iterator map { extract_state $_ } @parameters;
  26         78  
124              
125 13         51 while (my ($key_a, $val_a, @params) = $iterator->(1)) {
126 39529 100 66     134180 if (!defined $reducer->[0] || !defined $results{$key_a} || !$results{$key_a} ne !$reducer->[0]) {
      100        
127              
128 39370         71130 @params = map { $params[$_] } grep { $_ % 2 == 1 } keys @params;
  39370         75861  
  78740         140857  
129 39370         68177 @params = ($code->($val_a, @params));
130 39370         62881 unshift @params, $results{$key_a};
131              
132 39370         58197 $results{$key_a} = $reducer->[1](@params);
133             }
134             }
135              
136 13         27 my @carry;
137 13         12197 for my $key_a (keys %results) {
138 37710 100       89959 if ($results{$key_a}) {
139 30         77 push @carry, extract_state($parameters[0], $key_a);
140             }
141             }
142              
143 13         5538 return Quantum::Superpositions::Lazy::Superposition->new(
144             states => [@carry]
145             );
146             }
147              
148             1;
149