File Coverage

blib/lib/HOI/Comprehensions.pm
Criterion Covered Total %
statement 103 106 97.1
branch 19 26 73.0
condition 3 3 100.0
subroutine 12 12 100.0
pod 4 7 57.1
total 141 154 91.5


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