2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * @file inter_context_delegate.h
18 * @author Lukasz Wrzosek (l.wrzosek@samsung.com)
20 * @brief This file is the header file of inter context delegate
23 #ifndef DPL_INTER_CONTEXT_DELEGATE_H_
24 #define DPL_INTER_CONTEXT_DELEGATE_H_
26 #ifndef __GXX_EXPERIMENTAL_CXX0X__ // C++11 compatibility check
27 # include <bits/c++0x_warning.h>
36 #include <dpl/event/event_support.h>
37 #include <dpl/event/thread_event_dispatcher.h>
38 #include <dpl/event/main_event_dispatcher.h>
39 #include <dpl/generic_event.h>
40 #include <dpl/foreach.h>
41 #include <dpl/noncopyable.h>
42 #include <dpl/log/wrt_log.h>
43 #include <dpl/assert.h>
44 #include <dpl/apply.h>
48 * - Created ICDelegate can be passed freely to other threads.
49 * - ICDelegate can be called just once. All following calls will be
51 * - When ICDelegateSupport is destroyed, all its ICDelegates
52 * are invalidated and safetly removed.
53 * - ICDelegate can be invalidated by call to disable method on it.
54 * - To use ICDelegate you have to do two steps:
56 * 1. Class that will be used to create delegate have to derive from templated
57 * class ICDelegateSupport<T>
59 * 2. Create instance of ICDelegate by calling
60 * makeICDelegate and passing to it pointer to method
62 * class A : ICDelegateSupport<A>
64 * void methodA(int) {}
65 * void createDelegate() {
66 * ICDelegate<int> dlg;
67 * dlg = makeICDelegate(&A::MethodA);
74 template <typename ... ArgTypesList>
78 // This Type defines whether ICDelegate should be destroyed after the call, or
79 // could be reused later.
86 namespace ICDPrivate {
87 // Base for all ICDSharedDatas. Needed for auto disabling and deleting of
89 // If ICDSharedData is disabled, delegate won't be called anymore.
90 class ICDSharedDataBase
93 typedef std::shared_ptr<ICDSharedDataBase> ICDSharedDataBasePtr;
94 typedef std::list<ICDSharedDataBasePtr> ICDSharedDataBaseList;
96 class ScopedLock : DPL::Noncopyable
99 explicit ScopedLock(ICDSharedDataBasePtr helperBase) :
100 m_scopedLock(helperBase->m_mutex)
104 std::lock_guard<std::recursive_mutex> m_scopedLock;
107 ICDSharedDataBase() : m_disabled(false)
109 virtual ~ICDSharedDataBase()
112 bool isDisabled() const
116 virtual void disable()
121 void setIterator(ICDSharedDataBaseList::iterator pos)
126 ICDSharedDataBaseList::iterator getIterator() const
133 std::recursive_mutex m_mutex;
134 ICDSharedDataBaseList::iterator m_position;
137 // Pure Event to remove ICDSharedData.
138 class DeleteICDSharedDataBaseEventCall : public DPL::Event::AbstractEventCall
141 DeleteICDSharedDataBaseEventCall(
142 ICDSharedDataBase::ICDSharedDataBasePtr helperBase) :
143 m_helperBase(helperBase)
147 m_helperBase.reset();
151 ICDSharedDataBase::ICDSharedDataBasePtr m_helperBase;
154 class ICDelegateSupportInterface
157 virtual ~ICDelegateSupportInterface()
159 virtual void unregisterICDSharedData(
160 ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr helper) = 0;
161 virtual void registerICDSharedData(
162 ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr helper) = 0;
165 template <typename ... ArgTypesList>
166 friend class DPL::Event::ICDelegate;
170 template<typename ThisType, typename ... ArgTypesList>
171 std::function<void (ArgTypesList ...)>
172 makeDelegate(ThisType* This,
173 void (ThisType::*Func)(ArgTypesList ...))
175 return DPL::Bind(Func, This);
178 // ICDelegate class represents delegate that can be called from
179 // any context (thread). The actual calling context (thread) is allways the same
180 // as the context in which it was created.
181 template <typename ... ArgTypesList>
187 ICDelegate(ICDPrivate::ICDelegateSupportInterface* base,
188 std::function<void (ArgTypesList ...)> outerDelegate,
191 ICDSharedData* hlp = new ICDSharedData(base, outerDelegate, reuse);
195 // Calling operator will pass all args passed to it to correct context and
196 // will call apropriate method that was registered with.
197 void operator()(ArgTypesList ... args)
200 ICDPrivate::ICDSharedDataBase::ScopedLock lock(
201 std::static_pointer_cast<ICDPrivate::ICDSharedDataBase>(m_helper));
202 m_helper->CallDelegate(args ...);
205 //Disable delegate (it won't be called anymore)
209 ICDPrivate::ICDSharedDataBase::ScopedLock lock(
210 std::static_pointer_cast<ICDPrivate::ICDSharedDataBase>(m_helper));
215 ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr
216 getRelatedICDSharedData() const
218 return std::static_pointer_cast<ICDPrivate::ICDSharedDataBase>(m_helper);
222 template<typename ThisType>
223 friend class ICDelegateSupport;
225 typedef std::shared_ptr<ICDSharedData> ICDSharedDataPtr;
229 PrivateEvent(ICDSharedDataPtr a_helper,
230 ArgTypesList ... arguments) :
232 args(std::make_tuple(arguments ...))
235 ICDSharedDataPtr helper;
236 std::tuple<ArgTypesList ...> args;
239 typedef std::function<void (const PrivateEvent&)>
240 ICDSharedDataDelegateType;
241 class ICDSharedData : private DPL::Event::EventSupport<PrivateEvent>,
242 public std::enable_shared_from_this<ICDSharedData>,
243 public ICDPrivate::ICDSharedDataBase
247 ICDPrivate::ICDelegateSupportInterface *base,
248 std::function<void (ArgTypesList ...)> outerDelegate,
251 m_outerDelegate(outerDelegate),
255 // lock is not needed: this object is not shared at that moment
257 DPL::Event::makeDelegate(this,
258 &ICDSharedData::delegateForwarder);
259 EventSupport<PrivateEvent>::AddListener(m_subDelegate);
262 void CallDelegate(ArgTypesList ... args)
264 ICDPrivate::ICDSharedDataBase::ScopedLock lock(
265 std::static_pointer_cast<ICDPrivate::ICDSharedDataBase>(
266 this->shared_from_this()));
268 EmitEvent(PrivateEvent(this->shared_from_this(),
273 virtual void disable()
275 ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr ptr(
276 std::static_pointer_cast<ICDSharedDataBase>(
277 this->shared_from_this()));
278 ICDPrivate::ICDSharedDataBase::ScopedLock lock(ptr);
280 ICDPrivate::ICDSharedDataBase::disable();
281 EventSupport<PrivateEvent>::RemoveListener(m_subDelegate);
282 m_base->unregisterICDSharedData(ptr);
287 friend class std::shared_ptr<ICDSharedData>;
288 ICDSharedDataDelegateType m_subDelegate;
289 ICDPrivate::ICDelegateSupportInterface* m_base;
290 std::function<void (ArgTypesList ...)> m_outerDelegate;
293 void delegateForwarder(const PrivateEvent& event)
295 ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr ptr(
296 std::static_pointer_cast<ICDSharedDataBase>(event.helper));
297 ICDPrivate::ICDSharedDataBase::ScopedLock lock(ptr);
299 Assert(m_outerDelegate);
300 if (ptr->isDisabled()) {
301 WrtLogD("ICDSharedData has been disabled - call is ignored");
303 DPL::Apply(m_outerDelegate, event.args);
305 if (m_reuse == ICD::Reuse::Yes) {
310 deleteICDSharedDataBase(ptr);
315 // Schedules helper removal.
316 static void deleteICDSharedDataBase(
317 ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr helper)
319 using namespace ICDPrivate;
320 ICDSharedDataBase::ScopedLock lock(helper);
321 DeleteICDSharedDataBaseEventCall* event =
322 new DeleteICDSharedDataBaseEventCall(helper);
323 if (DPL::Thread::GetCurrentThread() == NULL) {
324 DPL::Event::GetMainEventDispatcherInstance().AddEventCall(event);
326 DPL::Event::ThreadEventDispatcher dispatcher;
327 dispatcher.SetThread(DPL::Thread::GetCurrentThread());
328 dispatcher.AddEventCall(event);
332 ICDSharedDataPtr m_helper;
335 template <typename ThisType>
336 class ICDelegateSupport : public ICDPrivate::ICDelegateSupportInterface
339 template<typename ... ArgTypesList>
340 ICDelegate<ArgTypesList ...> makeICDelegate(
341 void (ThisType::*Func)(ArgTypesList ...),
342 ICD::Reuse reuse = ICD::Reuse::No)
344 ThisType* This = static_cast<ThisType*>(this);
345 ICDelegate<ArgTypesList ...> icdelegate(
347 makeDelegate(This, Func),
349 this->registerICDSharedData(icdelegate.getRelatedICDSharedData());
358 ICDPrivate::ICDSharedDataBase::ICDSharedDataBaseList list =
360 FOREACH(helper, list) {
361 ICDPrivate::ICDSharedDataBase::ScopedLock lock(
362 std::static_pointer_cast<ICDPrivate::ICDSharedDataBase>(*helper));
363 (*helper)->disable();
365 m_ICDSharedDatas.clear();
369 virtual void unregisterICDSharedData(
370 ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr helper)
372 m_ICDSharedDatas.erase(helper->getIterator());
375 virtual void registerICDSharedData(
376 ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr helper)
379 m_ICDSharedDatas.insert(m_ICDSharedDatas.begin(),
384 ICDPrivate::ICDSharedDataBase::ICDSharedDataBaseList m_ICDSharedDatas;
389 #endif // __GXX_EXPERIMENTAL_CXX0X__
391 #endif //DPL_INTER_CONTEXT_DELEGATE_H_