]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/signal/signal.h
dc187e96c41da7f8a22bb1e0839462f9471bb906
[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 class Opaque;
195
196 template<typename Value, typename Allocator = DefaultAllocator<Value> >
197 class List : private Allocator
198 {
199   typedef ListDetail::ListNode<Value> Node;
200   ListDetail::ListNodeBase list;
201   typedef typename Allocator::template rebind<Node>::other NodeAllocator;
202 public:
203   typedef Value value_type;
204   typedef ListDetail::ListIterator< ListDetail::NonConstTraits<Value> > iterator;
205   typedef ListDetail::ListIterator< ListDetail::ConstTraits<Value> > const_iterator;
206
207   List()
208   {
209     list_initialise(list);
210   }
211   explicit List(const Allocator& allocator) : Allocator(allocator)
212   {
213     list_initialise(list);
214   }
215   iterator begin()
216   {
217     return iterator(static_cast<Node*>(list.next));
218   }
219   iterator end()
220   {
221     return iterator(static_cast<Node*>(&list));
222   }
223   const_iterator begin() const
224   {
225     return const_iterator(static_cast<const Node*>(list.next));
226   }
227   const_iterator end() const
228   {
229     return const_iterator(static_cast<const Node*>(&list));
230   }
231   void push_back(const Value& value)
232   {
233     insert(end(), value);
234   }
235   void pop_back(const Value& value)
236   {
237     erase(--end(), value);
238   }
239   void push_front(const Value& value)
240   {
241     insert(begin(), value);
242   }
243   void pop_front(const Value& value)
244   {
245     erase(begin(), value);
246   }
247   iterator insert(iterator pos, const Value& x)
248   {
249     Node* node = new (NodeAllocator(*this).allocate(1)) Node(x);
250     node_link(node, pos.node());
251     return iterator(node);
252   }
253   iterator erase(iterator pos)
254   {
255     Node* node = pos.node();
256     Node* next = node->getNext();
257     node_unlink(node);
258     node->~Node();
259     NodeAllocator(*this).deallocate(node, 1);
260     return iterator(next);
261   }
262 };
263
264 template<typename Functor>
265 class SignalBase
266 {
267   typedef List<Functor> SignalList;
268   SignalList events;
269
270 public:
271
272   typedef Functor handler_type;
273   typedef Handle< Opaque<Functor> > handler_id_type;
274   typedef typename SignalList::iterator iterator;
275   typedef typename SignalList::const_iterator const_iterator;
276   iterator begin()
277   {
278     return events.begin();
279   }
280   iterator end()
281   {
282     return events.end();
283   }
284   const_iterator begin() const
285   {
286     return events.begin();
287   }
288   const_iterator end() const
289   {
290     return events.end();
291   }
292   handler_id_type connectFirst(const Functor& event)
293   {
294     events.push_front(event);
295     return handler_id_type(begin().opaque());
296   }
297   handler_id_type connectLast(const Functor& event)
298   {
299     events.push_back(event);
300     return handler_id_type((--end()).opaque());
301   }
302   bool isConnected(handler_id_type id)
303   {
304     for(iterator i = begin(); i != end(); ++i)
305     {
306       if(id.get() == i.opaque())
307       {
308         return true;
309       }
310     }
311     return false;
312   }
313   handler_id_type connectBefore(handler_id_type id, const Functor& event)
314   {
315     ASSERT_MESSAGE(isConnected(id), "SignalBase::connectBefore: invalid id");
316     return events.insert(iterator(id.get()), event).opaque();
317   }
318   handler_id_type connectAfter(handler_id_type id, const Functor& event)
319   {
320     ASSERT_MESSAGE(isConnected(id), "SignalBase::connectAfter: invalid id");
321     return events.insert(++iterator(id.get()), event).opaque();
322   }
323   void disconnect(handler_id_type id)
324   {
325     ASSERT_MESSAGE(isConnected(id), "SignalBase::disconnect: invalid id");
326     events.erase(iterator(id.get()));
327   }
328 };
329
330 ///\brief
331 // It is safe to disconnect the signal handler currently being invoked.
332 template<typename InputIterator, typename SignalHandlerInvoke>
333 inline void invokeSignalHandlers(InputIterator first, InputIterator last, SignalHandlerInvoke invoke)
334 {
335   while(first != last && invoke(*first++) != SIGNAL_STOP_EMISSION);
336 }
337
338 class Signal0 : public SignalBase<SignalHandler>
339 {
340 public:
341   void operator()() const
342   {
343     invokeSignalHandlers(begin(), end(), FunctorInvoke<typename handler_type>());
344   }
345 };
346
347 template<typename FirstArgument>
348 class Signal1 : public SignalBase< SignalHandler1<FirstArgument> >
349 {
350 public:
351   void operator()(FirstArgument a1) const
352   {
353     invokeSignalHandlers(begin(), end(), Functor1Invoke<typename handler_type>(a1));
354   }
355 };
356
357 template<typename FirstArgument, typename SecondArgument>
358 class Signal2 : public SignalBase< SignalHandler2<FirstArgument, SecondArgument> >
359 {
360 public:
361   void operator()(FirstArgument a1, SecondArgument a2) const
362   {
363     invokeSignalHandlers(begin(), end(), Functor2Invoke<typename 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 public:
371   void operator()(FirstArgument a1, SecondArgument a2, ThirdArgument a3) const
372   {
373     invokeSignalHandlers(begin(), end(), Functor3Invoke<typename handler_type>(a1, a2, a3));
374   }
375 };
376
377 #endif