More grammar work, all idl files are now parsed entirely again.
[fail.git] / src / core / failsignal.h
blob384b13aacc77f70182a5c42d13737ed58023d7f6
1 /*
2 Fail game engine
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_
22 #include <list>
23 #include <iostream>
25 namespace fail
27 // We make signal inherit from this so we can easily determine if a type is a signal using type traits.
28 class SignalBase {};
30 template< typename... Args > class FLCORE_EXPORT Signal : SignalBase
32 private:
33 struct Slot
35 virtual ~Slot() {}
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_ )... );
47 return true;
50 func_type m_pFunc;
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() );
64 if( !pObj )
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_ )... );
68 return true;
71 weak_ptr< C > m_pObj;
72 method_type m_pMtd;
75 public:
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_ )
99 if( m_bTriggering )
100 return;
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;
111 ++it;
112 m_Slots.erase( remove_it );
114 else
115 ++it;
118 m_bTriggering = false;
121 private:
122 list_type m_Slots;
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)
130 bool m_bTriggering;
134 #endif