libsidplayfp  1.1.0
EventScheduler.h
1 /*
2  * This file is part of libsidplayfp, a SID player engine.
3  *
4  * Copyright (C) 2011-2012 Leandro Nini
5  * Copyright (C) 2009 Antti S. Lankila
6  * Copyright (C) 2001 Simon White
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #ifndef EVENTSCHEDULER_H
24 #define EVENTSCHEDULER_H
25 
26 #include <stdint.h>
27 
28 #include "event.h"
29 
30 
31 template< class This >
32 class EventCallback: public Event
33 {
34 private:
35  typedef void (This::*Callback) ();
36 
37 private:
38  This &m_this;
39  Callback const m_callback;
40 
41 private:
42  void event() { (m_this.*m_callback)(); }
43 
44 public:
45  EventCallback(const char * const name, This &_this, Callback callback) :
46  Event(name),
47  m_this(_this),
48  m_callback(callback) {}
49 };
50 
51 
58 {
59 private:
61  event_clock_t currentTime;
62 
64  Event *firstEvent;
65 
66 private:
72  void schedule(Event &event)
73  {
74  /* find the right spot where to tuck this new event */
75  Event **scan = &firstEvent;
76  for (;;)
77  {
78  if (*scan == 0 || (*scan)->triggerTime > event.triggerTime)
79  {
80  event.next = *scan;
81  *scan = &event;
82  break;
83  }
84  scan = &((*scan)->next);
85  }
86  }
87 
88 protected:
89  void schedule(Event &event, event_clock_t cycles,
90  event_phase_t phase)
91  {
92  // this strange formulation always selects the next available slot regardless of specified phase.
93  event.triggerTime = (cycles << 1) + currentTime + ((currentTime & 1) ^ phase);
94  schedule(event);
95  }
96 
97  void schedule(Event &event, event_clock_t cycles)
98  {
99  event.triggerTime = (cycles << 1) + currentTime;
100  schedule(event);
101  }
102 
103  void cancel(Event &event);
104 
105 public:
106  EventScheduler () :
107  currentTime(0),
108  firstEvent(0) {}
109 
111  void reset();
112 
114  void clock()
115  {
116  Event &event = *firstEvent;
117  firstEvent = firstEvent->next;
118  currentTime = event.triggerTime;
119  event.event();
120  }
121 
122  bool isPending(Event &event) const;
123 
124  event_clock_t getTime(event_phase_t phase) const
125  {
126  return (currentTime + (phase ^ 1)) >> 1;
127  }
128 
129  event_clock_t getTime(event_clock_t clock, event_phase_t phase) const
130  {
131  return getTime (phase) - clock;
132  }
133 
134  event_phase_t phase() const { return (event_phase_t) (currentTime & 1); }
135 };
136 
137 #endif // EVENTSCHEDULER_H