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 80     80   78726 use strict;
  80         4529  
  80         3526  
10 80     80   635 use warnings;
  80         1180  
  80         3988  
11              
12 80     80   489 use Carp;
  80         161  
  80         8068  
13              
14 80     80   1173 use Time::HiRes qw( time );
  80         1758  
  80         1175  
15              
16             BEGIN {
17 80     80   381 my @methods = qw( next_time _enqueue cancel _fire );
18 80 50       164 if( eval { require Heap::Fibonacci } ) {
  80         40287  
19 80         181845 unshift our @ISA, "Heap::Fibonacci";
20 80         37121 require Heap::Elem;
21 80     80   22169 no strict 'refs';
  80         355  
  80         7629  
22 80         21998 *$_ = \&{"HEAP_$_"} for @methods;
  320         15579  
23             }
24             else {
25 80     80   619 no strict 'refs';
  80         207  
  80         4739  
26 0         0 *$_ = \&{"ARRAY_$_"} for "new", @methods;
  0         0  
27             }
28             }
29              
30             # High-level methods
31              
32             sub enqueue
33             {
34 733     733 0 5399 my $self = shift;
35 733         5639 my ( %params ) = @_;
36              
37 733         1926 my $code = delete $params{code};
38 733 100       3888 ref $code or croak "Expected 'code' to be a reference";
39              
40 731 100       2403 defined $params{time} or croak "Expected 'time'";
41 730         1346 my $time = $params{time};
42              
43 730         5457 $self->_enqueue( $time, $code );
44             }
45              
46             sub fire
47             {
48 1295     1295 0 6342 my $self = shift;
49 1295         3538 my ( %params ) = @_;
50              
51 1295 100       6600 my $now = exists $params{now} ? $params{now} : time;
52 1295         5016 $self->_fire( $now );
53             }
54              
55             # Implementation using a Perl array
56              
57             use constant {
58 80         51044 TIME => 0,
59             CODE => 1,
60 80     80   752 };
  80         266  
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 1275     1275 0 6940 my $self = shift;
119              
120 1275         4689 my $top = $self->top;
121              
122 1275 100       9960 return defined $top ? $top->time : undef;
123             }
124              
125             sub HEAP__enqueue
126             {
127 730     730 0 1788 my $self = shift;
128 730         1679 my ( $time, $code ) = @_;
129              
130 730         8293 my $elem = IO::Async::Internals::TimeQueue::Elem->new( $time, $code );
131 730         4366 $self->add( $elem );
132              
133 730         31592 return $elem;
134             }
135              
136             sub HEAP_cancel
137             {
138 538     538 0 1628 my $self = shift;
139 538         1092 my ( $id ) = @_;
140              
141 538         2795 $self->delete( $id );
142             }
143              
144             sub HEAP__fire
145             {
146 1295     1295 0 2737 my $self = shift;
147 1295         2781 my ( $now ) = @_;
148              
149 1295         2473 my $count = 0;
150              
151 1295         6975 while( defined( my $top = $self->top ) ) {
152 1393 100       12829 last if( $top->time > $now );
153              
154 191         2051 $self->extract_top;
155              
156 191         4370 $top->code->();
157 189         2893 $count++;
158             }
159              
160 1293         11697 return $count;
161             }
162              
163             package # hide from CPAN
164             IO::Async::Internals::TimeQueue::Elem;
165              
166 80     80   667 use strict;
  80         317  
  80         16675  
167             our @ISA = qw( Heap::Elem );
168              
169             sub new
170             {
171 730     730   1605 my $self = shift;
172 730   33     4104 my $class = ref $self || $self;
173              
174 730         1815 my ( $time, $code ) = @_;
175              
176 730         3395 my $new = $class->SUPER::new(
177             time => $time,
178             code => $code,
179             );
180              
181 730         11208 return $new;
182             }
183              
184             sub time
185             {
186 4113     4113   9500 my $self = shift;
187 4113         11921 return $self->val->{time};
188             }
189              
190             sub code
191             {
192 191     191   385 my $self = shift;
193 191         454 return $self->val->{code};
194             }
195              
196             # This only uses methods so is transparent to HASH or ARRAY
197             sub cmp
198             {
199 752     752   27014 my $self = shift;
200 752         1177 my $other = shift;
201              
202 752         1361 $self->time <=> $other->time;
203             }
204              
205             0x55AA;