Last active
June 29, 2017 22:44
-
-
Save redrabbit/1958871 to your computer and use it in GitHub Desktop.
Generic C++ notification dispatcher with boost::signal2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <map> | |
#include <queue> | |
#include <typeinfo> | |
#include <iostream> | |
#include <boost/signals2/signal.hpp> | |
#include <boost/type_traits/is_base_of.hpp> | |
class notification_interface | |
{ | |
public: | |
virtual void trigger( boost::signals2::signal_base* ) = 0; | |
}; | |
template< typename signature_t > | |
class abstract_notification : public notification_interface | |
{ | |
public: | |
typedef signature_t callback; | |
protected: | |
virtual void notify( boost::signals2::signal< callback >& signal ) = 0; | |
private: | |
void trigger( boost::signals2::signal_base* base_signal ) | |
{ | |
typedef boost::signals2::signal< signature_t > signal_t; | |
signal_t* signal = dynamic_cast< signal_t* >( base_signal ); | |
if( !signal ) | |
{ | |
throw; // bad dynamic cast | |
} | |
notify( *signal ); | |
} | |
}; | |
class foo_notification : public abstract_notification< void ( int ) > | |
{ | |
public: | |
foo_notification( int foo ) : m_foo( foo ) { } | |
protected: | |
virtual void notify( boost::signals2::signal< callback >& signal ) | |
{ | |
signal( m_foo ); | |
} | |
private: | |
int m_foo; | |
}; | |
class bar_notification : public foo_notification | |
{ | |
public: | |
bar_notification( ) : foo_notification( 0 ) { } | |
protected: | |
virtual void notify( boost::signals2::signal< callback >& signal ) | |
{ | |
signal( 12 ); | |
} | |
}; | |
class notification_manager | |
{ | |
public: | |
virtual ~notification_manager( ) | |
{ | |
// delete registered signals | |
} | |
template< typename notification_t > | |
boost::signals2::connection register_callback( const boost::function< typename notification_t::callback >& callback ) | |
{ | |
if( !boost::is_base_of< notification_interface, notification_t >::value ) | |
{ | |
throw; // template parameter is not a notification type | |
} | |
typedef boost::signals2::signal< typename notification_t::callback > signal_t; | |
const std::string type_name = typeid( notification_t ).name( ); | |
signal_t* signal = 0; | |
if( m_signals.find( type_name ) != m_signals.end( ) ) | |
{ | |
signal = dynamic_cast< signal_t* >( m_signals[ type_name ] ); | |
} | |
else | |
{ | |
signal = new signal_t( ); | |
m_signals[ type_name ] = signal; | |
} | |
return signal->connect( callback ); | |
} | |
void dispatch( notification_interface* notification ) | |
{ | |
m_queue.push( notification ); | |
} | |
void poll( ) | |
{ | |
while( !m_queue.empty( ) ) | |
{ | |
notification_interface* notification = m_queue.front( ); | |
std::map< std::string, boost::signals2::signal_base* >::const_iterator iter; | |
iter = m_signals.find( typeid( *notification ).name( ) ); | |
if( iter != m_signals.end( ) ) | |
{ | |
notification->trigger( iter->second ); | |
} | |
m_queue.pop( ); | |
delete notification; | |
} | |
} | |
private: | |
std::map< std::string, boost::signals2::signal_base* > m_signals; | |
std::queue< notification_interface* > m_queue; | |
}; | |
void foo_callback( int foo ) | |
{ | |
std::cout << "foo: " << foo << std::endl; | |
} | |
void bar_callback( int bar ) | |
{ | |
std::cout << "bar: " << bar << std::endl; | |
} | |
int main( ) | |
{ | |
notification_manager man; | |
man.register_callback< bar_notification >( bar_callback ); | |
man.register_callback< foo_notification >( foo_callback ); | |
man.dispatch( new bar_notification ); | |
man.dispatch( new bar_notification ); | |
man.dispatch( new foo_notification( 42 ) ); | |
man.poll( ); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment