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>
30 #include <dpl/event/event_support.h>
31 #include <dpl/event/thread_event_dispatcher.h>
32 #include <dpl/event/main_event_dispatcher.h>
33 #include <dpl/fast_delegate.h>
34 #include <dpl/shared_ptr.h>
35 #include <dpl/enable_shared_from_this.h>
36 #include <dpl/generic_event.h>
37 #include <dpl/foreach.h>
38 #include <dpl/recursive_mutex.h>
39 #include <dpl/mutex.h>
40 #include <dpl/noncopyable.h>
41 #include <dpl/log/log.h>
42 #include <dpl/assert.h>
43 #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);
75 template <typename ... ArgTypesList>
79 // This Type defines whether ICDelegate should be destroyed after the call, or
80 // could be reused later.
81 enum class Reuse{ Yes, No };
84 namespace ICDPrivate {
85 // Base for all ICDSharedDatas. Needed for auto disabling and deleting of
87 // If ICDSharedData is disabled, delegate won't be called anymore.
88 class ICDSharedDataBase
91 typedef DPL::SharedPtr<ICDSharedDataBase> ICDSharedDataBasePtr;
92 typedef std::list<ICDSharedDataBasePtr> ICDSharedDataBaseList;
94 class ScopedLock : DPL::Noncopyable
97 explicit ScopedLock(ICDSharedDataBasePtr helperBase) :
98 m_scopedLock(&helperBase->m_mutex)
103 DPL::RecursiveMutex::ScopedLock m_scopedLock;
106 ICDSharedDataBase() : m_disabled(false)
109 virtual ~ICDSharedDataBase()
113 bool isDisabled() const
117 virtual void disable()
122 void setIterator(ICDSharedDataBaseList::iterator pos)
127 ICDSharedDataBaseList::iterator getIterator() const
134 DPL::RecursiveMutex m_mutex;
135 ICDSharedDataBaseList::iterator m_position;
138 // Pure Event to remove ICDSharedData.
139 class DeleteICDSharedDataBaseEventCall : public DPL::Event::AbstractEventCall
142 DeleteICDSharedDataBaseEventCall(
143 ICDSharedDataBase::ICDSharedDataBasePtr helperBase) :
144 m_helperBase(helperBase)
149 m_helperBase.Reset();
153 ICDSharedDataBase::ICDSharedDataBasePtr m_helperBase;
157 class ICDelegateSupportInterface
160 virtual ~ICDelegateSupportInterface()
163 virtual void unregisterICDSharedData(
164 ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr helper) = 0;
165 virtual void registerICDSharedData(
166 ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr helper) = 0;
168 template <typename ... ArgTypesList>
169 friend class DPL::Event::ICDelegate;
173 // Better makeDelegate then DPL::MakeDelegate
174 template<typename ThisType, typename ... ArgTypesList>
175 FastDelegate<void (ArgTypesList ...)>
176 makeDelegate(ThisType* This,
177 void (ThisType::*Func)(ArgTypesList ...))
179 return FastDelegate<void (ArgTypesList ...)>(This, Func);
182 // ICDelegate class represents delegate that can be called from
183 // any context (thread). The actual calling context (thread) is allways the same
184 // as the context in which it was created.
185 template <typename ... ArgTypesList>
192 ICDelegate(ICDPrivate::ICDelegateSupportInterface* base,
193 DPL::FastDelegate<void (ArgTypesList ...)> outerDelegate,
196 ICDSharedData* hlp = new ICDSharedData(base, outerDelegate, reuse);
200 // Calling operator will pass all args passed to it to correct context and
201 // will call apropriate method that was registered with.
202 void operator()(ArgTypesList ... args)
205 ICDPrivate::ICDSharedDataBase::ScopedLock lock(
206 DPL::StaticPointerCast<ICDPrivate::ICDSharedDataBase>(m_helper));
207 m_helper->CallDelegate(args ...);
210 //Disable delegate (it won't be called anymore)
214 ICDPrivate::ICDSharedDataBase::ScopedLock lock(
215 DPL::StaticPointerCast<ICDPrivate::ICDSharedDataBase>(m_helper));
220 ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr
221 getRelatedICDSharedData() const
223 return DPL::StaticPointerCast<ICDPrivate::ICDSharedDataBase>(m_helper);
227 template<typename ThisType>
228 friend class ICDelegateSupport;
230 typedef DPL::SharedPtr<ICDSharedData> ICDSharedDataPtr;
234 PrivateEvent(ICDSharedDataPtr a_helper,
235 ArgTypesList ... arguments) :
237 args(std::make_tuple(arguments ...))
241 ICDSharedDataPtr helper;
242 std::tuple<ArgTypesList ...> args;
245 typedef DPL::FastDelegate<void (const PrivateEvent&)>
246 ICDSharedDataDelegateType;
247 class ICDSharedData : private DPL::Event::EventSupport<PrivateEvent>,
248 private DPL::EnableSharedFromThis<ICDSharedData>,
249 public ICDPrivate::ICDSharedDataBase
253 ICDPrivate::ICDelegateSupportInterface *base,
254 DPL::FastDelegate<void (ArgTypesList ...)> outerDelegate,
257 m_outerDelegate(outerDelegate),
261 // lock is not needed: this object is not shared at that moment
263 DPL::Event::makeDelegate(this,
264 &ICDSharedData::delegateForwarder);
265 EventSupport<PrivateEvent>::AddListener(m_subDelegate);
268 void CallDelegate(ArgTypesList ... args)
270 ICDPrivate::ICDSharedDataBase::ScopedLock lock(
271 DPL::StaticPointerCast<ICDPrivate::ICDSharedDataBase>(
272 this->SharedFromThis()));
274 EmitEvent(PrivateEvent(this->SharedFromThis(),
279 virtual void disable()
281 ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr ptr(
282 DPL::StaticPointerCast<ICDSharedDataBase>(
283 this->SharedFromThis()));
284 ICDPrivate::ICDSharedDataBase::ScopedLock lock(ptr);
286 ICDPrivate::ICDSharedDataBase::disable();
287 EventSupport<PrivateEvent>::RemoveListener(m_subDelegate);
288 m_base->unregisterICDSharedData(ptr);
293 friend class DPL::SharedPtr<ICDSharedData>;
294 ICDSharedDataDelegateType m_subDelegate;
295 ICDPrivate::ICDelegateSupportInterface* m_base;
296 DPL::FastDelegate<void (ArgTypesList ...)> m_outerDelegate;
299 void delegateForwarder(const PrivateEvent& event)
301 ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr ptr(
302 DPL::StaticPointerCast<ICDSharedDataBase>(event.helper));
303 ICDPrivate::ICDSharedDataBase::ScopedLock lock(ptr);
305 Assert(!m_outerDelegate.empty());
306 if (ptr->isDisabled()) {
307 LogPedantic("ICDSharedData has been disabled - call is ignored");
309 DPL::Apply(m_outerDelegate, event.args);
311 if(m_reuse == ICD::Reuse::Yes)
315 deleteICDSharedDataBase(ptr);
320 // Schedules helper removal.
321 static void deleteICDSharedDataBase(ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr helper)
323 using namespace ICDPrivate;
324 ICDSharedDataBase::ScopedLock lock(helper);
325 DeleteICDSharedDataBaseEventCall* event =
326 new DeleteICDSharedDataBaseEventCall(helper);
327 if (DPL::Thread::GetCurrentThread() == NULL) {
328 DPL::Event::GetMainEventDispatcherInstance().AddEventCall(event);
330 DPL::Event::ThreadEventDispatcher dispatcher;
331 dispatcher.SetThread(DPL::Thread::GetCurrentThread());
332 dispatcher.AddEventCall(event);
336 ICDSharedDataPtr m_helper;
339 template <typename ThisType>
340 class ICDelegateSupport : public ICDPrivate::ICDelegateSupportInterface
343 template<typename ... ArgTypesList>
344 ICDelegate<ArgTypesList ...> makeICDelegate(
345 void (ThisType::*Func)(ArgTypesList ...),
346 ICD::Reuse reuse = ICD::Reuse::No)
348 ThisType* This = static_cast<ThisType*>(this);
349 ICDelegate<ArgTypesList ...> icdelegate(
351 makeDelegate(This, Func),
353 this->registerICDSharedData(icdelegate.getRelatedICDSharedData());
363 ICDPrivate::ICDSharedDataBase::ICDSharedDataBaseList list =
365 FOREACH(helper, list) {
366 ICDPrivate::ICDSharedDataBase::ScopedLock lock(
367 DPL::StaticPointerCast<ICDPrivate::ICDSharedDataBase>(*helper));
368 (*helper)->disable();
370 m_ICDSharedDatas.clear();
374 virtual void unregisterICDSharedData(
375 ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr helper)
377 m_ICDSharedDatas.erase(helper->getIterator());
380 virtual void registerICDSharedData(
381 ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr helper)
384 m_ICDSharedDatas.insert(m_ICDSharedDatas.begin(),
389 ICDPrivate::ICDSharedDataBase::ICDSharedDataBaseList m_ICDSharedDatas;
395 #endif // __GXX_EXPERIMENTAL_CXX0X__
397 #endif //DPL_INTER_CONTEXT_DELEGATE_H_