Fix some memory leak complaints from Valgrind
[lsnes.git] / src / core / dispatch.cpp
blob9ef820aba59bdb45b9d4c881920ce9280e66a345
1 #include "core/dispatch.hpp"
2 #include "library/globalwrap.hpp"
3 #include "core/keymapper.hpp"
4 #include "core/misc.hpp"
6 #include <sstream>
7 #include <iomanip>
8 #include <cmath>
10 #define START_EH_BLOCK try {
11 #define END_EH_BLOCK(obj, call) } catch(std::bad_alloc& e) { \
12 OOM_panic(); \
13 } catch(std::exception& e) { \
14 messages << "[dumper " << obj->get_name() << "] Warning: " call ": " << e.what() \
15 << std::endl; \
16 } catch(int code) { \
17 messages << "[dumper " << obj->get_name() << "] Warning: " call ": Error code #" << code \
18 << std::endl; \
21 gameinfo_struct::gameinfo_struct() throw(std::bad_alloc)
23 length = 0;
24 rerecords = "0";
27 std::string gameinfo_struct::get_readable_time(unsigned digits) const throw(std::bad_alloc)
29 double bias = 0.5 * pow(10, -static_cast<int>(digits));
30 double len = length + bias;
31 std::ostringstream str;
32 if(length >= 3600) {
33 double hours = floor(len / 3600);
34 str << hours << ":";
35 len -= hours * 3600;
37 double minutes = floor(len / 60);
38 len -= minutes * 60;
39 double seconds = floor(len);
40 len -= seconds;
41 str << std::setw(2) << std::setfill('0') << minutes << ":" << seconds;
42 if(digits > 0)
43 str << ".";
44 while(digits > 0) {
45 len = 10 * len;
46 str << '0' + static_cast<int>(len);
47 len -= floor(len);
48 digits--;
50 return str.str();
53 size_t gameinfo_struct::get_author_count() const throw()
55 return authors.size();
58 std::string gameinfo_struct::get_author_short(size_t idx) const throw(std::bad_alloc)
60 if(idx >= authors.size())
61 return "";
62 const std::pair<std::string, std::string>& x = authors[idx];
63 if(x.second != "")
64 return x.second;
65 else
66 return x.first;
69 uint64_t gameinfo_struct::get_rerecords() const throw()
71 uint64_t v = 0;
72 uint64_t max = 0xFFFFFFFFFFFFFFFFULL;
73 for(size_t i = 0; i < rerecords.length(); i++) {
74 if(v < max / 10)
75 //No risk of overflow.
76 v = v * 10 + static_cast<unsigned>(rerecords[i] - '0');
77 else if(v == max / 10) {
78 //THis may overflow.
79 v = v * 10;
80 if(v + static_cast<unsigned>(rerecords[i] - '0') < v)
81 return max;
82 v = v + static_cast<unsigned>(rerecords[i] - '0');
83 } else
84 //Definite overflow.
85 return max;
87 return v;
90 namespace
92 globalwrap<std::list<information_dispatch*>> _dispatch;
93 globalwrap<std::list<information_dispatch*>> dispatch_audio;
94 uint32_t srate_n = 32000;
95 uint32_t srate_d = 1;
96 struct gameinfo_struct sgi;
97 bool recursive = false;
100 information_dispatch::information_dispatch(const std::string& name) throw(std::bad_alloc)
102 target_name = name;
103 _dispatch().push_back(this);
104 known_if_dumper = false;
105 marked_as_dumper = false;
106 notified_as_dumper = false;
109 information_dispatch::~information_dispatch() throw()
111 for(auto i = _dispatch().begin(); i != _dispatch().end(); ++i) {
112 if(*i == this) {
113 _dispatch().erase(i);
114 break;
117 for(auto i = dispatch_audio().begin(); i != dispatch_audio().end(); ++i) {
118 if(*i == this) {
119 dispatch_audio().erase(i);
120 break;
123 if(notified_as_dumper)
124 for(auto& i : _dispatch()) {
125 START_EH_BLOCK
126 i->on_destroy_dumper(target_name);
127 END_EH_BLOCK(i, "on_destroy_dumper");
131 void information_dispatch::on_frame(struct framebuffer::raw& _frame, uint32_t fps_n, uint32_t fps_d)
133 //Do nothing.
136 void information_dispatch::do_frame(struct framebuffer::raw& _frame, uint32_t fps_n, uint32_t fps_d) throw()
138 update_dumpers();
139 for(auto& i : _dispatch()) {
140 START_EH_BLOCK
141 i->on_frame(_frame, fps_n, fps_d);
142 END_EH_BLOCK(i, "on_frame");
146 void information_dispatch::on_sample(short l, short r)
148 //Do nothing.
151 void information_dispatch::do_sample(short l, short r) throw()
153 update_dumpers();
154 for(auto& i : dispatch_audio()) {
155 START_EH_BLOCK
156 i->on_sample(l, r);
157 END_EH_BLOCK(i, "on_sample");
161 void information_dispatch::on_dump_end()
163 //Do nothing.
166 void information_dispatch::do_dump_end() throw()
168 update_dumpers();
169 for(auto& i : _dispatch()) {
170 START_EH_BLOCK
171 i->on_dump_end();
172 END_EH_BLOCK(i, "on_dump_end");
176 void information_dispatch::on_sound_rate(uint32_t rate_n, uint32_t rate_d)
178 if(!known_if_dumper) {
179 marked_as_dumper = get_dumper_flag();
180 known_if_dumper = true;
182 if(marked_as_dumper) {
183 messages << "[dumper " << get_name() << "] Warning: Sound sample rate changing not supported!"
184 << std::endl;
188 void information_dispatch::do_sound_rate(uint32_t rate_n, uint32_t rate_d) throw()
190 update_dumpers();
191 uint32_t g = gcd(rate_n, rate_d);
192 rate_n /= g;
193 rate_d /= g;
194 if(rate_n == srate_n && rate_d == srate_d)
195 return;
196 srate_n = rate_n;
197 srate_d = rate_d;
198 for(auto& i : _dispatch()) {
199 START_EH_BLOCK
200 i->on_sound_rate(rate_n, rate_d);
201 END_EH_BLOCK(i, "on_sound_rate");
205 std::pair<uint32_t, uint32_t> information_dispatch::get_sound_rate() throw()
207 return std::make_pair(srate_n, srate_d);
210 void information_dispatch::on_gameinfo(const struct gameinfo_struct& gi)
212 //Do nothing.
215 void information_dispatch::do_gameinfo(const struct gameinfo_struct& gi) throw()
217 update_dumpers();
218 try {
219 sgi = gi;
220 } catch(...) {
221 OOM_panic();
223 for(auto& i : _dispatch()) {
224 START_EH_BLOCK
225 i->on_gameinfo(sgi);
226 END_EH_BLOCK(i, "on_gameinfo");
230 const struct gameinfo_struct& information_dispatch::get_gameinfo() throw()
232 return sgi;
235 bool information_dispatch::get_dumper_flag() throw()
237 return false;
240 void information_dispatch::on_new_dumper(const std::string& dumper)
242 //Do nothing.
245 void information_dispatch::on_destroy_dumper(const std::string& dumper)
247 //Do nothing.
250 unsigned information_dispatch::get_dumper_count() throw()
252 update_dumpers(true);
253 unsigned count = 0;
254 for(auto& i : _dispatch())
255 if(i->marked_as_dumper)
256 count++;
257 if(!recursive) {
258 recursive = true;
259 update_dumpers();
260 recursive = false;
262 return count;
265 std::set<std::string> information_dispatch::get_dumpers() throw(std::bad_alloc)
267 update_dumpers();
268 std::set<std::string> r;
269 try {
270 for(auto& i : _dispatch())
271 if(i->notified_as_dumper)
272 r.insert(i->get_name());
273 } catch(...) {
274 OOM_panic();
276 return r;
280 const std::string& information_dispatch::get_name() throw()
282 return target_name;
285 void information_dispatch::update_dumpers(bool nocalls) throw()
287 for(auto& i : _dispatch()) {
288 if(!i->known_if_dumper) {
289 i->marked_as_dumper = i->get_dumper_flag();
290 i->known_if_dumper = true;
292 if(i->marked_as_dumper && !i->notified_as_dumper && !nocalls) {
293 for(auto& j : _dispatch()) {
294 START_EH_BLOCK
295 j->on_new_dumper(i->target_name);
296 END_EH_BLOCK(j, "on_new_dumper");
298 i->notified_as_dumper = true;
303 void information_dispatch::enable_send_sound() throw(std::bad_alloc)
305 dispatch_audio().push_back(this);
308 void information_dispatch::on_dumper_update()
310 //Do nothing.
313 void information_dispatch::do_dumper_update() throw()
315 if(in_global_ctors())
316 return;
317 for(auto& i : _dispatch()) {
318 START_EH_BLOCK
319 i->on_dumper_update();
320 END_EH_BLOCK(i, "on_dumper_update");
324 void dispatch_set_error_streams(std::ostream* stream)
326 notify_autofire_update.errors_to(stream);
327 notify_autohold_reconfigure.errors_to(stream);
328 notify_autohold_update.errors_to(stream);
329 notify_close.errors_to(stream);
330 notify_core_change.errors_to(stream);
331 notify_mode_change.errors_to(stream);
332 notify_new_core.errors_to(stream);
333 notify_screen_update.errors_to(stream);
334 notify_set_screen.errors_to(stream);
335 notify_sound_change.errors_to(stream);
336 notify_sound_unmute.errors_to(stream);
337 notify_status_update.errors_to(stream);
338 notify_subtitle_change.errors_to(stream);
339 notify_voice_stream_change.errors_to(stream);
340 notify_vu_change.errors_to(stream);
341 notify_core_changed.errors_to(stream);
342 notify_multitrack_change.errors_to(stream);
343 notify_title_change.errors_to(stream);
344 notify_branch_change.errors_to(stream);
345 notify_mbranch_change.errors_to(stream);
348 struct dispatch::source<> notify_autohold_reconfigure("autohold_reconfigure");
349 struct dispatch::source<unsigned, unsigned, unsigned, bool> notify_autohold_update("autohold_update");
350 struct dispatch::source<unsigned, unsigned, unsigned, unsigned, unsigned> notify_autofire_update("autofire_update");
351 struct dispatch::source<> notify_close("notify_close");
352 struct dispatch::source<framebuffer::fb<false>&> notify_set_screen("set_screen");
353 struct dispatch::source<std::pair<std::string, std::string>> notify_sound_change("sound_change");
354 struct dispatch::source<> notify_screen_update("screen_update");
355 struct dispatch::source<> notify_status_update("status_update");
356 struct dispatch::source<bool> notify_sound_unmute("sound_unmute");
357 struct dispatch::source<bool> notify_mode_change("mode_change");
358 struct dispatch::source<> notify_core_change("core_change");
359 struct dispatch::source<bool> notify_core_changed("core_changed");
360 struct dispatch::source<> notify_new_core("new_core");
361 struct dispatch::source<> notify_voice_stream_change("voice_stream_change");
362 struct dispatch::source<> notify_vu_change("vu_change");
363 struct dispatch::source<> notify_subtitle_change("subtitle_change");
364 struct dispatch::source<unsigned, unsigned, int> notify_multitrack_change("multitrack_change");
365 struct dispatch::source<> notify_title_change("title_change");
366 struct dispatch::source<> notify_branch_change("branch_change");
367 struct dispatch::source<> notify_mbranch_change("mbranch_change");