fixed gcc4 compile errors
[xonotic/netradiant.git] / libs / signal / signal.h
1
2 #if !defined(INCLUDED_SIGNAL_H)
3 #define INCLUDED_SIGNAL_H
4
5 #include "isignal.h"
6 #include "memory/allocator.h"
7 #include "debugging/debugging.h"
8 #include <iterator>
9
10 namespace ListDetail
11 {
12   struct ListNodeBase
13   {
14     ListNodeBase* next;
15     ListNodeBase* prev;
16   };
17
18   inline void list_initialise(ListNodeBase& self)
19   {
20     self.next = self.prev = &self;
21   }
22
23   inline void list_swap(ListNodeBase& self, ListNodeBase& other)
24   {
25     ListNodeBase tmp(self);
26     if(other.next == &other)
27     {
28       list_initialise(self);
29     }
30     else
31     {
32       self = other;
33       self.next->prev = self.prev->next = &self;
34     }
35     if(tmp.next == &self)
36     {
37       list_initialise(other);
38     }
39     else
40     {
41       other = tmp;
42       other.next->prev = other.prev->next = &other;
43     }
44   }
45
46   inline void node_link(ListNodeBase* node, ListNodeBase* next)
47   {
48     node->next = next;
49     node->prev = next->prev;
50     next->prev = node;
51     node->prev->next = node;
52   }
53   inline void node_unlink(ListNodeBase* node)
54   {
55     node->prev->next = node->next;
56     node->next->prev = node->prev;
57   }
58
59   template<typename Value>
60   struct ListNode : public ListNodeBase
61   {
62     Value value;
63
64     ListNode(const Value& value) : value(value) 
65     {
66     }
67     ListNode* getNext() const
68     {
69       return static_cast<ListNode*>(next);
70     }
71     ListNode* getPrev() const
72     {
73       return static_cast<ListNode*>(prev);
74     }
75   };
76
77   template<typename Type>
78   class NonConstTraits
79   {
80   public:
81     typedef Type value_type;
82     typedef value_type* pointer;
83     typedef value_type& reference;
84
85     template<typename Other>
86     struct rebind
87     {
88       typedef NonConstTraits<Other> other;
89     };
90   };
91
92   template<typename Type>
93   class ConstTraits
94   {
95   public:
96     typedef Type value_type;
97     typedef const value_type* pointer;
98     typedef const value_type& reference;
99
100     template<typename Other>
101     struct rebind
102     {
103       typedef ConstTraits<Other> other;
104     };
105   };
106
107   template<typename Traits>
108   class ListIterator
109   {
110   public:
111     typedef std::forward_iterator_tag iterator_category;
112     typedef std::ptrdiff_t difference_type;
113     typedef difference_type distance_type;
114     typedef typename Traits::value_type value_type;
115     typedef typename Traits::pointer pointer;
116     typedef typename Traits::reference reference;
117
118   private:
119     typedef ListNode<value_type> Node;
120     typedef typename Traits::template rebind<Node>::other NodeTraits;
121     typedef typename NodeTraits::pointer NodePointer;
122     typedef typename Traits::template rebind< Opaque<value_type> >::other OpaqueTraits;
123     typedef typename OpaqueTraits::pointer OpaquePointer;
124     NodePointer m_node;
125
126     void increment()
127     {
128       m_node = m_node->getNext();
129     }
130     void decrement()
131     {
132       m_node = m_node->getPrev();
133     }
134
135
136  public:
137    explicit ListIterator(NodePointer node) : m_node(node)
138     {
139     }
140     explicit ListIterator(OpaquePointer p) : m_node(reinterpret_cast<NodePointer>(p))
141     {
142     }
143
144     NodePointer node()
145     {
146       return m_node;
147     }
148     OpaquePointer opaque() const
149     {
150       return reinterpret_cast<OpaquePointer>(m_node);
151     }
152
153     bool operator==(const ListIterator& other) const
154     {
155       return m_node == other.m_node;
156     }
157     bool operator!=(const ListIterator& other) const
158     {
159       return !operator==(other);
160     }
161     ListIterator& operator++()
162     {
163       increment();
164       return *this;
165     }
166     ListIterator operator++(int)
167     {
168       ListIterator tmp = *this;
169       increment();
170       return tmp;
171     }
172     ListIterator& operator--()
173     {
174       decrement();
175       return *this;
176     }
177     ListIterator operator--(int)
178     {
179       ListIterator tmp = *this;
180       decrement();
181       return tmp;
182     }
183     reference operator*() const
184     {
185       return m_node->value;
186     }
187     pointer operator->() const
188     {
189       return &(operator*());
190     }
191   };
192 }
193
194 template<typename Value, typename Allocator = DefaultAllocator<Value> >
195 class List : private Allocator
196 {
197   typedef ListDetail::ListNode<Value> Node;
198   ListDetail::ListNodeBase list;
199   typedef typename Allocator::template rebind<Node>::other NodeAllocator;
200 public:
201   typedef Value value_type;
202   typedef ListDetail::ListIterator< ListDetail::NonConstTraits<Value> > iterator;
203   typedef ListDetail::ListIterator< ListDetail::ConstTraits<Value> > const_iterator;
204
205   List()
206   {
207     list_initialise(list);
208   }
209   explicit List(const Allocator& allocator) : Allocator(allocator)
210   {
211     list_initialise(list);
212   }
213   iterator begin()
214   {
215     return iterator(static_cast<Node*>(list.next));
216   }
217   iterator end()
218   {
219     return iterator(static_cast<Node*>(&list));
220   }
221   const_iterator begin() const
222   {
223     return const_iterator(static_cast<const Node*>(list.next));
224   }
225   const_iterator end() const
226   {
227     return const_iterator(static_cast<const Node*>(&list));
228   }
229   void push_back(const Value& value)
230   {
231     insert(end(), value);
232   }
233   void pop_back(const Value& value)
234   {
235     erase(--end(), value);
236   }
237   void push_front(const Value& value)
238   {
239     insert(begin(), value);
240   }
241   void pop_front(const Value& value)
242   {
243     erase(begin(), value);
244   }
245   iterator insert(iterator pos, const Value& x)
246   {
247     Node* node = new (NodeAllocator(*this).allocate(1)) Node(x);
248     node_link(node, pos.node());
249     return iterator(node);
250   }
251   iterator erase(iterator pos)
252   {
253     Node* node = pos.node();
254     Node* next = node->getNext();
255     node_unlink(node);
256     node->~Node();
257     NodeAllocator(*this).deallocate(node, 1);
258     return iterator(next);
259   }
260 };
261
262 template<typename Functor>
263 class SignalBase
264 {
265   typedef List<Functor> SignalList;
266   SignalList events;
267
268 public:
269
270   typedef Functor handler_type;
271   typedef Handle< Opaque<Functor> > handler_id_type;
272   typedef typename SignalList::iterator iterator;
273   typedef typename SignalList::const_iterator const_iterator;
274   iterator begin()
275   {
276     return events.begin();
277   }
278   iterator end()
279   {
280     return events.end();
281   }
282   const_iterator begin() const
283   {
284     return events.begin();
285   }
286   const_iterator end() const
287   {
288     return events.end();
289   }
290   handler_id_type connectFirst(const Functor& event)
291   {
292     events.push_front(event);
293     return handler_id_type(begin().opaque());
294   }
295   handler_id_type connectLast(const Functor& event)
296   {
297     events.push_back(event);
298     return handler_id_type((--end()).opaque());
299   }
300   bool isConnected(handler_id_type id)
301   {
302     for(iterator i = begin(); i != end(); ++i)
303     {
304       if(id.get() == i.opaque())
305       {
306         return true;
307       }
308     }
309     return false;
310   }
311   handler_id_type connectBefore(handler_id_type id, const Functor& event)
312   {
313     ASSERT_MESSAGE(isConnected(id), "SignalBase::connectBefore: invalid id");
314     return events.insert(iterator(id.get()), event).opaque();
315   }
316   handler_id_type connectAfter(handler_id_type id, const Functor& event)
317   {
318     ASSERT_MESSAGE(isConnected(id), "SignalBase::connectAfter: invalid id");
319     return events.insert(++iterator(id.get()), event).opaque();
320   }
321   void disconnect(handler_id_type id)
322   {
323     ASSERT_MESSAGE(isConnected(id), "SignalBase::disconnect: invalid id");
324     events.erase(iterator(id.get()));
325   }
326 };
327
328 ///\brief
329 // It is safe to disconnect the signal handler currently being invoked.
330 template<typename InputIterator, typename SignalHandlerInvoke>
331 inline void invokeSignalHandlers(InputIterator first, InputIterator last, SignalHandlerInvoke invoke)
332 {
333   while(first != last && invoke(*first++) != SIGNAL_STOP_EMISSION);
334 }
335
336 class Signal0 : public SignalBase<SignalHandler>
337 {
338 public:
339   void operator()() const
340   {
341     invokeSignalHandlers(begin(), end(), FunctorInvoke<handler_type>());
342   }
343 };
344
345 template<typename FirstArgument>
346 class Signal1 : public SignalBase< SignalHandler1<FirstArgument> >
347 {
348   typedef SignalBase< SignalHandler1<FirstArgument> > Base;
349 public:
350   void operator()(FirstArgument a1) const
351   {
352     invokeSignalHandlers(Base::begin(), Base::end(), Functor1Invoke<typename Base::handler_type>(a1));
353   }
354 };
355
356 template<typename FirstArgument, typename SecondArgument>
357 class Signal2 : public SignalBase< SignalHandler2<FirstArgument, SecondArgument> >
358 {
359   typedef SignalBase< SignalHandler2<FirstArgument, SecondArgument> > Base;
360 public:
361   void operator()(FirstArgument a1, SecondArgument a2) const
362   {
363     invokeSignalHandlers(Base::begin(), Base::end(), Functor2Invoke<typename Base::handler_type>(a1, a2));
364   }
365 };
366
367 template<typename FirstArgument, typename SecondArgument, typename ThirdArgument>
368 class Signal3 : public SignalBase< SignalHandler3<FirstArgument, SecondArgument, ThirdArgument> >
369 {
370   typedef SignalBase< SignalHandler3<FirstArgument, SecondArgument, ThirdArgument> > Base;
371 public:
372   void operator()(FirstArgument a1, SecondArgument a2, ThirdArgument a3) const
373   {
374     invokeSignalHandlers(Base::begin(), Base::end(), Functor3Invoke<typename Base::handler_type>(a1, a2, a3));
375   }
376 };
377
378 #endif