File Coverage

blib/lib/IO/Async/Internals/TimeQueue.pm
Criterion Covered Total %
statement 74 99 74.7
branch 11 16 68.7
condition 1 6 16.6
subroutine 19 24 79.1
pod 0 11 0.0
total 105 156 67.3


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2006-2012 -- leonerd@leonerd.org.uk
5              
6             package # hide from CPAN
7             IO::Async::Internals::TimeQueue;
8              
9 77     77   76468 use strict;
  77         193  
  77         3380  
10 77     77   521 use warnings;
  77         161  
  77         4128  
11              
12 77     77   511 use Carp;
  77         155  
  77         9015  
13              
14 77     77   1187 use Time::HiRes qw( time );
  77         1663  
  77         1167  
15              
16             BEGIN {
17 77     77   367 my @methods = qw( next_time _enqueue cancel _fire );
18 77 50       181 if( eval { require Heap::Fibonacci } ) {
  77         46446  
19 77         176914 unshift our @ISA, "Heap::Fibonacci";
20 77         38157 require Heap::Elem;
21 77     77   23940 no strict 'refs';
  77         314  
  77         7312  
22 77         21637 *$_ = \&{"HEAP_$_"} for @methods;
  308         15164  
23             }
24             else {
25 77     77   570 no strict 'refs';
  77         269  
  77         4674  
26 0         0 *$_ = \&{"ARRAY_$_"} for "new", @methods;
  0         0  
27             }
28             }
29              
30             # High-level methods
31              
32             sub enqueue
33             {
34 703     703 0 4891 my $self = shift;
35 703         4552 my ( %params ) = @_;
36              
37 703         1773 my $code = delete $params{code};
38 703 100       3165 ref $code or croak "Expected 'code' to be a reference";
39              
40 701 100       2114 defined $params{time} or croak "Expected 'time'";
41 700         1354 my $time = $params{time};
42              
43 700         4522 $self->_enqueue( $time, $code );
44             }
45              
46             sub fire
47             {
48 1219     1219 0 6179 my $self = shift;
49 1219         3174 my ( %params ) = @_;
50              
51 1219 100       5874 my $now = exists $params{now} ? $params{now} : time;
52 1219         4699 $self->_fire( $now );
53             }
54              
55             # Implementation using a Perl array
56              
57             use constant {
58 77         50394 TIME => 0,
59             CODE => 1,
60 77     77   693 };
  77         338  
61              
62             sub ARRAY_new
63             {
64 0     0 0 0 my $class = shift;
65 0         0 return bless [], $class;
66             }
67              
68             sub ARRAY_next_time
69             {
70 0     0 0 0 my $self = shift;
71 0 0       0 return @$self ? $self->[0]->[TIME] : undef;
72             }
73              
74             sub ARRAY__enqueue
75             {
76 0     0 0 0 my $self = shift;
77 0         0 my ( $time, $code ) = @_;
78              
79             # TODO: This could be more efficient maybe using a binary search
80 0         0 my $idx = 0;
81 0   0     0 $idx++ while $idx < @$self and $self->[$idx][TIME] <= $time;
82 0         0 splice @$self, $idx, 0, ( my $elem = [ $time, $code ]);
83              
84 0         0 return $elem;
85             }
86              
87             sub ARRAY_cancel
88             {
89 0     0 0 0 my $self = shift;
90 0         0 my ( $id ) = @_;
91              
92 0         0 @$self = grep { $_ != $id } @$self;
  0         0  
93             }
94              
95             sub ARRAY__fire
96             {
97 0     0 0 0 my $self = shift;
98 0         0 my ( $now ) = @_;
99              
100 0         0 my $count = 0;
101              
102 0         0 while( @$self ) {
103 0 0       0 last if( $self->[0]->[TIME] > $now );
104              
105 0         0 my $top = shift @$self;
106              
107 0         0 $top->[CODE]->();
108 0         0 $count++;
109             }
110              
111 0         0 return $count;
112             }
113              
114             # Implementation using Heap::Fibonacci
115              
116             sub HEAP_next_time
117             {
118 1189     1189 0 7210 my $self = shift;
119              
120 1189         4094 my $top = $self->top;
121              
122 1189 100       9674 return defined $top ? $top->time : undef;
123             }
124              
125             sub HEAP__enqueue
126             {
127 700     700 0 1624 my $self = shift;
128 700         1559 my ( $time, $code ) = @_;
129              
130 700         8835 my $elem = IO::Async::Internals::TimeQueue::Elem->new( $time, $code );
131 700         4692 $self->add( $elem );
132              
133 700         30661 return $elem;
134             }
135              
136             sub HEAP_cancel
137             {
138 526     526 0 1570 my $self = shift;
139 526         1197 my ( $id ) = @_;
140              
141 526         4347 $self->delete( $id );
142             }
143              
144             sub HEAP__fire
145             {
146 1219     1219 0 2442 my $self = shift;
147 1219         2633 my ( $now ) = @_;
148              
149 1219         2212 my $count = 0;
150              
151 1219         5285 while( defined( my $top = $self->top ) ) {
152 1341 100       12541 last if( $top->time > $now );
153              
154 173         1639 $self->extract_top;
155              
156 173         3655 $top->code->();
157 171         1570 $count++;
158             }
159              
160 1217         10763 return $count;
161             }
162              
163             package # hide from CPAN
164             IO::Async::Internals::TimeQueue::Elem;
165              
166 77     77   660 use strict;
  77         247  
  77         16293  
167             our @ISA = qw( Heap::Elem );
168              
169             sub new
170             {
171 700     700   1697 my $self = shift;
172 700   33     4395 my $class = ref $self || $self;
173              
174 700         1640 my ( $time, $code ) = @_;
175              
176 700         3742 my $new = $class->SUPER::new(
177             time => $time,
178             code => $code,
179             );
180              
181 700         10191 return $new;
182             }
183              
184             sub time
185             {
186 3969     3969   8265 my $self = shift;
187 3969         10167 return $self->val->{time};
188             }
189              
190             sub code
191             {
192 173     173   351 my $self = shift;
193 173         407 return $self->val->{code};
194             }
195              
196             # This only uses methods so is transparent to HASH or ARRAY
197             sub cmp
198             {
199 734     734   25145 my $self = shift;
200 734         1048 my $other = shift;
201              
202 734         1264 $self->time <=> $other->time;
203             }
204              
205             0x55AA;