MyGUI 3.4.3
MyGUI_Delegate.h
Go to the documentation of this file.
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 <algorithm>
13#include <list>
14#include <memory>
15#include <functional>
16
17namespace MyGUI
18{
19
20 namespace delegates
21 {
22 // base class for unsubscribing from multi delegates
24 {
25 public:
26 virtual ~IDelegateUnlink() = default;
27
29 m_baseDelegateUnlink(this)
30 {
31 }
32 bool compare(IDelegateUnlink* _unlink) const
33 {
34 return m_baseDelegateUnlink == _unlink->m_baseDelegateUnlink;
35 }
36
37 private:
38 IDelegateUnlink* m_baseDelegateUnlink;
39 };
40
41 template<typename... Args>
43 {
44 public:
45 using Function = std::function<void(Args...)>;
46
47 // function or static class method
48 DelegateFunction(Function _function, Any _functionPointer) :
49 mFunction(_function),
50 mFunctionPointer(_functionPointer)
51 {
52 }
53
54 // non-static class method
55 DelegateFunction(Function _function, Any _functionPointer, const IDelegateUnlink* _object) :
56 mFunction(_function),
57 mUnlink(_object),
58 mObject(_object),
59 mFunctionPointer(_functionPointer)
60 {
61 }
62
63 // non-static class method
64 DelegateFunction(Function _function, Any _functionPointer, const void* _object) :
65 mFunction(_function),
66 mObject(_object),
67 mFunctionPointer(_functionPointer)
68 {
69 }
70
71 void invoke(Args... args)
72 {
73 mFunction(args...);
74 }
75
76 bool compare(DelegateFunction<Args...>* _delegate) const
77 {
78 if (nullptr == _delegate)
79 return false;
80 return _delegate->mObject == mObject && _delegate->mFunctionPointer.compare(mFunctionPointer);
81 }
82
83 bool compare(IDelegateUnlink* _unlink) const
84 {
85 return mUnlink == _unlink;
86 }
87
88 private:
89 Function mFunction;
90
91 const IDelegateUnlink* mUnlink = nullptr;
92 const void* mObject = nullptr;
93 Any mFunctionPointer;
94 };
95
96 } // namespace delegates
97
98 // Creates delegate from a function or a static class method
99 template<typename... Args>
100 inline delegates::DelegateFunction<Args...>* newDelegate(void (*_func)(Args... args))
101 {
102 return new delegates::DelegateFunction<Args...>(_func, _func);
103 }
104
105 // Creates delegate from a non-static class method
106 template<typename T, typename... Args>
107 inline delegates::DelegateFunction<Args...>* newDelegate(T* _object, void (T::*_method)(Args... args))
108 {
109 return new delegates::DelegateFunction<Args...>(
110 [=](Args&&... args) { return (_object->*_method)(std::forward<decltype(args)>(args)...); },
111 _method,
112 _object);
113 }
114 template<typename T, typename... Args>
115 inline delegates::DelegateFunction<Args...>* newDelegate(const T* _object, void (T::*_method)(Args... args) const)
116 {
117 return new delegates::DelegateFunction<Args...>(
118 [=](Args&&... args) { return (_object->*_method)(std::forward<decltype(args)>(args)...); },
119 _method,
120 _object);
121 }
122
123 // Creates delegate from std::function
124 // Require some user-defined delegateId, that should be used if operator-= is called to remove delegate.
125 // delegateId need to be unique within single delegate.
126 template<typename... Args>
128 const std::function<void(Args...)>& _function,
129 int64_t delegateId)
130 {
131 return new delegates::DelegateFunction<Args...>(_function, delegateId);
132 }
133
134
135 template<typename>
137 template<typename R, typename C, typename... Args>
138 struct GetDelegateFunctionFromLambda<R (C::*)(Args...) const>
139 {
141 };
142
143 // Creates delegate from lambda
144 // Require some user-defined delegateId, that should be used if operator-= is called to remove delegate.
145 // delegateId need to be unique within single delegate.
146 template<typename TLambda>
147 inline auto newDelegate(const TLambda& _function, int64_t delegateId)
148 {
149 using DelegateType = typename GetDelegateFunctionFromLambda<decltype(&TLambda::operator())>::type;
150 return new DelegateType(_function, delegateId);
151 }
152
153 namespace delegates
154 {
155
156 template<typename... Args>
158 {
159 public:
160 using IDelegate = DelegateFunction<Args...>;
161
162 bool empty() const
163 {
164 return !mDelegate;
165 }
166
167 void clear()
168 {
169 mDelegate.reset();
170 }
171
173 {
174 mDelegate.reset(_delegate);
175 return *this;
176 }
177
178 void operator()(Args... args) const
179 {
180 if (mDelegate)
181 mDelegate->invoke(args...);
182 }
183
184 private:
185 std::unique_ptr<IDelegate> mDelegate;
186 };
187
188 template<typename... Args>
190 {
191 public:
192 using IDelegate = DelegateFunction<Args...>;
193 using ListDelegate = typename std::list<std::unique_ptr<IDelegate>>;
194
195 // These shouldn't be necessary, but MSVC (17.6.5) requires them anyway
196 MultiDelegate() = default;
197 MultiDelegate(MultiDelegate&&) noexcept = default;
198
199 bool empty() const
200 {
201 for (const auto& delegate : mListDelegates)
202 {
203 if (delegate)
204 return false;
205 }
206 return true;
207 }
208
209 void clear()
210 {
211 if (mRunning)
212 {
213 for (auto& delegate : mListDelegates)
214 delegate.reset();
215 }
216 else
217 mListDelegates.clear();
218 }
219
220 void clear(IDelegateUnlink* _unlink)
221 {
222 if (!_unlink)
223 return;
224 for (auto& delegate : mListDelegates)
225 {
226 if (delegate && delegate->compare(_unlink))
227 delegate.reset();
228 }
229 }
230
231 void operator+=(IDelegate* _delegate)
232 {
233 if (!_delegate)
234 return;
235 auto found = std::find_if(
236 mListDelegates.begin(),
237 mListDelegates.end(),
238 [=](const auto& delegate) { return delegate && delegate->compare(_delegate); });
239 if (found != mListDelegates.end())
240 MYGUI_EXCEPT("Trying to add same delegate twice.");
241 mListDelegates.emplace_back(_delegate);
242 }
243
244 void operator-=(IDelegate* _delegate)
245 {
246 if (!_delegate)
247 return;
248 auto found = std::find_if(
249 mListDelegates.begin(),
250 mListDelegates.end(),
251 [=](const auto& delegate) { return delegate && delegate->compare(_delegate); });
252 if (found != mListDelegates.end())
253 {
254 if (found->get() == _delegate)
255 _delegate = nullptr;
256 found->reset();
257 }
258 delete _delegate;
259 }
260
261 void operator()(Args... args) const
262 {
263 bool canErase = !mRunning;
264 InvocationModificationGuard guard(*this);
265 for (auto it = mListDelegates.begin(); it != mListDelegates.end();)
266 {
267 if (*it)
268 (*it)->invoke(args...);
269 else if (canErase)
270 {
271 it = mListDelegates.erase(it);
272 continue;
273 }
274 ++it;
275 }
276 }
277
278 MYGUI_OBSOLETE("use : operator += ")
279 MultiDelegate& operator=(IDelegate* _delegate)
280 {
281 clear();
282 *this += _delegate;
283 return *this;
284 }
285
286 private:
287 mutable ListDelegate mListDelegates;
288 mutable bool mRunning{false};
289
291 {
292 const MultiDelegate* mDelegate;
293
294 public:
296 {
297 if (delegate.mRunning)
298 mDelegate = nullptr;
299 else
300 {
301 mDelegate = &delegate;
302 mDelegate->mRunning = true;
303 }
304 }
305 ~InvocationModificationGuard()
306 {
307 if (mDelegate)
308 mDelegate->mRunning = false;
309 }
310 };
311 friend class InvocationModificationGuard;
312 };
313
314#ifndef MYGUI_DONT_USE_OBSOLETE
315 using CDelegate0 MYGUI_OBSOLETE("use : MyGUI::delegates::Delegate<>") = Delegate<>;
316 template<typename... Args>
317 using CDelegate1 MYGUI_OBSOLETE("use : MyGUI::delegates::Delegate") = Delegate<Args...>;
318 template<typename... Args>
319 using CDelegate2 MYGUI_OBSOLETE("use : MyGUI::delegates::Delegate") = Delegate<Args...>;
320 template<typename... Args>
321 using CDelegate3 MYGUI_OBSOLETE("use : MyGUI::delegates::Delegate") = Delegate<Args...>;
322 template<typename... Args>
323 using CDelegate4 MYGUI_OBSOLETE("use : MyGUI::delegates::Delegate") = Delegate<Args...>;
324 template<typename... Args>
325 using CDelegate5 MYGUI_OBSOLETE("use : MyGUI::delegates::Delegate") = Delegate<Args...>;
326 template<typename... Args>
327 using CDelegate6 MYGUI_OBSOLETE("use : MyGUI::delegates::Delegate") = Delegate<Args...>;
328
329 using CMultiDelegate0 MYGUI_OBSOLETE("use : MyGUI::delegates::MultiDelegate<>") = MultiDelegate<>;
330 template<typename... Args>
331 using CMultiDelegate1 MYGUI_OBSOLETE("use : MyGUI::delegates::MultiDelegate") = MultiDelegate<Args...>;
332 template<typename... Args>
333 using CMultiDelegate2 MYGUI_OBSOLETE("use : MyGUI::delegates::MultiDelegate") = MultiDelegate<Args...>;
334 template<typename... Args>
335 using CMultiDelegate3 MYGUI_OBSOLETE("use : MyGUI::delegates::MultiDelegate") = MultiDelegate<Args...>;
336 template<typename... Args>
337 using CMultiDelegate4 MYGUI_OBSOLETE("use : MyGUI::delegates::MultiDelegate") = MultiDelegate<Args...>;
338 template<typename... Args>
339 using CMultiDelegate5 MYGUI_OBSOLETE("use : MyGUI::delegates::MultiDelegate") = MultiDelegate<Args...>;
340 template<typename... Args>
341 using CMultiDelegate6 MYGUI_OBSOLETE("use : MyGUI::delegates::MultiDelegate") = MultiDelegate<Args...>;
342#endif
343 }
344
345} // namespace MyGUI
346
347#endif // MYGUI_DELEGATE_H_
#define MYGUI_EXCEPT(dest)
#define MYGUI_OBSOLETE(text)
#define MYGUI_EXPORT
bool compare(const Any &other) const
Definition MyGUI_Any.cpp:44
DelegateFunction(Function _function, Any _functionPointer, const void *_object)
DelegateFunction(Function _function, Any _functionPointer)
DelegateFunction(Function _function, Any _functionPointer, const IDelegateUnlink *_object)
std::function< void(Args...)> Function
bool compare(DelegateFunction< Args... > *_delegate) const
bool compare(IDelegateUnlink *_unlink) const
void operator()(Args... args) const
Delegate & operator=(IDelegate *_delegate)
typename std::list< std::unique_ptr< IDelegate > > ListDelegate
void operator-=(IDelegate *_delegate)
void operator+=(IDelegate *_delegate)
MultiDelegate(MultiDelegate &&) noexcept=default
void clear(IDelegateUnlink *_unlink)
void operator()(Args... args) const
delegates::DelegateFunction< Args... > * newDelegate(void(*_func)(Args... args))