MyGUI: MyGUI_Delegate.h Source File

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
23 class MYGUI_EXPORT IDelegateUnlink
24 {
25 public:
26 virtual ~IDelegateUnlink() = default;
27
28 IDelegateUnlink() :
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>
42 class DelegateFunction
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>
127 inline delegates::DelegateFunction<Args...>* newDelegate(
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>
136 struct GetDelegateFunctionFromLambda;
137 template<typename R, typename C, typename... Args>
138 struct GetDelegateFunctionFromLambda<R (C::*)(Args...) const>
139 {
140 using type = MyGUI::delegates::DelegateFunction<Args...>;
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>
157 class Delegate
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
172 Delegate& operator=(IDelegate* _delegate)
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>
189 class MultiDelegate
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
290 class InvocationModificationGuard
291 {
292 const MultiDelegate* mDelegate;
293
294 public:
295 InvocationModificationGuard(const MultiDelegate& delegate)
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_
MyGUI_Any.h
MyGUI_Diagnostic.h
MYGUI_EXCEPT
#define MYGUI_EXCEPT(dest)
Definition MyGUI_Diagnostic.h:21
MYGUI_OBSOLETE
#define MYGUI_OBSOLETE(text)
Definition MyGUI_Diagnostic.h:68
MYGUI_EXPORT
#define MYGUI_EXPORT
Definition MyGUI_Platform.h:77
MyGUI::Any
Definition MyGUI_Any.h:56
MyGUI::Any::compare
bool compare(const Any &other) const
Definition MyGUI_Any.cpp:44
MyGUI::delegates::DelegateFunction
Definition MyGUI_Delegate.h:43
MyGUI::delegates::DelegateFunction::invoke
void invoke(Args... args)
Definition MyGUI_Delegate.h:71
MyGUI::delegates::DelegateFunction::DelegateFunction
DelegateFunction(Function _function, Any _functionPointer, const void *_object)
Definition MyGUI_Delegate.h:64
MyGUI::delegates::DelegateFunction::DelegateFunction
DelegateFunction(Function _function, Any _functionPointer)
Definition MyGUI_Delegate.h:48
MyGUI::delegates::DelegateFunction::DelegateFunction
DelegateFunction(Function _function, Any _functionPointer, const IDelegateUnlink *_object)
Definition MyGUI_Delegate.h:55
MyGUI::delegates::DelegateFunction::Function
std::function< void(Args...)> Function
Definition MyGUI_Delegate.h:45
MyGUI::delegates::DelegateFunction::compare
bool compare(DelegateFunction< Args... > *_delegate) const
Definition MyGUI_Delegate.h:76
MyGUI::delegates::DelegateFunction::compare
bool compare(IDelegateUnlink *_unlink) const
Definition MyGUI_Delegate.h:83
MyGUI::delegates::Delegate
Definition MyGUI_Delegate.h:158
MyGUI::delegates::Delegate::operator()
void operator()(Args... args) const
Definition MyGUI_Delegate.h:178
MyGUI::delegates::Delegate< Canvas *, Event >::IDelegate
DelegateFunction< Args... > IDelegate
Definition MyGUI_Delegate.h:160
MyGUI::delegates::Delegate::clear
void clear()
Definition MyGUI_Delegate.h:167
MyGUI::delegates::Delegate::empty
bool empty() const
Definition MyGUI_Delegate.h:162
MyGUI::delegates::Delegate::operator=
Delegate & operator=(IDelegate *_delegate)
Definition MyGUI_Delegate.h:172
MyGUI::delegates::IDelegateUnlink
Definition MyGUI_Delegate.h:24
MyGUI::delegates::IDelegateUnlink::IDelegateUnlink
IDelegateUnlink()
Definition MyGUI_Delegate.h:28
MyGUI::delegates::IDelegateUnlink::~IDelegateUnlink
virtual ~IDelegateUnlink()=default
MyGUI::delegates::IDelegateUnlink::compare
bool compare(IDelegateUnlink *_unlink) const
Definition MyGUI_Delegate.h:32
MyGUI::delegates::MultiDelegate
Definition MyGUI_Delegate.h:190
MyGUI::delegates::MultiDelegate< Canvas * >::ListDelegate
typename std::list< std::unique_ptr< IDelegate > > ListDelegate
Definition MyGUI_Delegate.h:193
MyGUI::delegates::MultiDelegate< Canvas * >::empty
bool empty() const
Definition MyGUI_Delegate.h:199
MyGUI::delegates::MultiDelegate::operator-=
void operator-=(IDelegate *_delegate)
Definition MyGUI_Delegate.h:244
MyGUI::delegates::MultiDelegate::MultiDelegate
MultiDelegate()=default
MyGUI::delegates::MultiDelegate< Canvas * >::IDelegate
DelegateFunction< Args... > IDelegate
Definition MyGUI_Delegate.h:192
MyGUI::delegates::MultiDelegate::clear
void clear()
Definition MyGUI_Delegate.h:209
MyGUI::delegates::MultiDelegate::InvocationModificationGuard
friend class InvocationModificationGuard
Definition MyGUI_Delegate.h:311
MyGUI::delegates::MultiDelegate::operator+=
void operator+=(IDelegate *_delegate)
Definition MyGUI_Delegate.h:231
MyGUI::delegates::MultiDelegate::MultiDelegate
MultiDelegate(MultiDelegate &&) noexcept=default
MyGUI::delegates::MultiDelegate::clear
void clear(IDelegateUnlink *_unlink)
Definition MyGUI_Delegate.h:220
MyGUI::delegates::MultiDelegate::operator()
void operator()(Args... args) const
Definition MyGUI_Delegate.h:261
MyGUI::delegates
Definition MyGUI_Delegate.h:21
MyGUI
Definition MyGUI_ActionController.h:15
MyGUI::newDelegate
delegates::DelegateFunction< Args... > * newDelegate(void(*_func)(Args... args))
Definition MyGUI_Delegate.h:100
MyGUI::GetDelegateFunctionFromLambda< R(C::*)(Args...) const >::type
MyGUI::delegates::DelegateFunction< Args... > type
Definition MyGUI_Delegate.h:140
MyGUI::GetDelegateFunctionFromLambda
Definition MyGUI_Delegate.h:136