1 /*
2 * This source file is part of MyGUI. For the latest info, see http://mygui.info/
3 * Distributed under the MIT License
4 * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
5 */
6
7 #ifndef MYGUI_DELEGATE_H_
8 #define MYGUI_DELEGATE_H_
9
10 #include "MyGUI_Diagnostic.h"
11 #include "MyGUI_Any.h"
12 #include <list>
13
14 #include <functional>
15
16 namespace MyGUI
17 {
18
19 namespace delegates
20 {
21 // base class for unsubscribing from multi delegates
22 class IDelegateUnlink
23 {
24 public:
25 virtual ~IDelegateUnlink() = default;
26
IDelegateUnlink()27 IDelegateUnlink()
28 {
29 m_baseDelegateUnlink = this;
30 }
compare(IDelegateUnlink * _unlink)31 bool compare(IDelegateUnlink* _unlink) const
32 {
33 return m_baseDelegateUnlink == _unlink->m_baseDelegateUnlink;
34 }
35
36 private:
37 IDelegateUnlink* m_baseDelegateUnlink;
38 };
39
40 template <typename ...Args>
41 class DelegateFunction
42 {
43 public:
44 using Function = std::function<void(Args...)>;
45
46 // function or static class method
DelegateFunction(Function _function,Any _functionPointer)47 DelegateFunction(Function _function, Any _functionPointer) :
48 mFunction(_function),
49 mFunctionPointer(_functionPointer)
50 {
51 }
52
53 // non-static class method
DelegateFunction(Function _function,Any _functionPointer,IDelegateUnlink * _object)54 DelegateFunction(Function _function, Any _functionPointer, IDelegateUnlink* _object) :
55 mFunction(_function),
56 mUnlink(_object),
57 mObject(_object),
58 mFunctionPointer(_functionPointer)
59 {
60 }
61
62 // non-static class method
DelegateFunction(Function _function,Any _functionPointer,void * _object)63 DelegateFunction(Function _function, Any _functionPointer, void* _object) :
64 mFunction(_function),
65 mUnlink(nullptr),
66 mObject(_object),
67 mFunctionPointer(_functionPointer)
68 {
69 }
70
invoke(Args...args)71 void invoke(Args... args)
72 {
73 mFunction(args...);
74 }
75
compare(DelegateFunction<Args...> * _delegate)76 bool compare(DelegateFunction<Args...>* _delegate) const
77 {
78 if (nullptr == _delegate) return false;
79 return _delegate->mObject == mObject && _delegate->mFunctionPointer.compare(mFunctionPointer);
80 }
81
compare(IDelegateUnlink * _unlink)82 bool compare(IDelegateUnlink* _unlink) const
83 {
84 return mUnlink == _unlink;
85 }
86
87 private:
88 Function mFunction;
89
90 IDelegateUnlink* mUnlink = nullptr;
91 void* mObject = nullptr;
92 Any mFunctionPointer;
93 };
94
95 } // namespace delegates
96
97 // Creates delegate from a function or a static class method
98 template <typename ...Args>
newDelegate(void (* _func)(Args...args))99 inline delegates::DelegateFunction<Args...>* newDelegate(void(*_func)(Args... args))
100 {
101 return new delegates::DelegateFunction<Args...>(_func, _func);
102 }
103
104 // Creates delegate from a non-static class method
105 template <typename T, typename ...Args>
newDelegate(T * _object,void (T::* _method)(Args...args))106 inline delegates::DelegateFunction<Args...>* newDelegate(T* _object, void (T::*_method)(Args... args))
107 {
108 return new delegates::DelegateFunction<Args...>(
109 [=](Args&&... args) { return (_object->*_method)(std::forward<decltype(args)>(args)...); },
110 _method,
111 _object);
112 }
113
114 namespace delegates
115 {
116
117 template <typename ...Args>
118 class Delegate
119 {
120 public:
121 using IDelegate = DelegateFunction<Args...>;
122
Delegate()123 Delegate() : mDelegate(nullptr) { }
Delegate(const Delegate & _event)124 Delegate(const Delegate& _event) : mDelegate(nullptr)
125 {
126 // take ownership
127 mDelegate = _event.mDelegate;
128 const_cast<Delegate&>(_event).mDelegate = nullptr;
129 }
130
~Delegate()131 ~Delegate()
132 {
133 clear();
134 }
135
empty()136 bool empty() const
137 {
138 return mDelegate == nullptr;
139 }
140
clear()141 void clear()
142 {
143 delete mDelegate;
144 mDelegate = nullptr;
145 }
146
147 Delegate& operator=(IDelegate* _delegate)
148 {
149 delete mDelegate;
150 mDelegate = _delegate;
151 return *this;
152 }
153
154 Delegate& operator=(const Delegate<Args...>& _event)
155 {
156 if (this == &_event)
157 return *this;
158
159 // take ownership
160 IDelegate* del = _event.mDelegate;
161 const_cast<Delegate&>(_event).mDelegate = nullptr;
162
163 if (mDelegate != nullptr && !mDelegate->compare(del))
164 delete mDelegate;
165
166 mDelegate = del;
167
168 return *this;
169 }
170
operator()171 void operator()(Args... args)
172 {
173 if (mDelegate == nullptr) return;
174 mDelegate->invoke(args...);
175 }
176
177 private:
178 IDelegate* mDelegate;
179 };
180
181 template <typename ...Args>
182 class MultiDelegate
183 {
184 public:
185 using IDelegate = DelegateFunction<Args...>;
186 using ListDelegate = typename std::list<IDelegate*>;
187
MultiDelegate()188 MultiDelegate() { }
~MultiDelegate()189 ~MultiDelegate()
190 {
191 clear();
192 }
193
empty()194 bool empty() const
195 {
196 for (const auto& delegate : mListDelegates)
197 {
198 if (delegate) return false;
199 }
200 return true;
201 }
202
clear()203 void clear()
204 {
205 for (auto iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
206 {
207 if (*iter)
208 {
209 delete (*iter);
210 (*iter) = nullptr;
211 }
212 }
213 }
214
clear(IDelegateUnlink * _unlink)215 void clear(IDelegateUnlink* _unlink)
216 {
217 for (auto iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
218 {
219 if ((*iter) && (*iter)->compare(_unlink))
220 {
221 delete (*iter);
222 (*iter) = nullptr;
223 }
224 }
225 }
226
227 void operator+=(IDelegate* _delegate)
228 {
229 for (auto iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
230 {
231 if ((*iter) && (*iter)->compare(_delegate))
232 {
233 MYGUI_EXCEPT("Trying to add same delegate twice.");
234 }
235 }
236 mListDelegates.push_back(_delegate);
237 }
238
239 void operator-=(IDelegate* _delegate)
240 {
241 for (auto iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
242 {
243 if ((*iter) && (*iter)->compare(_delegate))
244 {
245 if ((*iter) != _delegate) delete (*iter);
246 (*iter) = nullptr;
247 break;
248 }
249 }
250 delete _delegate;
251 }
252
operator()253 void operator()(Args... args)
254 {
255 auto iter = mListDelegates.begin();
256 while (iter != mListDelegates.end())
257 {
258 if (nullptr == (*iter))
259 {
260 iter = mListDelegates.erase(iter);
261 }
262 else
263 {
264 (*iter)->invoke(args...);
265 ++iter;
266 }
267 }
268 }
269
MultiDelegate(const MultiDelegate & _event)270 MultiDelegate(const MultiDelegate& _event)
271 {
272 // take ownership
273 ListDelegate del = _event.mListDelegates;
274 const_cast<MultiDelegate&>(_event).mListDelegates.clear();
275
276 safe_clear(del);
277
278 mListDelegates = del;
279 }
280
281 MultiDelegate& operator=(const MultiDelegate& _event)
282 {
283 // take ownership
284 ListDelegate del = _event.mListDelegates;
285 const_cast<MultiDelegate&>(_event).mListDelegates.clear();
286
287 safe_clear(del);
288
289 mListDelegates = del;
290
291 return *this;
292 }
293
294 MYGUI_OBSOLETE("use : operator += ")
295 MultiDelegate& operator=(IDelegate* _delegate)
296 {
297 clear();
298 *this += _delegate;
299 return *this;
300 }
301
302 private:
safe_clear(ListDelegate & _delegates)303 void safe_clear(ListDelegate& _delegates)
304 {
305 for (auto iter = mListDelegates.begin(); iter != mListDelegates.end(); ++iter)
306 {
307 if (*iter)
308 {
309 IDelegate* del = (*iter);
310 (*iter) = nullptr;
311 delete_is_not_found(del, _delegates);
312 }
313 }
314 }
315
delete_is_not_found(IDelegate * _del,ListDelegate & _delegates)316 void delete_is_not_found(IDelegate* _del, ListDelegate& _delegates)
317 {
318 for (auto iter = _delegates.begin(); iter != _delegates.end(); ++iter)
319 {
320 if ((*iter) && (*iter)->compare(_del))
321 {
322 return;
323 }
324 }
325
326 delete _del;
327 }
328
329 private:
330 ListDelegate mListDelegates;
331 };
332
333 //#ifndef MYGUI_DONT_USE_OBSOLETE // TODO
334 using CDelegate0 = Delegate<>;
335 template <typename ...Args>
336 using CDelegate1 = Delegate<Args...>;
337 template <typename ...Args>
338 using CDelegate2 = Delegate<Args...>;
339 template <typename ...Args>
340 using CDelegate3 = Delegate<Args...>;
341 template <typename ...Args>
342 using CDelegate4 = Delegate<Args...>;
343 template <typename ...Args>
344 using CDelegate5 = Delegate<Args...>;
345 template <typename ...Args>
346 using CDelegate6 = Delegate<Args...>;
347
348 using CMultiDelegate0 = MultiDelegate<>;
349 template <typename ...Args>
350 using CMultiDelegate1 = MultiDelegate<Args...>;
351 template <typename ...Args>
352 using CMultiDelegate2 = MultiDelegate<Args...>;
353 template <typename ...Args>
354 using CMultiDelegate3 = MultiDelegate<Args...>;
355 template <typename ...Args>
356 using CMultiDelegate4 = MultiDelegate<Args...>;
357 template <typename ...Args>
358 using CMultiDelegate5 = MultiDelegate<Args...>;
359 template <typename ...Args>
360 using CMultiDelegate6 = MultiDelegate<Args...>;
361 //#endif
362 }
363
364 } // namespace MyGUI
365
366 #endif // MYGUI_DELEGATE_H_
367