]> git.mxchange.org Git - simgear.git/blob - simgear/structure/event_mgr.cxx
Revert the check fro std::isnan() and isnan()
[simgear.git] / simgear / structure / event_mgr.cxx
1 #ifdef HAVE_CONFIG_H
2 #  include <simgear_config.h>
3 #endif
4
5 #include "event_mgr.hxx"
6
7 #include <simgear/debug/logstream.hxx>
8
9 void SGEventMgr::add(const std::string& name, SGCallback* cb,
10                      double interval, double delay,
11                      bool repeat, bool simtime)
12 {
13     // Clamp the delay value to 1 usec, so that user code can use
14     // "zero" as a synonym for "next frame".
15     if(delay <= 0) delay = 1e-6;
16     if(interval <= 0) interval = 1e-6; // No timer endless loops please...
17
18     SGTimer* t = new SGTimer;
19     t->interval = interval;
20     t->callback = cb;
21     t->repeat = repeat;
22     t->name = name;
23     t->running = false;
24     
25     SGTimerQueue* q = simtime ? &_simQueue : &_rtQueue;
26
27     q->insert(t, delay);
28 }
29
30 SGTimer::~SGTimer()
31 {
32     delete callback;
33     callback = NULL;
34 }
35
36 void SGTimer::run()
37 {
38     (*callback)();
39 }
40
41 SGEventMgr::SGEventMgr() :
42     _inited(false)
43 {
44     
45 }
46
47 SGEventMgr::~SGEventMgr()
48 {
49     
50 }
51
52 void SGEventMgr::unbind()
53 {
54     _freezeProp.clear();
55     _rtProp.clear();
56 }
57
58 void SGEventMgr::init()
59 {
60     if (_inited) {
61         // protected against duplicate calls here, in case
62                 // init ever does something more complex in the future.
63                 return;
64     }
65         
66     _inited = true;
67 }
68
69 void SGEventMgr::shutdown()
70 {
71     _inited = false;
72     
73     _simQueue.clear();
74     _rtQueue.clear();
75 }
76
77 void SGEventMgr::update(double delta_time_sec)
78 {
79     _simQueue.update(delta_time_sec);
80     
81     double rt = _rtProp ? _rtProp->getDoubleValue() : 0;
82     _rtQueue.update(rt);
83 }
84
85 void SGEventMgr::removeTask(const std::string& name)
86 {
87     // due to the ordering of the event-mgr in FG, tasks can be removed
88     // after we are shutdown (and hence, have all been cleared). Guard
89     // against this so we don't generate warnings below.
90     if (!_inited) {
91         return;
92     }
93     
94   SGTimer* t = _simQueue.findByName(name);
95   if (t) {
96     _simQueue.remove(t);
97   } else if ((t = _rtQueue.findByName(name))) {
98     _rtQueue.remove(t);
99   } else {
100     SG_LOG(SG_GENERAL, SG_WARN, "removeTask: no task found with name:" << name);
101     return;
102   }
103   if (t->running) {
104     // mark as not repeating so that the SGTimerQueue::update()
105     // will clean it up
106     t->repeat = false;
107   } else {
108     delete t;
109   }
110 }
111
112 ////////////////////////////////////////////////////////////////////////
113 // SGTimerQueue
114 // This is the priority queue implementation:
115 ////////////////////////////////////////////////////////////////////////
116
117 SGTimerQueue::SGTimerQueue(int size)
118 {
119     _now = 0;
120     _numEntries = 0;
121     _tableSize = 1;
122     while(size > _tableSize)
123         _tableSize = ((_tableSize + 1)<<1) - 1;
124
125     _table = new HeapEntry[_tableSize];
126     for(int i=0; i<_tableSize; i++) {
127             _table[i].pri = 0;
128         _table[i].timer = 0;
129     }
130 }
131
132
133 SGTimerQueue::~SGTimerQueue()
134 {
135     clear();
136     delete[] _table;
137 }
138
139 void SGTimerQueue::clear()
140 {
141     // delete entries
142     for(int i=0; i<_numEntries; i++) {
143         delete _table[i].timer;
144     }
145     
146     _numEntries = 0;
147     
148     // clear entire table to empty
149     for(int i=0; i<_tableSize; i++) {
150             _table[i].pri = 0;
151         _table[i].timer = 0;
152     }
153 }
154
155 void SGTimerQueue::update(double deltaSecs)
156 {
157     _now += deltaSecs;
158     while(_numEntries && nextTime() <= _now) {
159         SGTimer* t = remove();
160         if(t->repeat)
161             insert(t, t->interval);
162         // warning: this is not thread safe
163         // but the entire timer queue isn't either
164         t->running = true;
165         t->run();
166         t->running = false;
167         if (!t->repeat)
168             delete t;
169     }
170 }
171
172 void SGTimerQueue::insert(SGTimer* timer, double time)
173 {
174     if(_numEntries >= _tableSize)
175         growArray();
176
177     _numEntries++;
178     _table[_numEntries-1].pri = -(_now + time);
179     _table[_numEntries-1].timer = timer;
180
181     siftUp(_numEntries-1);
182 }
183
184 SGTimer* SGTimerQueue::remove(SGTimer* t)
185 {
186     int entry;
187     for(entry=0; entry<_numEntries; entry++)
188         if(_table[entry].timer == t)
189             break;
190     if(entry == _numEntries)
191         return 0;
192
193     // Swap in the last item in the table, and sift down
194     swap(entry, _numEntries-1);
195     _numEntries--;
196     siftDown(entry);
197
198     return t;
199 }
200
201 SGTimer* SGTimerQueue::remove()
202 {
203     if(_numEntries == 0) {
204         return 0;
205     } else if(_numEntries == 1) {
206         _numEntries = 0;
207         return _table[0].timer;
208     }
209
210     SGTimer *result = _table[0].timer;
211     _table[0] = _table[_numEntries - 1];
212     _numEntries--;
213     siftDown(0);
214     return result;
215 }
216
217 void SGTimerQueue::siftDown(int n)
218 {
219     // While we have children bigger than us, swap us with the biggest
220     // child.
221     while(lchild(n) < _numEntries) {
222         int bigc = lchild(n);
223         if(rchild(n) < _numEntries && pri(rchild(n)) > pri(bigc))
224             bigc = rchild(n);
225         if(pri(bigc) <= pri(n))
226             break;
227         swap(n, bigc);
228         n = bigc;
229     }
230 }
231
232 void SGTimerQueue::siftUp(int n)
233 {
234     while((n != 0) && (_table[n].pri > _table[parent(n)].pri)) {
235         swap(n, parent(n));
236         n = parent(n);
237     }
238     siftDown(n);
239 }
240
241 void SGTimerQueue::growArray()
242 {
243     _tableSize = ((_tableSize+1)<<1) - 1;
244     HeapEntry *newTable = new HeapEntry[_tableSize];
245     for(int i=0; i<_numEntries; i++) {
246         newTable[i].pri  = _table[i].pri;
247         newTable[i].timer = _table[i].timer;
248     }
249     delete[] _table;
250     _table = newTable;
251 }
252
253 SGTimer* SGTimerQueue::findByName(const std::string& name) const
254 {
255   for (int i=0; i < _numEntries; ++i) {
256     if (_table[i].timer->name == name) {
257       return _table[i].timer;
258     }
259   }
260   
261   return NULL;
262 }