mirror of
https://github.com/TTimo/GtkRadiant.git
synced 2025-01-10 12:01:10 +00:00
d617f066bc
git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/trunk@57 8a3a26a2-13c4-0310-b231-cf6edde360e5
396 lines
9 KiB
C++
396 lines
9 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(), 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
|