File Coverage

blib/lib/HOI/Comprehensions.pm
Criterion Covered Total %
statement 105 108 97.2
branch 21 30 70.0
condition 3 3 100.0
subroutine 12 12 100.0
pod 4 7 57.1
total 145 160 90.6


line stmt bran cond sub pod time code
1             package HOI::Comprehensions;
2              
3             require Exporter;
4             our @ISA = qw( Exporter );
5             our @EXPORT_OK = qw( comp );
6             our $VERSION = '0.045';
7              
8              
9             sub comp {
10 3     3 0 449 my $computation = shift;
11 3         6 my $generators_ = \@_;
12             sub {
13 3     3   7 my @guards = @_;
14 3         4 my %generators;
15 3         5 my ($evalstr, $postfix) = ("", "");
16 3         4 my $self_;
17 3         11 while ($#$generators_ > -1) {
18 7         14 my ($key, $value) = (shift @$generators_, shift @$generators_);
19 7         14 $evalstr .= '$self->{generators}->{'.$key.'}->(';
20 7         9 $postfix .= ')';
21             $generators{$key} =
22             (ref($value) eq 'ARRAY') ?
23             sub {
24 4         5 my $idx = 0;
25             sub {
26 60 100       103 if ($#_ == -1) {
27 6 50       22 my $last_ret = (defined $value->[$idx]) ? { $key => $value->[$idx] } : {};
28 6         8 $idx++;
29 6         11 my $last_done = ($idx > $#$value);
30 6 50       20 $idx %= ($#$value + 1) if ($#$value > -1);
31 6         37 return ($last_done, $last_ret);
32             }
33 54         49 my ($done, $res) = @_;
34 54         126 my $ret = { %$res, $key => $value->[$idx] };
35 54 100       82 $idx++ if ($done);
36 54         56 my $self_done = ($idx > $#$value);
37 54         52 $idx %= ($#$value + 1);
38 54         256 ($self_done, $ret);
39             }
40 4         32 }->() :
41             ( (ref($value) eq 'HOI::Comprehensions') ?
42             sub {
43 1         8 my $value_ = $value;
44 1         3 my $idx = 0;
45             sub {
46             my $forward =
47             sub {
48 27         18 my ($ret, $forward_done);
49 27 100       46 if ($value_->{all_done}) {
50 24         33 ($ret) = $value_->{list}->[$idx];
51 24         20 $idx++;
52 24         21 $forward_done = ($idx > $#{$value_->{list}});
  24         37  
53 24         19 $idx %= ($#{$value_->{list}} + 1);
  24         37  
54 24         40 return ($forward_done, $ret);
55             }
56 3         10 ($ret, $forward_done) = $value_->next(0);
57 3         7 ($forward_done, $ret)
58 27         88 };
59 27 50       63 if ($#_ == -1) {
60 0         0 my ($last_done, $last_res) = $forward->();
61 0         0 return ($last_done, { $key => $last_res });
62             }
63 27         27 my ($done, $res) = @_;
64 27         33 my ($self_done, $self_res) = $forward->();
65 27         72 my $ret = { %$res, $key => $self_res };
66 27         154 ($self_done * $done, $ret);
67             }
68 1         8 }->() :
69             sub {
70 30 100       61 if ($#_ == -1) {
71 27         46 my ($last_res, $last_done) = $value->();
72 27 50       97 $last_done = 1 if (not defined $last_done);
73 27         84 return ($last_done, { $key => $last_res });
74             }
75 3         3 my ($done, $res) = @_;
76             my ($self_res, $self_done) =
77             sub {
78 3         4 my $scopestr = '';
79 3         4 my ($package_name) = $self_->{caller};
80 3         6 local $AttrPrefix = $package_name.'::';
81 3         7 for my $elt (keys %$res) {
82 3         11 $scopestr = 'local $'."$AttrPrefix"."$elt"." = \$res->{$elt}; ";
83             }
84 3         152 eval $scopestr.'$value->()';
85             #$value->();
86 3         18 }->();
87 3 50       38 $self_done = 1 if (not defined $self_done);
88 3         8 my $ret = { %$res, $key => $self_res };
89 3         17 ($self_done * $done, $ret);
90             }
91 7 100       54 );
    100          
92             }
93             $self_ =
94 3         37 bless
95             {
96             computation => $computation,
97             generators => \%generators,
98             all_done => 0,
99             geneitr => $evalstr.$postfix,
100             guards => \@guards,
101             list => [],
102             caller => caller()
103             }
104             }
105 3         27 }
106              
107             sub get_member {
108 2     2 1 2 my ($self, $name) = @_;
109 2         11 $self->{$name}
110             }
111              
112             sub get_list {
113 1     1 1 42 my ($self) = @_;
114 1         4 $self->get_member('list')
115             }
116              
117             sub is_over {
118 1     1 1 2 my ($self) = @_;
119 1         2 $self->get_member('all_done')
120             }
121              
122             sub step_next_lazy {
123 33     33 0 38 my ($self, $flag) = @_;
124 33 50       62 return ($self->{list}, 1) if ($self->{all_done});
125 33         1960 my ($done, $arguments) = eval $self->{geneitr};
126 33         110 $self->{all_done} = $done;
127 33         40 my ($package_name) = $self->{caller};
128 33         52 local $AttrPrefix = $package_name.'::';
129 33         35 my $evalstr = '';
130 33         70 for my $key (keys %$arguments) {
131 117         185 $evalstr .= 'local $'."$AttrPrefix"."$key".' = $arguments->{'."$key".'}; ';
132             }
133             my %switches = (
134             full => sub {
135 33     33   31 my $guards_ok = 1;
136 33         3183 eval '{'.$evalstr.'($_->($arguments) or $guards_ok = 0) for (@{$self->{guards}}); '.'push @{$self->{list}}, $self->{computation}->($arguments) if ($guards_ok); '.'}';
137 33         328 $guards_ok
138             },
139 33         122 );
140 33         34 my $guard = 0;
141 33 50       30 $guard = $switches{$flag}->() if (scalar(keys %$arguments) == scalar(keys %{$self->{generators}}));
  33         97  
142 33         461 ($self->{list}, $done, $guard)
143             }
144              
145             sub next {
146             my ($l_, $done, $guard);
147             for my $cnt (0..$_[1]) {
148             do {
149             ($l_, $done, $guard) = $_[0]->step_next_lazy('full');
150             } until ($done or $guard);
151             }
152             ($l_->[$#$l_], $done, $guard)
153             }
154              
155             sub next {
156 24     24 0 22 my ($l_, $done, $guard);
157             #print "cnt to $_[1]\n";
158 24         35 for my $cnt (0..$_[1]) {
159 24   100     20 do {
160 33         63 ($l_, $done, $guard) = $_[0]->step_next_lazy('full');
161             } until ($done or $guard);
162             }
163 24         67 ($l_->[$#$l_], $done, $guard)
164             }
165              
166             use overload
167 21     21   168 '<>' => sub { my @ret = $_[0]->next(0); \@ret },
  21         85  
168             '+' =>
169             sub {
170             #print(scalar(@{$_[0]->{list}}), ' ', $_[1], "\n");
171 18 50   18   89 my @ret = (scalar(@{$_[0]->{list}}) - 1 >= $_[1]) ? ($_[0]->{list}->[$_[1]], $_[0]->{all_done}) : ($_[0]->next($_[1] - scalar(@{$_[0]->{list}})));
  18         48  
  0         0  
172             \@ret
173 18         32 },
174 1     1   29493 ;
  1         830  
  1         10  
175              
176             1;
177              
178             sub force {
179 1     1 1 5 my $self = shift;
180 1 50       4 if (not $self->{all_done}) {
181 1         1 my ($elt, $done);
182 1         1 do {
183 3         4 ($elt, $done) = @{<$self>};
  3         6  
184             } while (not $done);
185             }
186 1         5 $self->{list}
187             }
188              
189             __END__