worldspawn/libs/signal/signal.h
2020-11-17 12:16:16 +01:00

342 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