343 lines
8.2 KiB
C
343 lines
8.2 KiB
C
|
|
||
|
#if !defined( INCLUDED_SIGNAL_H )
|
||
|
#define INCLUDED_SIGNAL_H
|
||
|
|
||
|
#include "isignal.h"
|
||
|
#include "memory/allocator.h"
|
||
|
#include "debugging/debugging.h"
|
||
|
#include <iterator>
|
||
|
|
||
|
namespace ListDetail
|
||
|
{
|
||
|
struct ListNodeBase
|
||
|
{
|
||
|
ListNodeBase* next;
|
||
|
ListNodeBase* prev;
|
||
|
};
|
||
|
|
||
|
inline void list_initialise( ListNodeBase& self ){
|
||
|
self.next = self.prev = &self;
|
||
|
}
|
||
|
|
||
|
inline void list_swap( ListNodeBase& self, ListNodeBase& other ){
|
||
|
ListNodeBase tmp( self );
|
||
|
if ( other.next == &other ) {
|
||
|
list_initialise( self );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
self = other;
|
||
|
self.next->prev = self.prev->next = &self;
|
||
|
}
|
||
|
if ( tmp.next == &self ) {
|
||
|
list_initialise( other );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
other = tmp;
|
||
|
other.next->prev = other.prev->next = &other;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void node_link( ListNodeBase* node, ListNodeBase* next ){
|
||
|
node->next = next;
|
||
|
node->prev = next->prev;
|
||
|
next->prev = node;
|
||
|
node->prev->next = node;
|
||
|
}
|
||
|
inline void node_unlink( ListNodeBase* node ){
|
||
|
node->prev->next = node->next;
|
||
|
node->next->prev = node->prev;
|
||
|
}
|
||
|
|
||
|
template<typename Value>
|
||
|
struct ListNode : public ListNodeBase
|
||
|
{
|
||
|
Value value;
|
||
|
|
||
|
ListNode( const Value& value ) : value( value ){
|
||
|
}
|
||
|
ListNode* getNext() const {
|
||
|
return static_cast<ListNode*>( next );
|
||
|
}
|
||
|
ListNode* getPrev() const {
|
||
|
return static_cast<ListNode*>( prev );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<typename Type>
|
||
|
class NonConstTraits
|
||
|
{
|
||
|
public:
|
||
|
typedef Type value_type;
|
||
|
typedef value_type* pointer;
|
||
|
typedef value_type& reference;
|
||
|
|
||
|
template<typename Other>
|
||
|
struct rebind
|
||
|
{
|
||
|
typedef NonConstTraits<Other> other;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
template<typename Type>
|
||
|
class ConstTraits
|
||
|
{
|
||
|
public:
|
||
|
typedef Type value_type;
|
||
|
typedef const value_type* pointer;
|
||
|
typedef const value_type& reference;
|
||
|
|
||
|
template<typename Other>
|
||
|
struct rebind
|
||
|
{
|
||
|
typedef ConstTraits<Other> other;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
template<typename Traits>
|
||
|
class ListIterator
|
||
|
{
|
||
|
public:
|
||
|
typedef std::bidirectional_iterator_tag iterator_category;
|
||
|
typedef std::ptrdiff_t difference_type;
|
||
|
typedef difference_type distance_type;
|
||
|
typedef typename Traits::value_type value_type;
|
||
|
typedef typename Traits::pointer pointer;
|
||
|
typedef typename Traits::reference reference;
|
||
|
|
||
|
private:
|
||
|
typedef ListNode<value_type> Node;
|
||
|
typedef typename Traits::template rebind<Node>::other NodeTraits;
|
||
|
typedef typename NodeTraits::pointer NodePointer;
|
||
|
typedef typename Traits::template rebind< Opaque<value_type> >::other OpaqueTraits;
|
||
|
typedef typename OpaqueTraits::pointer OpaquePointer;
|
||
|
NodePointer m_node;
|
||
|
|
||
|
void increment(){
|
||
|
m_node = m_node->getNext();
|
||
|
}
|
||
|
void decrement(){
|
||
|
m_node = m_node->getPrev();
|
||
|
}
|
||
|
|
||
|
|
||
|
public:
|
||
|
explicit ListIterator( NodePointer node ) : m_node( node ){
|
||
|
}
|
||
|
explicit ListIterator( OpaquePointer p ) : m_node( reinterpret_cast<NodePointer>( p ) ){
|
||
|
}
|
||
|
|
||
|
NodePointer node(){
|
||
|
return m_node;
|
||
|
}
|
||
|
OpaquePointer opaque() const {
|
||
|
return reinterpret_cast<OpaquePointer>( m_node );
|
||
|
}
|
||
|
|
||
|
bool operator==( const ListIterator& other ) const {
|
||
|
return m_node == other.m_node;
|
||
|
}
|
||
|
bool operator!=( const ListIterator& other ) const {
|
||
|
return !operator==( other );
|
||
|
}
|
||
|
ListIterator& operator++(){
|
||
|
increment();
|
||
|
return *this;
|
||
|
}
|
||
|
ListIterator operator++( int ){
|
||
|
ListIterator tmp = *this;
|
||
|
increment();
|
||
|
return tmp;
|
||
|
}
|
||
|
ListIterator& operator--(){
|
||
|
decrement();
|
||
|
return *this;
|
||
|
}
|
||
|
ListIterator operator--( int ){
|
||
|
ListIterator tmp = *this;
|
||
|
decrement();
|
||
|
return tmp;
|
||
|
}
|
||
|
reference operator*() const {
|
||
|
return m_node->value;
|
||
|
}
|
||
|
pointer operator->() const {
|
||
|
return &( operator*() );
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
template<typename Value, typename Allocator = DefaultAllocator<Value> >
|
||
|
class List : private Allocator
|
||
|
{
|
||
|
typedef ListDetail::ListNode<Value> Node;
|
||
|
ListDetail::ListNodeBase list;
|
||
|
typedef typename Allocator::template rebind<Node>::other NodeAllocator;
|
||
|
|
||
|
Node* newNode( const Value& value ){
|
||
|
return new ( NodeAllocator( *this ).allocate( 1 ) )Node( value );
|
||
|
}
|
||
|
void deleteNode( Node* node ){
|
||
|
node->~Node();
|
||
|
NodeAllocator( *this ).deallocate( node, 1 );
|
||
|
}
|
||
|
public:
|
||
|
typedef Value value_type;
|
||
|
typedef ListDetail::ListIterator< ListDetail::NonConstTraits<Value> > iterator;
|
||
|
typedef ListDetail::ListIterator< ListDetail::ConstTraits<Value> > const_iterator;
|
||
|
|
||
|
List(){
|
||
|
list_initialise( list );
|
||
|
}
|
||
|
explicit List( const Allocator& allocator ) : Allocator( allocator ){
|
||
|
list_initialise( list );
|
||
|
}
|
||
|
~List(){
|
||
|
for (; list.next != &list; )
|
||
|
{
|
||
|
Node* node = static_cast<Node*>( list.next );
|
||
|
list.next = list.next->next;
|
||
|
deleteNode( node );
|
||
|
}
|
||
|
}
|
||
|
iterator begin(){
|
||
|
return iterator( static_cast<Node*>( list.next ) );
|
||
|
}
|
||
|
iterator end(){
|
||
|
return iterator( static_cast<Node*>( &list ) );
|
||
|
}
|
||
|
const_iterator begin() const {
|
||
|
return const_iterator( static_cast<const Node*>( list.next ) );
|
||
|
}
|
||
|
const_iterator end() const {
|
||
|
return const_iterator( static_cast<const Node*>( &list ) );
|
||
|
}
|
||
|
void push_back( const Value& value ){
|
||
|
insert( end(), value );
|
||
|
}
|
||
|
void pop_back( const Value& value ){
|
||
|
erase( --end(), value );
|
||
|
}
|
||
|
void push_front( const Value& value ){
|
||
|
insert( begin(), value );
|
||
|
}
|
||
|
void pop_front( const Value& value ){
|
||
|
erase( begin(), value );
|
||
|
}
|
||
|
iterator insert( iterator pos, const Value& value ){
|
||
|
Node* node = newNode( value );
|
||
|
node_link( node, pos.node() );
|
||
|
return iterator( node );
|
||
|
}
|
||
|
iterator erase( iterator pos ){
|
||
|
Node* node = pos.node();
|
||
|
Node* next = node->getNext();
|
||
|
node_unlink( node );
|
||
|
deleteNode( node );
|
||
|
return iterator( next );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<typename Functor>
|
||
|
class SignalBase
|
||
|
{
|
||
|
typedef List<Functor> SignalList;
|
||
|
SignalList events;
|
||
|
|
||
|
public:
|
||
|
|
||
|
typedef Functor handler_type;
|
||
|
typedef Handle< Opaque<Functor> > handler_id_type;
|
||
|
typedef typename SignalList::iterator iterator;
|
||
|
typedef typename SignalList::const_iterator const_iterator;
|
||
|
iterator begin(){
|
||
|
return events.begin();
|
||
|
}
|
||
|
iterator end(){
|
||
|
return events.end();
|
||
|
}
|
||
|
const_iterator begin() const {
|
||
|
return events.begin();
|
||
|
}
|
||
|
const_iterator end() const {
|
||
|
return events.end();
|
||
|
}
|
||
|
handler_id_type connectFirst( const Functor& event ){
|
||
|
events.push_front( event );
|
||
|
return handler_id_type( begin().opaque() );
|
||
|
}
|
||
|
handler_id_type connectLast( const Functor& event ){
|
||
|
events.push_back( event );
|
||
|
return handler_id_type( ( --end() ).opaque() );
|
||
|
}
|
||
|
bool isConnected( handler_id_type id ){
|
||
|
for ( iterator i = begin(); i != end(); ++i )
|
||
|
{
|
||
|
if ( id.get() == i.opaque() ) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
handler_id_type connectBefore( handler_id_type id, const Functor& event ){
|
||
|
ASSERT_MESSAGE( isConnected( id ), "SignalBase::connectBefore: invalid id" );
|
||
|
return events.insert( iterator( id.get() ), event ).opaque();
|
||
|
}
|
||
|
handler_id_type connectAfter( handler_id_type id, const Functor& event ){
|
||
|
ASSERT_MESSAGE( isConnected( id ), "SignalBase::connectAfter: invalid id" );
|
||
|
return events.insert( ++iterator( id.get() ), event ).opaque();
|
||
|
}
|
||
|
void disconnect( handler_id_type id ){
|
||
|
ASSERT_MESSAGE( isConnected( id ), "SignalBase::disconnect: invalid id" );
|
||
|
events.erase( iterator( id.get() ) );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
///\brief
|
||
|
// It is safe to disconnect the signal handler currently being invoked.
|
||
|
template<typename InputIterator, typename SignalHandlerInvoke>
|
||
|
inline void invokeSignalHandlers( InputIterator first, InputIterator last, SignalHandlerInvoke invoke ){
|
||
|
while ( first != last && invoke( *first++ ) != SIGNAL_STOP_EMISSION ) ;
|
||
|
}
|
||
|
|
||
|
class Signal0 : public SignalBase<SignalHandler>
|
||
|
{
|
||
|
public:
|
||
|
void operator()() const {
|
||
|
invokeSignalHandlers( begin(), end(), FunctorInvoke<handler_type>() );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<typename FirstArgument>
|
||
|
class Signal1 : public SignalBase< SignalHandler1<FirstArgument> >
|
||
|
{
|
||
|
typedef SignalBase< SignalHandler1<FirstArgument> > Base;
|
||
|
public:
|
||
|
void operator()( FirstArgument a1 ) const {
|
||
|
invokeSignalHandlers( Base::begin(), Base::end(), FunctorInvoke<typename Base::handler_type>( a1 ) );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<typename FirstArgument, typename SecondArgument>
|
||
|
class Signal2 : public SignalBase< SignalHandler2<FirstArgument, SecondArgument> >
|
||
|
{
|
||
|
typedef SignalBase< SignalHandler2<FirstArgument, SecondArgument> > Base;
|
||
|
public:
|
||
|
void operator()( FirstArgument a1, SecondArgument a2 ) const {
|
||
|
invokeSignalHandlers( Base::begin(), Base::end(), FunctorInvoke<typename Base::handler_type>( a1, a2 ) );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<typename FirstArgument, typename SecondArgument, typename ThirdArgument>
|
||
|
class Signal3 : public SignalBase< SignalHandler3<FirstArgument, SecondArgument, ThirdArgument> >
|
||
|
{
|
||
|
typedef SignalBase< SignalHandler3<FirstArgument, SecondArgument, ThirdArgument> > Base;
|
||
|
public:
|
||
|
void operator()( FirstArgument a1, SecondArgument a2, ThirdArgument a3 ) const {
|
||
|
invokeSignalHandlers( Base::begin(), Base::end(), FunctorInvoke<typename Base::handler_type>( a1, a2, a3 ) );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#endif
|