fw4spl
Signal.hxx
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2016.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #ifndef __FWCOM_SIGNAL_HXX__
8 #define __FWCOM_SIGNAL_HXX__
9 
10 #ifndef __FWCOM_SIGNAL_HPP__
11 #error fwCom/Signal.hpp not included
12 #endif
13 
14 #include "fwCom/exception/AlreadyConnected.hpp"
15 #include "fwCom/exception/BadSlot.hpp"
16 #include "fwCom/Slot.hpp"
17 #include "fwCom/Slot.hxx"
18 #include "fwCom/SlotConnection.hpp"
19 #include "fwCom/SlotConnection.hxx"
20 #include "fwCom/util/remove_last_arg.hpp"
21 
22 #include <boost/function_types/function_arity.hpp>
23 
24 namespace fwCom
25 {
26 
27 template < typename R, typename ... A >
28 typename Signal< R (A ...) >::sptr Signal< R (A ...) >::New()
29 {
30  return std::make_shared< Signal< R (A ...) > > ();
31 }
32 
33 //-----------------------------------------------------------------------------
34 
35 template < typename R, typename ... A >
36 Connection Signal< R (A ...) >::connect( SlotBase::sptr slot )
37 {
38  return this->connect< SignatureType >(slot);
39 }
40 
41 //-----------------------------------------------------------------------------
42 
43 template < typename R, typename ... A >
44 void Signal< R (A ...) >::disconnect( SlotBase::sptr slot )
45 {
46  ::fwCore::mt::ReadToWriteLock lock(m_connectionsMutex);
47 
48  ConnectionMapType::const_iterator iter = m_connections.find(slot);
49 
50  if (iter != m_connections.end())
51  {
52  SlotConnectionBase::sptr connection ( iter->second.lock() );
53  SLM_ASSERT( "Connection has been previously destroyed", connection );
54  if (connection)
55  {
56  ::fwCore::mt::UpgradeToWriteLock writeLock(lock);
57  connection->disconnectWeakLock();
58  // m_connections.erase(slot.get()); // done in connection->disconnect
59  }
60  }
61  else
62  {
63  FW_RAISE_EXCEPTION( ::fwCom::exception::BadSlot( "No such slot connected" ) );
64  }
65 }
66 
67 //-----------------------------------------------------------------------------
68 
69 template < typename R, typename ... A >
70 void Signal< R (A ...) >::disconnectAll()
71 {
72  ::fwCore::mt::WriteLock lock(m_connectionsMutex);
73 
74  ConnectionMapType connections = m_connections;
75 
76  for( const typename ConnectionMapType::value_type &conn : connections )
77  {
78  SlotConnectionBase::sptr connection( conn.second.lock() );
79 
80  if(connection)
81  {
82  connection->disconnectWeakLock();
83  }
84  }
85 }
86 
87 //-----------------------------------------------------------------------------
88 
89 template < typename R, typename ... A >
90 void Signal< R (A ...) >::emit( A ... a ) const
91 {
92  ::fwCore::mt::ReadLock lock(m_connectionsMutex);
93  typename SlotContainerType::const_iterator iter;
94  typename SlotContainerType::const_iterator end = m_slots.end();
95  for ( iter = m_slots.begin(); iter != end; ++iter )
96  {
97  if ((*iter)->first)
98  {
99  (*iter)->second->run(a ...);
100  }
101  }
102 }
103 
104 //-----------------------------------------------------------------------------
105 
106 template < typename R, typename ... A >
107 void Signal< R (A ...) >::asyncEmit( A ... a ) const
108 {
109  ::fwCore::mt::ReadLock lock(m_connectionsMutex);
110  typename SlotContainerType::const_iterator iter;
111  typename SlotContainerType::const_iterator end = m_slots.end();
112  for ( iter = m_slots.begin(); iter != end; ++iter )
113  {
114  if ((*iter)->first)
115  {
116  (*iter)->second->asyncRun(a ...);
117  }
118  }
119 }
120 
121 //-----------------------------------------------------------------------------
122 
123 template < typename R, typename ... A >
124 template< typename FROM_F >
125 Connection Signal< R( A ... ) >::connect( SlotBase::sptr slot )
126 {
127  {
128  ::fwCore::mt::ReadLock lock(m_connectionsMutex);
129 
130  if(m_connections.find( slot ) != m_connections.end())
131  {
132  FW_RAISE_EXCEPTION( fwCom::exception::AlreadyConnected("Slot already connected") );
133  }
134  }
135 
136  typedef SlotConnection< void ( A ... ) > ConnectionType;
137  Connection connection;
138 
139  unsigned int sigArity = ::boost::function_types::function_arity< SignatureType >::value;
140  if ( sigArity == slot->arity() )
141  {
142  SlotSptr slotToConnect = std::dynamic_pointer_cast< SlotRunType >(slot);
143  if(slotToConnect)
144  {
145  ::fwCore::mt::WriteLock lock(m_connectionsMutex);
146  typename Signal< R( A ... ) >::sptr sig =
147  std::dynamic_pointer_cast < Signal< R( A ... ) > > ( this->shared_from_this() );
148  typename ConnectionType::sptr slotConnection = ConnectionType::New( sig, slotToConnect);
149  slot->m_connections.insert(slotConnection);
150  m_connections.insert( typename ConnectionMapType::value_type( slot, slotConnection ) );
151  slotConnection->connectNoLock();
152  connection = Connection(slotConnection);
153  }
154  else
155  {
156  FW_RAISE_EXCEPTION( ::fwCom::exception::BadSlot( "Incompatible slot" ) );
157  }
158  }
159  else if ( sigArity > slot->arity() )
160  {
161 
162  typedef SlotRun< FROM_F > WrappedSlotRunType;
163  typename SPTR(WrappedSlotRunType) wrappedSlot = std::dynamic_pointer_cast< WrappedSlotRunType >(slot);
164 
165  if(wrappedSlot)
166  {
167  ::fwCore::mt::WriteLock lock(m_connectionsMutex);
168  SlotSptr slotToConnect = Slot < Slot < void (A ...) > >::New(wrappedSlot);
169  typename Signal< R( A ... ) >::sptr sig =
170  std::dynamic_pointer_cast < Signal< R( A ... ) > > ( this->shared_from_this() );
171  typename ConnectionType::sptr slotConnection = ConnectionType::New( sig, slot, slotToConnect );
172  slot->m_connections.insert(slotConnection);
173  m_connections.insert( typename ConnectionMapType::value_type( slot, slotConnection ) );
174  slotConnection->connectNoLock();
175  connection = Connection(slotConnection);
176  }
177  else
178  {
179  connection = this->connect< typename ::fwCom::util::remove_last_arg< FROM_F >::type >( slot );
180  }
181 
182  }
183  else
184  {
185  FW_RAISE_EXCEPTION( ::fwCom::exception::BadSlot( "Incompatible slot" ) );
186  }
187 
188  return connection;
189 }
190 
191 //-----------------------------------------------------------------------------
192 
193 template < typename R, typename ... A >
194 Connection Signal< R( A ... ) >::getConnection( SlotBase::sptr slot, bool throws )
195 {
196  ::fwCore::mt::ReadLock lock(m_connectionsMutex);
197  Connection connection;
198 
199  ConnectionMapType::const_iterator iter = m_connections.find(slot);
200 
201  if (iter == m_connections.end() )
202  {
203  if(throws)
204  {
205  FW_RAISE_EXCEPTION( ::fwCom::exception::BadSlot( "No such slot connected" ) );
206  }
207  }
208  else
209  {
210  SlotConnectionBase::sptr slotConnection (iter->second);
211  connection = Connection( slotConnection );
212  }
213  return connection;
214 }
215 
216 //-----------------------------------------------------------------------------
217 
218 } // namespace fwCom
219 
220 #endif /* __FWCOM_SIGNAL_HXX__ */
221 
222 
#define SPTR(_cls_)
::boost::upgrade_lock< ReadWriteMutex > ReadToWriteLock
Defines an upgradable lock type for read/write mutex.
::boost::upgrade_to_unique_lock< ReadWriteMutex > UpgradeToWriteLock
Defines a write lock upgraded from ReadToWriteLock.
Namespace containing fw4spl communication tools.
Definition: DumpEditor.hpp:30
::boost::unique_lock< ReadWriteMutex > WriteLock
Defines a lock of write type for read/write mutex.
Class managing Signal-Slot connections.
Definition: Connection.hpp:17
Bad slot exception.
Definition: BadSlot.hpp:20
#define SLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:308
::boost::shared_lock< ReadWriteMutex > ReadLock
Defines a lock of read type for read/write mutex.