summaryrefslogtreecommitdiff
path: root/lib/IO/Async/Internals/TimeQueue.pm
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2015-06-01 14:15:30 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2015-06-01 14:15:30 +0000
commit1425eea04dd872dc6313f5315f317b2de288037c (patch)
treef81c74f75429e829714029850f89ee4c7f13aa39 /lib/IO/Async/Internals/TimeQueue.pm
downloadIO-Async-tarball-master.tar.gz
Diffstat (limited to 'lib/IO/Async/Internals/TimeQueue.pm')
-rw-r--r--lib/IO/Async/Internals/TimeQueue.pm205
1 files changed, 205 insertions, 0 deletions
diff --git a/lib/IO/Async/Internals/TimeQueue.pm b/lib/IO/Async/Internals/TimeQueue.pm
new file mode 100644
index 0000000..4278fbd
--- /dev/null
+++ b/lib/IO/Async/Internals/TimeQueue.pm
@@ -0,0 +1,205 @@
+# You may distribute under the terms of either the GNU General Public License
+# or the Artistic License (the same terms as Perl itself)
+#
+# (C) Paul Evans, 2006-2012 -- leonerd@leonerd.org.uk
+
+package # hide from CPAN
+ IO::Async::Internals::TimeQueue;
+
+use strict;
+use warnings;
+
+use Carp;
+
+use Time::HiRes qw( time );
+
+BEGIN {
+ my @methods = qw( next_time _enqueue cancel _fire );
+ if( eval { require Heap::Fibonacci } ) {
+ unshift our @ISA, "Heap::Fibonacci";
+ require Heap::Elem;
+ no strict 'refs';
+ *$_ = \&{"HEAP_$_"} for @methods;
+ }
+ else {
+ no strict 'refs';
+ *$_ = \&{"ARRAY_$_"} for "new", @methods;
+ }
+}
+
+# High-level methods
+
+sub enqueue
+{
+ my $self = shift;
+ my ( %params ) = @_;
+
+ my $code = delete $params{code};
+ ref $code or croak "Expected 'code' to be a reference";
+
+ defined $params{time} or croak "Expected 'time'";
+ my $time = $params{time};
+
+ $self->_enqueue( $time, $code );
+}
+
+sub fire
+{
+ my $self = shift;
+ my ( %params ) = @_;
+
+ my $now = exists $params{now} ? $params{now} : time;
+ $self->_fire( $now );
+}
+
+# Implementation using a Perl array
+
+use constant {
+ TIME => 0,
+ CODE => 1,
+};
+
+sub ARRAY_new
+{
+ my $class = shift;
+ return bless [], $class;
+}
+
+sub ARRAY_next_time
+{
+ my $self = shift;
+ return @$self ? $self->[0]->[TIME] : undef;
+}
+
+sub ARRAY__enqueue
+{
+ my $self = shift;
+ my ( $time, $code ) = @_;
+
+ # TODO: This could be more efficient maybe using a binary search
+ my $idx = 0;
+ $idx++ while $idx < @$self and $self->[$idx][TIME] <= $time;
+ splice @$self, $idx, 0, ( my $elem = [ $time, $code ]);
+
+ return $elem;
+}
+
+sub ARRAY_cancel
+{
+ my $self = shift;
+ my ( $id ) = @_;
+
+ @$self = grep { $_ != $id } @$self;
+}
+
+sub ARRAY__fire
+{
+ my $self = shift;
+ my ( $now ) = @_;
+
+ my $count = 0;
+
+ while( @$self ) {
+ last if( $self->[0]->[TIME] > $now );
+
+ my $top = shift @$self;
+
+ $top->[CODE]->();
+ $count++;
+ }
+
+ return $count;
+}
+
+# Implementation using Heap::Fibonacci
+
+sub HEAP_next_time
+{
+ my $self = shift;
+
+ my $top = $self->top;
+
+ return defined $top ? $top->time : undef;
+}
+
+sub HEAP__enqueue
+{
+ my $self = shift;
+ my ( $time, $code ) = @_;
+
+ my $elem = IO::Async::Internals::TimeQueue::Elem->new( $time, $code );
+ $self->add( $elem );
+
+ return $elem;
+}
+
+sub HEAP_cancel
+{
+ my $self = shift;
+ my ( $id ) = @_;
+
+ $self->delete( $id );
+}
+
+sub HEAP__fire
+{
+ my $self = shift;
+ my ( $now ) = @_;
+
+ my $count = 0;
+
+ while( defined( my $top = $self->top ) ) {
+ last if( $top->time > $now );
+
+ $self->extract_top;
+
+ $top->code->();
+ $count++;
+ }
+
+ return $count;
+}
+
+package # hide from CPAN
+ IO::Async::Internals::TimeQueue::Elem;
+
+use strict;
+our @ISA = qw( Heap::Elem );
+
+sub new
+{
+ my $self = shift;
+ my $class = ref $self || $self;
+
+ my ( $time, $code ) = @_;
+
+ my $new = $class->SUPER::new(
+ time => $time,
+ code => $code,
+ );
+
+ return $new;
+}
+
+sub time
+{
+ my $self = shift;
+ return $self->val->{time};
+}
+
+sub code
+{
+ my $self = shift;
+ return $self->val->{code};
+}
+
+# This only uses methods so is transparent to HASH or ARRAY
+sub cmp
+{
+ my $self = shift;
+ my $other = shift;
+
+ $self->time <=> $other->time;
+}
+
+0x55AA;