File Coverage

blib/lib/Sim/Dispatcher.pm
Criterion Covered Total %
statement 53 56 94.6
branch 15 20 75.0
condition 7 8 87.5
subroutine 11 11 100.0
pod 7 7 100.0
total 93 102 91.1


line stmt bran cond sub pod time code
1             package Sim::Dispatcher;
2              
3 2     2   606 use strict;
  2         4  
  2         77  
4 2     2   10 use warnings;
  2         4  
  2         84  
5              
6             our $VERSION = '0.03';
7              
8 2     2   12 use Carp qw( carp croak );
  2         4  
  2         1423  
9              
10             our $DEBUG = 0;
11              
12             sub new {
13 3 50   3 1 23 my $self = ref $_[0] ? ref shift : shift;
14 3         12 my %opts = @_;
15 3 50       19 croak "No clock given" if !$opts{clock};
16 3         23 bless {
17             clock => $opts{clock},
18             queue => [],
19             }, $self;
20             }
21              
22             sub now {
23 84     84 1 1754 $_[0]->{clock}->now;
24             }
25              
26             sub schedule {
27 21     21 1 71 my $self = shift;
28 21         121 my %events = @_;
29 21         75 while (my ($time, $handle) = each %events) {
30 29 50       83 if ($time < $self->now) {
31 0         0 carp "out-dated event [$time => $handle] ignored";
32 0         0 next;
33             }
34 29         86 $self->_insert_event([$time => $handle]);
35             }
36             }
37              
38             sub _insert_event {
39 29     29   42 my ($self, $event) = @_;
40 29         43 my $queue = $self->{queue};
41 29         79 for (my $i = 0; $i < @$queue; $i++) {
42 15 100       48 if ($event->[0] < $queue->[$i]->[0]) {
43 7         12 splice( @$queue, $i, 0, $event );
44 7         36 return;
45             }
46             }
47 22         117 push @$queue, $event;
48             }
49              
50             sub fire_next ($) {
51 26     26 1 44 my $self = shift;
52 26         51 my $queue = $self->{queue};
53 26         35 my $clock = $self->{clock};
54 26 50       60 return undef if @$queue == 0;
55 26         59 my $event = shift @$queue;
56 26         44 my ($time, $handle) = @$event;
57 26         54 my $now = $self->now;
58 26 50       65 if ($time >= $now) {
59 26         69 $clock->push_to($time);
60 26         58 $handle->();
61             } else {
62 0         0 die "Clock modified outside of the dispatcher: next event is at $time while now is $now";
63             }
64 26         102 return 1;
65             }
66              
67             sub run ($@) {
68 6     6 1 42 my $self = shift;
69 6         17 my %opts = @_;
70 6 100       22 my $end_time = $self->now + $opts{duration} if defined $opts{duration};
71 6   100     26 my $fires = $opts{fires} || 100_000_000;
72 6         6 my $i = 0;
73 6         9 while (1) {
74             #warn "run: next!";
75 32 100       644 last if ++$i > $fires;
76 30         61 my $t = $self->time_of_next;
77 30 100 100     153 last if !defined $t or (defined $end_time and $t > $end_time);
      66        
78 26         56 $self->fire_next;
79             }
80             }
81              
82             sub time_of_next ($) {
83 32     32 1 41 my $self = shift;
84 32         50 my $queue = $self->{queue};
85 32 100       100 return @$queue ? $queue->[0]->[0] : undef;
86             }
87              
88             sub reset ($) {
89 4     4 1 571 my $self = shift;
90 4         10 $self->{queue} = [];
91 4         21 $self->{clock}->reset();
92             }
93              
94             1;
95             __END__