Actually call on_reset callback
[lsnes.git] / include / library / dispatch.hpp
blobbc23cf25bcb3391c4130fe0051dbb6f975665486
1 #ifndef _library__dispatch__hpp__included__
2 #define _library__dispatch__hpp__included__
4 #include <iostream>
5 #include <map>
6 #include <set>
7 #include <list>
8 #include <functional>
9 #include "threads.hpp"
11 namespace dispatch
13 threads::lock& global_init_lock();
15 template<typename... T> struct source;
17 /**
18 * Dispatch target handler.
20 template<typename... T> struct target
22 /**
23 * Create a new target handler.
25 target()
27 src = NULL;
28 fn = dummy;
30 /**
31 * Destroy a target, detaching it from source.
33 inline ~target();
34 /**
35 * Connect a target to given source and give a handler.
37 * Parameter d: The source to connect to.
38 * Parameter _fn: The function to use as handler.
40 inline void set(source<T...>& d, std::function<void(T...)> _fn);
41 private:
42 static void dummy(T... args) {};
43 void set_source(source<T...>* d) { src = d; }
44 void call(T... args) { fn(args...); }
45 source<T...>* src;
46 std::function<void(T...)> fn;
47 friend class source<T...>;
50 /**
51 * Dispatch source (event generator).
53 template<typename... T> struct source
55 /**
56 * Create a new event source.
58 * Parameter _name: The name of the event.
60 source(const char* _name)
62 init();
63 name = _name;
65 /**
66 * Destory an event source.
68 * All targets are disconnected.
70 ~source()
72 delete _targets;
73 delete lck;
74 lck = NULL;
76 /**
77 * Send an event.
79 * Parameter args: The arguments to send.
81 void operator()(T... args)
83 init();
84 uint64_t k = 0;
85 typename std::map<uint64_t, target<T...>*>::iterator i;
86 lck->lock();
87 i = targets().lower_bound(k);
88 while(i != targets().end()) {
89 k = i->first + 1;
90 target<T...>* t = i->second;
91 lck->unlock();
92 try {
93 t->call(args...);
94 } catch(std::exception& e) {
95 (*errstrm) << name << ": Error in handler: " << e.what() << std::endl;
97 lck->lock();
98 i = targets().lower_bound(k);
100 lck->unlock();
103 * Connect a new target.
105 * Parameters target: The target to connect.
107 void connect(target<T...>& target)
109 init();
110 threads::alock h(*lck);
111 targets()[next_cbseq++] = &target;
112 target.set_source(this);
115 * Disconnect a target.
117 * Parameters target: The target to disconnect.
119 void disconnect(target<T...>& target)
121 init();
122 if(!lck)
123 return;
124 threads::alock h(*lck);
125 for(auto i = targets().begin(); i != targets().end(); i++)
126 if(i->second == &target) {
127 targets().erase(i);
128 break;
130 target.set_source(NULL);
133 * Set stream to send error messages to.
135 * Parameter to: The stream (if NULL, use std::cerr).
137 void errors_to(std::ostream* to)
139 errstrm = to ? to : &std::cerr;
141 private:
142 void init()
144 if(inited)
145 return;
146 threads::alock h(global_init_lock());
147 if(inited)
148 return;
149 errstrm = &std::cerr;
150 next_cbseq = 0;
151 name = "(unknown)";
152 _targets = NULL;
153 lck = new threads::lock;
154 inited = true;
156 threads::lock* lck;
157 std::map<uint64_t, target<T...>*>& targets()
159 if(!_targets) _targets = new std::map<uint64_t, target<T...>*>;
160 return *_targets;
162 std::map<uint64_t, target<T...>*>* _targets;
163 uint64_t next_cbseq;
164 std::ostream* errstrm;
165 const char* name;
166 bool inited;
167 source(const source<T...>&);
168 source<T...>& operator=(const source<T...>&);
171 template <typename... T> target<T...>::~target()
173 if(src)
174 src->disconnect(*this);
177 template <typename... T> void target<T...>::set(source<T...>& d, std::function<void(T...)> _fn)
179 fn = _fn;
180 src = &d;
181 if(src)
182 src->connect(*this);
185 #endif