libsidplayfp  0.3.5
event.h
1 /***************************************************************************
2  event.h - Event scheduler (based on alarm
3  from Vice)
4  -------------------
5  begin : Wed May 9 2001
6  copyright : (C) 2001 by Simon White
7  email : s_a_white@email.com
8  ***************************************************************************/
9 
10 /***************************************************************************
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * *
17  ***************************************************************************/
18 
19 #ifndef _event_h_
20 #define _event_h_
21 
22 #include "sidtypes.h"
23 
24 typedef int_fast64_t event_clock_t;
25 
32 typedef enum {EVENT_CLOCK_PHI1 = 0, EVENT_CLOCK_PHI2 = 1} event_phase_t;
33 
34 
44 class SID_EXTERN Event
45 {
46  friend class EventScheduler;
47 
48 private:
49  class EventContext *m_context SID_DEPRECATED;
50 
52  const char * const m_name;
53 
55  event_clock_t triggerTime;
56 
61  bool m_pending;
62 
64  Event *next;
65 
66 public:
73  Event(const char * const name)
74  : m_name(name),
75  m_pending(false) {}
76  ~Event() {}
77 
83  virtual void event (void) = 0;
84 
86  bool pending () const { return m_pending; }
87 
93  SID_DEPRECATED void cancel ();
94 
100  SID_DEPRECATED void schedule(EventContext &context, event_clock_t cycles,
101  event_phase_t phase);
102 };
103 
104 
105 template< class This >
106 class EventCallback: public Event
107 {
108 private:
109  typedef void (This::*Callback) ();
110  This &m_this;
111  Callback const m_callback;
112  void event(void) { (m_this.*m_callback) (); }
113 
114 public:
115  EventCallback (const char * const name, This &_this, Callback callback)
116  : Event(name), m_this(_this),
117  m_callback(callback) {}
118 };
119 
120 
121 // Public Event Context
123 {
124  friend class Event;
125 
126 public:
127  virtual void cancel (Event &event) = 0;
128  virtual void schedule (Event &event, const event_clock_t cycles,
129  const event_phase_t phase) = 0;
130  virtual void schedule (Event &event, const event_clock_t cycles) = 0;
131  virtual event_clock_t getTime (const event_phase_t phase) const = 0;
132  virtual event_clock_t getTime (const event_clock_t clock, const event_phase_t phase) const = 0;
133  virtual event_phase_t phase () const = 0;
134 };
135 
161 {
162 private:
163  event_clock_t currentTime;
164  Event *firstEvent;
165 
166 private:
167  void event (void);
168 
174  void schedule(Event &event) {
175 
176  if (event.m_pending)
177  cancel(event);
178 
179  event.m_pending = true;
180 
181  /* find the right spot where to tuck this new event */
182  Event **scan = &firstEvent;
183  for (;;) {
184  if (*scan == 0 || (*scan)->triggerTime > event.triggerTime) {
185  event.next = *scan;
186  *scan = &event;
187  break;
188  }
189  scan = &((*scan)->next);
190  }
191  }
192 
193 protected:
200  void schedule (Event &event, const event_clock_t cycles,
201  const event_phase_t phase) {
202  // this strange formulation always selects the next available slot regardless of specified phase.
203  event.triggerTime = (cycles << 1) + currentTime + ((currentTime & 1) ^ phase);
204  schedule(event);
205  }
206 
212  void schedule(Event &event, const event_clock_t cycles) {
213  event.triggerTime = (cycles << 1) + currentTime;
214  schedule(event);
215  }
216 
221  void cancel (Event &event);
222 
223 public:
224  EventScheduler ()
225  : currentTime(0),
226  firstEvent(0) {}
227 
229  void reset (void);
230 
232  void clock (void)
233  {
234  Event &event = *firstEvent;
235  firstEvent = firstEvent->next;
236  event.m_pending = false;
237  currentTime = event.triggerTime;
238  event.event();
239  }
240 
246  event_clock_t getTime (const event_phase_t phase) const
247  { return (currentTime + (phase ^ 1)) >> 1; }
248 
255  event_clock_t getTime (const event_clock_t clock, const event_phase_t phase) const
256  { return getTime (phase) - clock; }
257 
262  event_phase_t phase () const { return (event_phase_t) (currentTime & 1); }
263 };
264 
265 
266 inline void Event::schedule (EventContext &context, event_clock_t cycles,
267  event_phase_t phase)
268 {
269  m_context = &context;
270  m_context->schedule (*this, cycles, phase);
271 }
272 
273 inline void Event::cancel ()
274 {
275  if (m_pending)
276  m_context->cancel (*this);
277 }
278 
279 #endif // _event_h_