3 Copyright 2007 Antoine Chavasse <a.chavasse@gmail.com>
5 This file is part of Fail.
7 Fail is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 3
9 as published by the Free Software Foundation.
11 Fail is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #ifndef FAIL_FAILSIGNAL_H_
20 #define FAIL_FAILSIGNAL_H_
27 // We make signal inherit from this so we can easily determine if a type is a signal using type traits.
30 template< typename
... Args
> class FLCORE_EXPORT Signal
: SignalBase
36 virtual bool operator()( Args
&&... args_
) = 0;
39 struct FuncSlot
: public Slot
41 typedef void ( * func_type
)( Args
&&... );
42 FuncSlot( func_type pFunc_
) : m_pFunc( pFunc_
) {}
44 virtual bool operator()( Args
&&... args_
)
46 m_pFunc( forward
< Args
>( args_
)... );
53 template< class C
> struct MethodSlot
: public Slot
55 // TODO: If I define Args as r-value reference, then overload resolution on the connect method fails.
56 // No idea if it's not supposed to work or if it might be a gcc bug.
57 typedef void ( C::* method_type
)( Args
... );
58 MethodSlot( shared_ptr
< C
> pObj_
, method_type pMtd_
) : m_pObj( pObj_
), m_pMtd( pMtd_
) {}
60 virtual bool operator()( Args
&&... args_
)
62 // Lock the weak pointer by copying it into a shared_ptr
63 shared_ptr
< C
> pObj( m_pObj
.lock() );
65 return false; // The object is gone, we return false to tell the signal to remove that slot.
67 ( pObj
.get()->*m_pMtd
)( forward
< Args
>( args_
)... );
76 Signal() : m_bTriggering( false ) {}
78 typedef std::list
< Slot
* > list_type
;
79 typedef typename
list_type::iterator slot_handle
;
81 slot_handle
connect( typename
FuncSlot::func_type pFunc_
)
83 return m_Slots
.insert( m_Slots
.end(), new FuncSlot( pFunc_
) );
86 template< class C
> slot_handle
connect( shared_ptr
< C
> pObj_
,
87 typename MethodSlot
< C
>::method_type pMethod_
)
89 return m_Slots
.insert( m_Slots
.end(), new MethodSlot
< C
>( pObj_
, pMethod_
) );
92 void disconnect( slot_handle
& Handle
)
94 m_Slots
.erase( Handle
);
97 void operator()( Args
&&... args_
)
102 m_bTriggering
= true;
104 typename
list_type::iterator it
= m_Slots
.begin();
106 while( it
!= m_Slots
.end() )
108 if( !( **it
)( forward
< Args
>( args_
)... ) )
110 typename
list_type::iterator remove_it
= it
;
112 m_Slots
.erase( remove_it
);
118 m_bTriggering
= false;
124 // This is to avoid cyclic notification loops.
125 // TODO: add a mutex - so if the same thread tries to fire this same signal
126 // again while as a result of triggering it it will ignore it,
127 // whereas when another thread wants to trigger it it will wait
128 // (we don't want another thread to ignore the signal just because it
129 // happens to try to fire it at the same time as another thread)