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   61987 use strict;
  80         165  
  80         2752  
10 80     80   409 use warnings;
  80         147  
  80         3453  
11              
12 80     80   407 use Carp;
  80         137  
  80         6953  
13              
14 80     80   947 use Time::HiRes qw( time );
  80         1338  
  80         1287  
15              
16             BEGIN {
17 80     80   311 my @methods = qw( next_time _enqueue cancel _fire );
18 80 50       239 if( eval { require Heap::Fibonacci } ) {
  80         33089  
19 80         151621 unshift our @ISA, "Heap::Fibonacci";
20 80         30523 require Heap::Elem;
21 80     80   19399 no strict 'refs';
  80         230  
  80         6259  
22 80         17947 *$_ = \&{"HEAP_$_"} for @methods;
  320         12908  
23             }
24             else {
25 80     80   474 no strict 'refs';
  80         152  
  80         3722  
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 4073 my $self = shift;
35 733         3554 my ( %params ) = @_;
36              
37 733         1681 my $code = delete $params{code};
38 733 100       3614 ref $code or croak "Expected 'code' to be a reference";
39              
40 731 100       1909 defined $params{time} or croak "Expected 'time'";
41 730         1178 my $time = $params{time};
42              
43 730         3629 $self->_enqueue( $time, $code );
44             }
45              
46             sub fire
47             {
48 1222     1222 0 5029 my $self = shift;
49 1222         2816 my ( %params ) = @_;
50              
51 1222 100       5169 my $now = exists $params{now} ? $params{now} : time;
52 1222         3830 $self->_fire( $now );
53             }
54              
55             # Implementation using a Perl array
56              
57             use constant {
58 80         42579 TIME => 0,
59             CODE => 1,
60 80     80   602 };
  80         184  
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 1198     1198 0 5798 my $self = shift;
119              
120 1198         3713 my $top = $self->top;
121              
122 1198 100       8065 return defined $top ? $top->time : undef;
123             }
124              
125             sub HEAP__enqueue
126             {
127 730     730 0 1279 my $self = shift;
128 730         1338 my ( $time, $code ) = @_;
129              
130 730         7104 my $elem = IO::Async::Internals::TimeQueue::Elem->new( $time, $code );
131 730         3694 $self->add( $elem );
132              
133 730         24866 return $elem;
134             }
135              
136             sub HEAP_cancel
137             {
138 538     538 0 24300 my $self = shift;
139 538         1008 my ( $id ) = @_;
140              
141 538         2568 $self->delete( $id );
142             }
143              
144             sub HEAP__fire
145             {
146 1222     1222 0 2101 my $self = shift;
147 1222         2349 my ( $now ) = @_;
148              
149 1222         1847 my $count = 0;
150              
151 1222         5402 while( defined( my $top = $self->top ) ) {
152 1320 100       10783 last if( $top->time > $now );
153              
154 191         1934 $self->extract_top;
155              
156 191         3839 $top->code->();
157 189         2954 $count++;
158             }
159              
160 1220         10118 return $count;
161             }
162              
163             package # hide from CPAN
164             IO::Async::Internals::TimeQueue::Elem;
165              
166 80     80   610 use strict;
  80         151  
  80         13869  
167             our @ISA = qw( Heap::Elem );
168              
169             sub new
170             {
171 730     730   1663 my $self = shift;
172 730   33     4320 my $class = ref $self || $self;
173              
174 730         1418 my ( $time, $code ) = @_;
175              
176 730         3503 my $new = $class->SUPER::new(
177             time => $time,
178             code => $code,
179             );
180              
181 730         8974 return $new;
182             }
183              
184             sub time
185             {
186 3963     3963   7434 my $self = shift;
187 3963         8602 return $self->val->{time};
188             }
189              
190             sub code
191             {
192 191     191   401 my $self = shift;
193 191         532 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   23254 my $self = shift;
200 752         928 my $other = shift;
201              
202 752         1209 $self->time <=> $other->time;
203             }
204              
205             0x55AA;