gtkradiant/libs/signal/signal.h

379 lines
8.6 KiB
C
Raw Normal View History

#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::forward_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;
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);
}
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& x)
{
Node* node = new (NodeAllocator(*this).allocate(1)) Node(x);
node_link(node, pos.node());
return iterator(node);
}
iterator erase(iterator pos)
{
Node* node = pos.node();
Node* next = node->getNext();
node_unlink(node);
node->~Node();
NodeAllocator(*this).deallocate(node, 1);
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(), Functor1Invoke<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(), Functor2Invoke<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(), Functor3Invoke<typename Base::handler_type>(a1, a2, a3));
}
};
#endif