1 // -*- mode: c++ -*-
2 //
3 // This file is part of libyacurs.
4 // Copyright (C) 2013  Rafael Ostertag
5 //
6 // This program is free software: you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License as
8 // published by the Free Software Foundation, either version 3 of the
9 // License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program.  If not, see
18 // <http://www.gnu.org/licenses/>.
19 //
20 //
21 // $Id$
22 
23 #ifndef EVENTCONNECTOR_H
24 #define EVENTCONNECTOR_H 1
25 
26 // Can't use #ifdef HAVE_STDINT_H since that would require pulling in
27 // config.h or libyacurscfg.h which might cause undesired side
28 // effects.
29 #include <stdint.h>
30 
31 #include <cassert>
32 #include <cstdlib>
33 #include <functional>
34 #include <string>
35 #include <typeinfo>
36 
37 #include "event.h"
38 #include "yacurstypes.h"
39 
40 namespace YACURS {
41 /**
42  * @ingroup Event
43  *
44  * An Event Connector connects an event (@c EventType) to an
45  * handler (function, or member function).
46  *
47  * When connecting an event to a member function, it is expected
48  * that exactly one member function per object for a particular
49  * event is called. Connecting a particular event to several
50  * member functions of the same object result in only the last
51  * connection made taking effect (i.e. the current connection
52  * replaces any previous connections).
53  *
54  * This uniqueness is not enforced by the event connector itself,
55  * but an event connector has to provide an equality operator
56  * allowing to compare event connector for equality.
57  *
58  * See operator==() for more information about equality.
59  *
60  * @see Event
61  * @see EventQueue
62  */
63 class EventConnectorBase {
64    private:
65     /// The event type the handler is connected to.
66     EventType evt;
67 
68     /**
69      * indication whether (@c true) or not (@c false) the
70      * event handler is suspended. Suspended event handler
71      * won't be called.
72      */
73     bool _suspended;
74 
75    public:
76     /**
77      * Constructor.
78      *
79      * @param e the event type
80      * @param s whether or not the handler is suspended.
81      */
82     EventConnectorBase(const EventType e, bool s = false);
83 
84     virtual ~EventConnectorBase();
85 
86     /**
87      * The value returned by id() together with the event type has
88      * to uniquely identifiy the event connector
89      *
90      * @return value of type @c uintptr_t uniquely identifying the
91      * handler.
92      */
93     virtual uintptr_t id() const = 0;
94 
95     /**
96      * Tests two event connector for equality. It tests for
97      * equality by comparing the event type of both connectors and
98      * equality of the value returned by id().
99      *
100      * When comparing member function event connectors, the
101      * following must hold:
102      *
103      * <pre>
104      *  class base {
105      *   public:
106      *   virtual int handler(Event&);
107      *  };
108      *  class derived : public base {
109      *   public:
110      *   int handler(Event&);
111      *  };
112      *
113      *  derived d();
114      *  base* bptr=\&d;
115      *
116      *  EventConnectorBase(&d,&derived::handler) == EventConnectorBase(bptr,
117      * &base::handler);
118      * </pre>
119      *
120      * @return @c true if evt and id() are equal, @c false
121      * otherwise.
122      */
123     bool operator==(const EventConnectorBase& ec) const;
124 
125     bool operator!=(const EventConnectorBase& ec) const;
126 
127     /**
128      * Compare the event type.
129      *
130      * Compares only the event type of the given Event.
131      *
132      * @param eb reference to an Event object.
133      *
134      * @return @c true if the value of evt and eb.type() are
135      * equal, @c false otherwise.
136      */
137     bool operator==(const Event& eb) const;
138 
139     bool operator!=(const Event& eb) const;
140 
141     /**
142      * Compare the event type.
143      *
144      * Compares only the event type.
145      *
146      * @param et event type
147      *
148      * @return @c true if _evt and @c et are equal, @c false
149      * otherwise.
150      */
151     bool operator==(const EventType et) const;
152 
153     bool operator!=(const EventType et) const;
154 
155     /**
156      * Returns the event the handler is connected to.
157      *
158      * @return the EventType
159      */
160     const EventType type() const;
161 
162     /**
163      * Set the suspended state to the given value.
164      *
165      * @param s boolean value indicating whether (@c true) or not
166      * (@c false) the event handler is called upon the occurrence
167      * of the event.
168      */
169     void suspended(bool s);
170 
171     /**
172      * Query the suspended state.
173      *
174      * @return @c true if event connector is suspended, @c false
175      * otherwise.
176      */
177     bool suspended() const;
178 
179     /**
180      * Call the handler and pass the event
181      *
182      * @param e event object that caused the call.
183      *
184      * @return the value returned by the handler.
185      */
186     virtual void call(Event& e) const = 0;
187 
188     /**
189      * The EventQueue creates a local copy of the EventConnector
190      * object. This method has to return a copy of the object. The
191      * caller is responsible for freeing the memory.
192      *
193      * @return pointer to a derived EventConnectorBase object. The
194      * caller is responsible for freeing the memory.
195      */
196     virtual EventConnectorBase* clone() const = 0;
197 
198     operator const EventType() const;
199 };
200 
201 /**
202  * @ingroup Event
203  *
204  * Connect a member function to an event.
205  *
206  * The signature of the handler has to be
207  *
208  *  <code>Class::handler(Event&)</code>
209  *
210  */
211 template <class T /* Type of object called */>
212 class EventConnectorMethod1 : public EventConnectorBase {
213    public:
214     typedef void (T::*_mem_fun_t)(Event&);
215     typedef T* _obj_ptr_t;
216 
217    private:
218     /// Holds the pointer to the member function of a class of
219     /// type T
220     _mem_fun_t _func;
221     /// Holds the pointer to the object of type T
222     _obj_ptr_t _obj_ptr;
223 
224    public:
225     /**
226      * Constructs an EventConnectorMethod1 object. The handler is
227      * connected to a particular event has to have the following
228      * signature:
229      *
230      * <code>Class::handler(Event&)</code>
231      *
232      * @param e the event type to connect
233      *
234      * @param obj_ptr pointer to the object whos member function
235      * will be called.
236      *
237      * @param func the address of the member function to be
238      * called.
239      *
240      * For instance:
241      *
242      * <pre>
243      *  class A {
244      *   public:
245      *    int event_handler(Event& e);
246      *  };
247      *
248      *  A a;
249      *  EventConnector1<A> c(EVT_RESIZE, &a, &A::event_handler);
250      * </pre>
251      */
EventConnectorMethod1(const EventType e,_obj_ptr_t obj_ptr,_mem_fun_t func)252     EventConnectorMethod1(const EventType e, _obj_ptr_t obj_ptr,
253                           _mem_fun_t func)
254         : EventConnectorBase(e), _func(func), _obj_ptr(obj_ptr) {
255         assert(_func != 0);
256         assert(_obj_ptr != 0);
257     }
258 
259     /**
260      * The id returned is the pointer to the object converted to
261      * an uintptr_t.
262      *
263      * @return the id used for testing for equality with other
264      * event connectors.
265      */
id()266     uintptr_t id() const { return (uintptr_t)_obj_ptr; }
267 
268     /**
269      * The EventQueue calls this function and passes a reference
270      * to the event to it.
271      *
272      * @param e the event that caused the call.
273      *
274      * @return the value returned by the member function called,
275      * or -1 if the connector is suspended
276      */
call(Event & e)277     void call(Event& e) const {
278         assert(_obj_ptr != 0);
279         assert(_func != 0);
280 
281         if (suspended()) return;
282         (_obj_ptr->*_func)(e);
283     }
284 
285     /**
286      * Creates a copy of this object. The caller is responsible
287      * for freeing the memory.
288      *
289      * @return pointer to the newly created object.
290      */
clone()291     EventConnectorBase* clone() const {
292         return new EventConnectorMethod1<T>(*this);
293     }
294 };
295 
296 /**
297  * @ingroup Event
298  *
299  * Connect a function to an event.
300  *
301  * The signature of the function connected has to be
302  *
303  *  <code>int fct(Event&)</code>
304  *
305  * or
306  *
307  *  <code>static int Class::handler(Event&)</code>
308  */
309 class EventConnectorFunction1 : public EventConnectorBase {
310    private:
311     /// Holds the pointer to the function to be called.
312     fptr_t _func;
313 
314    public:
315     /**
316      * Create an event connector to a function.
317      *
318      * @param e the type of the event
319      *
320      * @param func the pointer to the function.
321      */
322     EventConnectorFunction1(const EventType e, fptr_t func);
323 
324     /**
325      * The id returned is the pointer to the function converted to
326      * an uintptr_t.
327      *
328      * @return the id used for testing for equality with other
329      * event connectors.
330      */
331     uintptr_t id() const;
332 
333     /**
334      * The EventQueue calls this function and passes a reference
335      * to the event to it.
336      *
337      * @param e the event that caused the call.
338      *
339      * @return the value returned by the function called,
340      * or -1 if the connector is suspended
341      */
342     void call(Event& e) const;
343 
344     /**
345      * Creates a copy of this object. The caller is responsible
346      * for freeing the memory.
347      *
348      * @return pointer to the newly created object.
349      */
350     EventConnectorBase* clone() const;
351 };
352 }  // namespace YACURS
353 
354 #endif  // EVENTCONNECTOR_H
355