File Coverage

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