Tulip  5.6.3
Large graphs analysis and drawing
Observable.h
1 /*
2  *
3  * This file is part of Tulip (http://tulip.labri.fr)
4  *
5  * Authors: David Auber and the Tulip development Team
6  * from LaBRI, University of Bordeaux
7  *
8  * Tulip is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation, either version 3
11  * of the License, or (at your option) any later version.
12  *
13  * Tulip is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  * See the GNU General Public License for more details.
17  *
18  */
19 
20 #ifndef OBSERVABLE_H
21 #define OBSERVABLE_H
22 
23 #include <vector>
24 
25 #include <tulip/tulipconf.h>
26 #include <tulip/Iterator.h>
27 #include <tulip/Node.h>
28 
29 namespace tlp {
30 class VectorGraph;
31 class Observable;
32 //=======================================
33 /**
34  * @ingroup Observation
35  * @brief Event is the base class for all events used in the Observation mechanism.
36  *
37  * An Event is characterized by its type. The base Event class only carries information as to the
38  *type of event, nothing specific.
39  *
40  * Event::TLP_DELETE : send directly to all Observers/Listeners, not affected by
41  *Observable::holdObservers().
42  * Event::TLP_MODIFICATION : sent to all Observers/Listeners. MODIFICATION are first sent to
43  *Observers
44  *and then to Listeners.
45  * Event::TLP_INFORMATION : sent only to Listeners.
46  * Event::TLP_INVALID : never sent, used internally for delaying events.
47  *
48  * @see Listener
49  * @see Observer
50  * @see Observable
51  **/
52 class TLP_SCOPE Event {
53  friend class Observable;
54  friend class Graph;
55  friend class PropertyInterface;
56 
57 public:
58  enum EventType { TLP_DELETE = 0, TLP_MODIFICATION, TLP_INFORMATION, TLP_INVALID };
59  virtual ~Event();
60  Observable *sender() const;
61  Event(const Observable &sender, EventType type);
62  EventType type() const {
63  return _type;
64  }
65 
66 private:
67  Event() {}
68  tlp::node _sender;
69  EventType _type;
70 };
71 
72 /**
73  * @ingroup Observation
74  * @brief The Observable class is the base of Tulip's observation system.
75  *
76  * Each class that wishes to send or receive notifications needs to inherit from Observable.
77  *
78  * Tulip has two separate mechanisms of observation, Observers and Listeners.
79  * These two mechanisms work through the same class, the difference lies
80  * in the way an Observer or a Listener is attached to the object whose events
81  * it will receive.
82  *
83  * The Listener is closer to the original pattern, where events are sent directly to the recipient.
84  * The Observer is a twist for performance purposes, it can receive the events in a delayed fashion,
85  *and cannot know if the event was just sent or was delayed.
86  *
87  * The purpose of this twist is to allow algorithms that perform a high number of modifications
88  *(e.g. creating a grid to route edges,
89  * creating multiple subgraphs with metrics or layouts) to run smoothly without overcrowding the
90  *event queue.
91  * As events are sent for every graph modification (e.g. adding a node, deleting a node, setting a
92  *value on a node), the sheer quantity of events sent by these
93  * algorithms would cause a big performance hit.
94  *
95  * This can be avoided by using Observable::holdObservers().
96  * This holds all events in a queue and only sends them when Observable::unholdObservers() is
97  *called.
98  *
99  * The only exception to this mechanism is the Event::DELETE kind of event, that is never held back.
100  * Think of it as an unmaskable POSIX signal; whatever the connection to the object and the state of
101  *holdObserver, this event will get through.
102  * This is used to prevent crashes in the case where and object is listened or observed and is
103  *deleted, as it is likely the recipient
104  * keeps a pointer to the now deleted object.
105  *
106  * The Listener however is not affected by the use of Observable::holdObservers() and
107  *Observable::unholdObservers().
108  *
109  * The observable Observers and Listeners are internally store in a Graph structure, allowing to
110  *easily visualize their connections.
111  * This eases debugging of Observation-related bugs.
112  *
113  * Events are always sent to Listeners first, and then to Observers, even when there is no hold.
114  *
115  * If you wish to receive events, you must inherit from Observable, and implement at least one of
116  *the two virtual functions below.
117  *
118  * If you need to receive events without delay, you will be a Listener, and need to implement
119  *treatEvent(const Event &message).
120  * You will attach to the object you wish to receive events from using addListener().
121  *
122  * If you can receive events after a delay, you will be an Observer, and need to implement
123  *treatEvents(const std::vector<Event> &events).
124  * You will attach to the object you wish to receive events from using addObserver().
125  *
126  **/
127 class TLP_SCOPE Observable {
128  friend class Event;
129 
130 public:
131  /**
132  * @brief Holds back all events until Observable::unholdObservers() is called.
133  *
134  * Listeners are not affected by this function.
135  * Once this function is called, all events heading to an Observer will be held, except TLP_DELETE
136  * events.
137  * The events are stored in a queue, and will be sent once Observable::unholdObservers() is
138  * called.
139  *
140  * It is possible to nest calls to Observable::holdObservers() and Observable::unholdObservers(),
141  * and in this case the events will only be sent when there
142  * have been as many calls to Observable::unholdObservers() as to Observable::holdObservers().
143  *
144  * It is possible to check whether the events are being help by checking the
145  * Observable::observersHoldCounter() function.
146  *
147  * @see unholdObservers
148  * @see observersHoldCounter
149  */
150  static void holdObservers();
151  /**
152  * @brief Sends all held events to the Observers.
153  *
154  * Listeners are not affected by this function.
155  *
156  * In debug mode, if the hold counter is less than one when calling this function, an
157  * ObservableException will be raised.
158  *
159  * @see holdObservers
160  * @see observersHoldCounter
161  */
162  static void unholdObservers();
163 
164  /**
165  * @brief observersHoldCounter gives the number of times holdObservers() has been called without a
166  * matching unholdObservers() call.
167  * @return the number of times holdObservers() has been called without a matching
168  * unholdObservers() call.
169  */
170  static unsigned int observersHoldCounter() {
171  return _oHoldCounter;
172  }
173 
174  /**
175  * @brief disable the whole event notification mechanism
176  * Until a call to enableEventNotification(),
177  * all sent events will be lost,
178  * except TLP_DELETE events which are synchronously processed,
179  * in order to void dangling pointers.
180  * @warning this function is a first step to allow parallel
181  * computation (of Tulip properties, for example). Use it at your
182  * own risk and avoid the sent of TLP_DELETE events whose management
183  * is not thread safe.
184  */
185  inline static void disableEventNotification() {
186  _oDisabled = true;
187  }
188 
189  /**
190  * @brief re-enable the whole event notification mechanism
191  * All events sent since a previous call to enableEventNotification(),
192  * are definitively lost.
193  */
194  inline static void enableEventNotification() {
195  _oDisabled = false;
196  }
197 
198  /**
199  * @brief Adds an Observer to this object.
200  *
201  * The observer will receive events sent by this object, if there is no hold applied.
202  * @param observer The object that will receive events.
203  */
204  void addObserver(Observable *const observer) const;
205 
206  /**
207  * @brief Adds an Observer to this object.
208  *
209  * The observer will receive events sent by this object, if there is no hold applied.
210  * @param observer The object that will receive events.
211  */
212  void addObserver(Observable &observer) const {
213  addObserver(&observer);
214  }
215 
216  /**
217  * @brief Adds a Listener to this object.
218  *
219  * The Listener will receive events regardless of the state of holdObservers() and
220  * unholdObservers().
221  * @param listener The object that will receive events.
222  */
223  void addListener(Observable *const listener) const;
224 
225  /**
226  * @brief Adds a Listener to this object.
227  *
228  * The Listener will receive events regardless of the state of holdObservers() and
229  * unholdObservers().
230  * @param listener The object that will receive events.
231  */
232  inline void addListener(Observable &listener) const {
233  addListener(&listener);
234  }
235 
236  /**
237  * @brief Removes an observer from this object.
238  *
239  * The observer will no longer receive events from this object.
240  * @param observer The observer to remove from this object.
241  */
242  void removeObserver(Observable *const observer) const;
243 
244  /**
245  * @brief Removes an observer from this object.
246  *
247  * The observer will no longer receive events from this object.
248  * @param observer The observer to remove from this object.
249  */
250  inline void removeObserver(Observable &observer) const {
251  removeObserver(&observer);
252  }
253 
254  /**
255  * @brief Removes a listener from this object.
256  *
257  * The listener will no longer receive events from this object.
258  * @param listener The listener to remove from this object.
259  */
260  void removeListener(Observable *const listener) const;
261 
262  /**
263  * @brief Removes a listener from this object.
264  *
265  * The listener will no longer receive events from this object.
266  * @param listener The listener to remove from this object.
267  */
268  inline void removeListener(Observable &listener) const {
269  removeListener(&listener);
270  }
271 
272  /**
273  * @brief gets the number of sent events.
274  * @return the number of sent events (0 when compiling with -DNDEBUG).
275  */
276  unsigned int getSent() const;
277 
278  /**
279  * @brief get the number of received events.
280  * @return the number of received events (0 when compiling with -DNDEBUG).
281  */
282  unsigned int getReceived() const;
283 
284  /**
285  * @brief gets the number of observers attached to this object.
286  * @return the number of observers attached to this object.
287  */
288  unsigned int countObservers() const;
289 
290  /**
291  * @brief gets the number of listeners attached to this object.
292  * @return the number of listeners attached to this object.
293  */
294  unsigned int countListeners() const;
295 
296 public:
297  /**
298  * @brief internal function for debugging purpose
299  * If there is no hold currently applied, or no update ongoing, always returns true.
300  * Checks if the object represented by the node has been deleted.
301  * @param n The node to check for life signs.
302  * @return Whether the node is dead.
303  **/
304  static bool isAlive(tlp::node n);
305 
306  /**
307  * @brief internal function for debugging purpose
308  * If called during an update, it is possible the pointed object has been deleted.
309  * use isAlive() to check for this and avoid a crash.
310  * @param n The node representing the object to retrieve.
311  * @return The object represented by the node.
312  **/
313  static Observable *getObject(tlp::node n);
314 
315  /**
316  * @brief internal function for debugging purpose
317  * getScheduled get the number of scheduled events for this Observable.
318  * @param n The node of an Observable object
319  * @return the number of scheduled events involving this Observable as sender or receiver.
320  */
321  static unsigned int getScheduled(tlp::node n);
322 
323  /**
324  * @brief internal function for debugging purpose
325  * Get the node representing this object in the Observable Graph.
326  * @param obs the Observable object
327  * @return the node of the Observable object in the Observable Graph.
328  */
329  static tlp::node getNode(const tlp::Observable *obs);
330 
331  /**
332  * @brief Gets the observation graph.
333  * @return The graph containing a node for each Observable/Observer/Listener, and an edge between
334  * connected objects.
335  */
336  static const tlp::VectorGraph &getObservableGraph();
337 
338 protected:
339  Observable();
340  Observable(const Observable &);
341  virtual ~Observable();
342  Observable &operator=(const Observable &);
343 
344  /**
345  * @brief Sends an event to all the Observers/Listeners.
346  * It is higly recommended to check if there are observers/listeners to send the event to before
347  * actually sending it
348  * to avoid the overhead of creating too many objects.
349  *
350  * This can be achieved by using the hasOnLookers() function :
351  *
352  * @code
353  * if (hasOnlookers()) {
354  * sendEvent(GraphEvent(*this, GraphEvent::TLP_ADD_NODE, n));
355  * }
356  * @endcode
357  *
358  * @param message The message to send to the listeners/observers.
359  */
360  void sendEvent(const Event &message);
361 
362  /**
363  * @brief This function is called when events are sent to Observers, and Observers only.
364  *
365  * It is passed a vector of all the events that happened since the last call.
366  * If events were held, this vector can be pretty large, and if events were not held it is likely
367  * it only contains a single element.
368  *
369  * @param events The events that happened since the last unHoldObservers().
370  */
371  virtual void treatEvents(const std::vector<Event> &events);
372 
373  /**
374  * @brief This function is called when events are sent to the Listeners, and Listeners only.
375  *
376  * Is it passed a reference to the event that just happened.
377  *
378  * @param message The event that was sent.
379  */
380  virtual void treatEvent(const Event &message);
381 
382  /**
383  * @brief Sends the Event::DELETE before the deletion of the subclass and its internal objects.
384  *
385  * The observation system automatically sends the DELETE event when the Observable is deleted, but
386  * in the case you need to access members of the class inheriting from Observable, you need the
387  * event
388  * sent *before* the outermost objects are destroyed.
389  *
390  * To achieve this, you can call this function in your destructor, and the DELETE event will be
391  * sent.
392  * This will allow your Listeners/Observers to access your members one last time before deletion.
393  *
394  * @warning This function must be called only once per object.
395  * Make sure no other class in the inheritance tree calls this function before adding this call to
396  * your destructor.
397  */
398  void observableDeleted();
399 
400  /**
401  * @brief Checks whether there are Observers/Listeners attached to this object.
402  *
403  * Using this function avoids the creation of events that no-one will see :
404  * @code
405  * if (hasOnlookers()) {
406  * sendEvent(GraphEvent(*this, GraphEvent::TLP_ADD_NODE, n));
407  * }
408  * @endcode
409  *
410  * @return
411  */
412  bool hasOnlookers() const;
413 
414 private:
415  enum OBSERVABLEEDGETYPE { OBSERVABLE = 0x01, OBSERVER = 0x02, LISTENER = 0x04 };
416 
417  /**
418  * @brief deleteMsgSent This allows for calling observableDeleted() multiple times safely.
419  */
420  bool deleteMsgSent;
421 
422  /**
423  * @brief queuedEvent Used to prevent unnecessary elements insertion in the set of events.
424  */
425  mutable bool queuedEvent;
426 
427  /**
428  * @brief _n The node that represents this object in the ObservableGraph.
429  */
430  tlp::node _n;
431 #ifndef NDEBUG
432  /**
433  * @brief sent The number of sent events
434  */
435  unsigned int sent;
436 
437  /**
438  * @brief received The number of received events.
439  */
440  unsigned int received;
441 #endif
442 
443  /**
444  * @brief return an Iterator on all Onlookers
445  * @warning adding or removing Onlooker to that Observable will devalidate the iterator
446  * @see StableIterator
447  */
448  tlp::Iterator<Observable *> *getOnlookers() const;
449 
450  /**
451  * @brief getInObjects Retrieves Inbound objects (observed objects; i.e. Observable).
452  * @return an iterator on 'in' objects (Observable), the iterator guarantees that all objects are
453  * alive (not deleted during hold or notify).
454  */
455  tlp::Iterator<tlp::node> *getInObjects() const;
456 
457  /**
458  * @brief getOutObjects Retrieves Outbound objects (observing objects; i.e. Listeners and
459  * Observers).
460  * @return an iterator on out objects (Listener/Observer), the iterator guarantees that all
461  * objects are alive (not deleted during hold or notify).
462  */
463  tlp::Iterator<tlp::node> *getOutObjects() const;
464 
465  /**
466  * @brief addOnlooker Adds an Observer/Listener to this object.
467  *
468  * The added Onlookers will received the next Event sent by the Observable.
469  * In case of nested unholding (higly unlikely), calling that function inside hold/unhold block
470  * can make the Observer receive an event that has been sent before it was Observing the object.
471  *
472  * @param obs The Observer/Listener to add to this object.
473  * @param type The kind of observation (Listener or Observer).
474  */
475  void addOnlooker(const Observable &obs, OBSERVABLEEDGETYPE type) const;
476 
477  /**
478  * @brief removeOnlooker removes an Observer/Listener from this object.
479  *
480  * In case of nested unholding (higly unlikely), calling that function inside a hold/unhold block
481  * could
482  * make the Observer not receive an event that was sent when it was connected.
483  *
484  * @warning removing OnLooker that has been created outside of your code can create serious
485  * problems in your application. Objects that are listening/observing could need to receive
486  * the events to work properly.
487  *
488  * @param obs The Observer/Listener to remove
489  * @param type The kind of connection (Listener or Observer).
490  */
491  void removeOnlooker(const Observable &obs, OBSERVABLEEDGETYPE type) const;
492 
493  /**
494  * @brief getNode Get the node representing this object in the ObservableGraph.
495  * @return the node representing that ObservableObject in the ObservableGraph.
496  */
497  tlp::node getNode() const;
498 
499  // static members and methods
500  /**
501  * @brief _oHoldCounter counter of nested holds
502  */
503  static unsigned int _oHoldCounter;
504 
505  /**
506  * @brief _oDisabled used to disable the events notification
507  */
508  static bool _oDisabled;
509 
510  /**
511  * @brief delete nodes from the ObservableGraph that have been preserved to keep coherency and
512  * check bad use of the mechanism.
513  */
514  static void updateObserverGraph();
515 
516  /**
517  * @brief getBoundNode
518  * @return the bound node representing this ObservableObject in the ObservableGraph,
519  * if _n is not valid it is then bound to a new added node
520  */
521  tlp::node getBoundNode();
522  bool isBound() const {
523  return _n.isValid();
524  }
525 };
526 
527 /**
528  * @ingroup Observation
529  * @brief The ObserverHolder class is a convenience class to automatically hold and unhold
530  * observers. It performs a call to Observable::holdObservers() at its creation and a call to
531  * Observable::unholdObservers() at its destruction.
532  * You can use it if you have to hold observers in a function with multiple return points to avoid
533  * to call Observable::unholdObservers() for each of them.
534  * @code
535  * void myFunc(){
536  * ObserverHolder holder;//Automatically call Observable::holdObservers()
537  *
538  * if(someTest()){
539  * someOperation1();
540  * return;//No need to call Observable::unholdObservers() it will be called with the
541  * destruction of the locker object
542  * }
543  *
544  * }
545  * @endcode
546  *
547  */
548 class TLP_SCOPE ObserverHolder {
549 public:
550  ObserverHolder() {
552  }
553  ~ObserverHolder() {
555  }
556 };
557 } // namespace tlp
558 
559 #endif
tlp::Observable::removeListener
void removeListener(Observable &listener) const
Removes a listener from this object.
Definition: Observable.h:268
tlp::Graph
Definition: Graph.h:234
tlp::Observable::addListener
void addListener(Observable &listener) const
Adds a Listener to this object.
Definition: Observable.h:232
tlp::Observable::disableEventNotification
static void disableEventNotification()
disable the whole event notification mechanism Until a call to enableEventNotification(),...
Definition: Observable.h:185
tlp::PropertyInterface
PropertyInterface describes the interface of a graph property.
Definition: PropertyInterface.h:60
tlp::node::isValid
bool isValid() const
isValid checks if the node is valid. An invalid node is a node whose id is UINT_MAX.
Definition: Node.h:92
tlp::Event
Event is the base class for all events used in the Observation mechanism.
Definition: Observable.h:52
tlp::Observable::observersHoldCounter
static unsigned int observersHoldCounter()
observersHoldCounter gives the number of times holdObservers() has been called without a matching unh...
Definition: Observable.h:170
tlp::Observable::holdObservers
static void holdObservers()
Holds back all events until Observable::unholdObservers() is called.
tlp::ObserverHolder
The ObserverHolder class is a convenience class to automatically hold and unhold observers....
Definition: Observable.h:548
tlp::Iterator
Interface for Tulip iterators. Allows basic iteration operations only.
Definition: Graph.h:43
tlp
Definition: AbstractProperty.h:34
tlp::Observable::unholdObservers
static void unholdObservers()
Sends all held events to the Observers.
tlp::Observable
The Observable class is the base of Tulip's observation system.
Definition: Observable.h:127
tlp::Observable::removeObserver
void removeObserver(Observable &observer) const
Removes an observer from this object.
Definition: Observable.h:250
tlp::node
The node struct represents a node in a Graph object.
Definition: Node.h:40
tlp::Observable::enableEventNotification
static void enableEventNotification()
re-enable the whole event notification mechanism All events sent since a previous call to enableEvent...
Definition: Observable.h:194
tlp::Observable::addObserver
void addObserver(Observable &observer) const
Adds an Observer to this object.
Definition: Observable.h:212