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