File Coverage

lib/Perl6/GatherTake/LazyList.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package # hide from PAUSE indexer
2             Perl6::GatherTake::LazyList;
3              
4             =head1 NAME
5              
6             C - Lazy tied array for C.
7              
8             =head1 SYNOPSIS
9              
10             You shouldn't use this module. C does that transparently
11             for you.
12              
13             use Coro;
14             use Coro::Channel;
15             use Perl6::GatherTake::LazyList;
16              
17             my $queue = Coro::Channel->new(1);
18              
19             my $coro = async {
20             for (1 .. 100){
21             my $result;
22             # do some heavy computations here
23             $queue->put($result);
24             }
25             };
26              
27             my @results;
28             tie @results, 'Perl6::GatherTake::LazyList', $coro, $queue;
29              
30             =head1 DESCRIPTION
31              
32             Tied array implementation for C. Again: don't use this
33             yourself unless you really know what you're doing (and you don't).
34              
35             =head1 LICENSE
36              
37             Same as C.
38              
39             =head1 AUTHOR
40              
41             Moritz Lenz, L, L.
42             E-Mail Emoritz@faui2k3.orgE.
43              
44             =cut
45              
46 6     6   30 use strict;
  6         11  
  6         219  
47 6     6   28 use warnings;
  6         11  
  6         183  
48 6     6   29 use Carp qw(confess cluck);
  6         10  
  6         401  
49 6     6   26 use Scalar::Util qw(refaddr);
  6         11  
  6         661  
50             #use Data::Dumper;
51              
52 6     6   2423 use Coro;
  0            
  0            
53             our %_ties;
54              
55             our @ISA;
56              
57             BEGIN {
58             require Tie::Array;
59             @ISA = qw(Tie::Array);
60             }
61              
62             sub TIEARRAY {
63             my ($class, $coro, $queue) = @_;
64             my $self = bless {
65             coro => $coro,
66             queue => $queue,
67             computed => [],
68             exhausted => 0,
69             }, $class;
70             $_ties{$coro} = $self;
71              
72             $coro->on_destroy( sub {
73             #print "Exhausted iterator\n";
74             $self->{exhausted} = 1 ;
75             # this is tricky: the coro will not put another item into
76             # the queue when it end, but _compute calls ->get(), thus
77             # waits for one - which is a deadlock.
78             # so we have to put another value, which _computed will remove
79             $self->{queue}->put(undef);
80             });
81              
82             return $self;
83             }
84              
85             sub FETCH {
86             my ($self, $index) = @_;
87             # warn "Fetching item $index ($self->{exhausted})\n";
88             # print Dumper $self->{computed};
89             $self->_compute($index);
90             return $self->{computed}->[$index];
91             }
92              
93             sub STORE {
94             my ($self, $index, $value) = @_;
95             $self->_compute($index);
96             $self->{computed}[$index] = $value;
97             }
98              
99             # XXX this is ugly and wrong
100             sub FETCHSIZE {
101             my $self = shift;
102             # warn "# FETCHSIZE called\n";
103             return ($self->{exhausted} ? 0 : 1) + scalar @{$self->{computed}};
104             # return 2;
105              
106             # while (!$self->{exhausted}){
107             # $self->_compute();
108             # }
109             # return scalar @{$self->{computed}};
110             }
111              
112             sub STORESIZE {
113             # do nothing
114             }
115              
116             sub EXISTS {
117             my ($self, $index) = @_;
118             # warn "EXISTS($index) called\n";
119             $self->_compute($index);
120             return @{$self->{computed}} > $index ? 1 : 0;
121             }
122              
123             sub _compute {
124             my $self = shift;
125             return if $self->{exhausted};
126             # print "Size: ", $self->{queue}->size, "\n";
127              
128             # local $Coro::idle = sub { $self->{queue}->put(undef) };
129              
130              
131             if (@_){
132             my $index = shift;
133             while(@{$self->{computed}} <= $index && !$self->{exhausted}){
134             push @{$self->{computed}}, $self->{queue}->get();
135             }
136             } else {
137             push @{$self->{computed}}, $self->{queue}->get();
138             }
139             if ($self->{exhausted}){
140             # see comment in sub TIEARRAY - the last item is pushed
141             # by the on_destroy handler that also set the exhausted flag
142             pop @{$self->{computed}};
143             }
144             # print Dumper $self->{computed};
145             }
146              
147             sub UNTIE {
148             my $self = shift;
149             delete $self->{computed};
150             }
151              
152             1;