COIN-OR::LEMON - Graph Library

source: lemon/lemon/bits/alteration_notifier.h @ 1131:43a91b33f374

Last change on this file since 1131:43a91b33f374 was 1131:43a91b33f374, checked in by Balazs Dezso <deba@…>, 12 years ago

Thread safe map construction and destruction (#223)

It currently support pthread and windows threads.

File size: 15.4 KB
Line 
1/* -*- mode: C++; indent-tabs-mode: nil; -*-
2 *
3 * This file is a part of LEMON, a generic C++ optimization library.
4 *
5 * Copyright (C) 2003-2009
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 *
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
12 *
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
15 * purpose.
16 *
17 */
18
19#ifndef LEMON_BITS_ALTERATION_NOTIFIER_H
20#define LEMON_BITS_ALTERATION_NOTIFIER_H
21
22#include <vector>
23#include <list>
24
25#include <lemon/core.h>
26#include <lemon/bits/lock.h>
27
28//\ingroup graphbits
29//\file
30//\brief Observer notifier for graph alteration observers.
31
32namespace lemon {
33
34  // \ingroup graphbits
35  //
36  // \brief Notifier class to notify observes about alterations in
37  // a container.
38  //
39  // The simple graphs can be refered as two containers: a node container
40  // and an edge container. But they do not store values directly, they
41  // are just key continars for more value containers, which are the
42  // node and edge maps.
43  //
44  // The node and edge sets of the graphs can be changed as we add or erase
45  // nodes and edges in the graph. LEMON would like to handle easily
46  // that the node and edge maps should contain values for all nodes or
47  // edges. If we want to check on every indicing if the map contains
48  // the current indicing key that cause a drawback in the performance
49  // in the library. We use another solution: we notify all maps about
50  // an alteration in the graph, which cause only drawback on the
51  // alteration of the graph.
52  //
53  // This class provides an interface to a node or edge container.
54  // The first() and next() member functions make possible
55  // to iterate on the keys of the container.
56  // The id() function returns an integer id for each key.
57  // The maxId() function gives back an upper bound of the ids.
58  //
59  // For the proper functonality of this class, we should notify it
60  // about each alteration in the container. The alterations have four type:
61  // add(), erase(), build() and clear(). The add() and
62  // erase() signal that only one or few items added or erased to or
63  // from the graph. If all items are erased from the graph or if a new graph
64  // is built from an empty graph, then it can be signaled with the
65  // clear() and build() members. Important rule that if we erase items
66  // from graphs we should first signal the alteration and after that erase
67  // them from the container, on the other way on item addition we should
68  // first extend the container and just after that signal the alteration.
69  //
70  // The alteration can be observed with a class inherited from the
71  // ObserverBase nested class. The signals can be handled with
72  // overriding the virtual functions defined in the base class.  The
73  // observer base can be attached to the notifier with the
74  // attach() member and can be detached with detach() function. The
75  // alteration handlers should not call any function which signals
76  // an other alteration in the same notifier and should not
77  // detach any observer from the notifier.
78  //
79  // Alteration observers try to be exception safe. If an add() or
80  // a clear() function throws an exception then the remaining
81  // observeres will not be notified and the fulfilled additions will
82  // be rolled back by calling the erase() or clear() functions.
83  // Hence erase() and clear() should not throw exception.
84  // Actullay, they can throw only \ref ImmediateDetach exception,
85  // which detach the observer from the notifier.
86  //
87  // There are some cases, when the alteration observing is not completly
88  // reliable. If we want to carry out the node degree in the graph
89  // as in the \ref InDegMap and we use the reverseArc(), then it cause
90  // unreliable functionality. Because the alteration observing signals
91  // only erasing and adding but not the reversing, it will stores bad
92  // degrees. Apart form that the subgraph adaptors cannot even signal
93  // the alterations because just a setting in the filter map can modify
94  // the graph and this cannot be watched in any way.
95  //
96  // \param _Container The container which is observed.
97  // \param _Item The item type which is obserbved.
98
99  template <typename _Container, typename _Item>
100  class AlterationNotifier {
101  public:
102
103    typedef True Notifier;
104
105    typedef _Container Container;
106    typedef _Item Item;
107
108    // \brief Exception which can be called from clear() and
109    // erase().
110    //
111    // From the clear() and erase() function only this
112    // exception is allowed to throw. The exception immediatly
113    // detaches the current observer from the notifier. Because the
114    // clear() and erase() should not throw other exceptions
115    // it can be used to invalidate the observer.
116    struct ImmediateDetach {};
117
118    // \brief ObserverBase is the base class for the observers.
119    //
120    // ObserverBase is the abstract base class for the observers.
121    // It will be notified about an item was inserted into or
122    // erased from the graph.
123    //
124    // The observer interface contains some pure virtual functions
125    // to override. The add() and erase() functions are
126    // to notify the oberver when one item is added or erased.
127    //
128    // The build() and clear() members are to notify the observer
129    // about the container is built from an empty container or
130    // is cleared to an empty container.
131    class ObserverBase {
132    protected:
133      typedef AlterationNotifier Notifier;
134
135      friend class AlterationNotifier;
136
137      // \brief Default constructor.
138      //
139      // Default constructor for ObserverBase.
140      ObserverBase() : _notifier(0) {}
141
142      // \brief Constructor which attach the observer into notifier.
143      //
144      // Constructor which attach the observer into notifier.
145      ObserverBase(AlterationNotifier& nf) {
146        attach(nf);
147      }
148
149      // \brief Constructor which attach the obserever to the same notifier.
150      //
151      // Constructor which attach the obserever to the same notifier as
152      // the other observer is attached to.
153      ObserverBase(const ObserverBase& copy) {
154        if (copy.attached()) {
155          attach(*copy.notifier());
156        }
157      }
158
159      // \brief Destructor
160      virtual ~ObserverBase() {
161        if (attached()) {
162          detach();
163        }
164      }
165
166      // \brief Attaches the observer into an AlterationNotifier.
167      //
168      // This member attaches the observer into an AlterationNotifier.
169      void attach(AlterationNotifier& nf) {
170        nf.attach(*this);
171      }
172
173      // \brief Detaches the observer into an AlterationNotifier.
174      //
175      // This member detaches the observer from an AlterationNotifier.
176      void detach() {
177        _notifier->detach(*this);
178      }
179
180      // \brief Gives back a pointer to the notifier which the map
181      // attached into.
182      //
183      // This function gives back a pointer to the notifier which the map
184      // attached into.
185      Notifier* notifier() const { return const_cast<Notifier*>(_notifier); }
186
187      // Gives back true when the observer is attached into a notifier.
188      bool attached() const { return _notifier != 0; }
189
190    private:
191
192      ObserverBase& operator=(const ObserverBase& copy);
193
194    protected:
195
196      Notifier* _notifier;
197      typename std::list<ObserverBase*>::iterator _index;
198
199      // \brief The member function to notificate the observer about an
200      // item is added to the container.
201      //
202      // The add() member function notificates the observer about an item
203      // is added to the container. It have to be overrided in the
204      // subclasses.
205      virtual void add(const Item&) = 0;
206
207      // \brief The member function to notificate the observer about
208      // more item is added to the container.
209      //
210      // The add() member function notificates the observer about more item
211      // is added to the container. It have to be overrided in the
212      // subclasses.
213      virtual void add(const std::vector<Item>& items) = 0;
214
215      // \brief The member function to notificate the observer about an
216      // item is erased from the container.
217      //
218      // The erase() member function notificates the observer about an
219      // item is erased from the container. It have to be overrided in
220      // the subclasses.
221      virtual void erase(const Item&) = 0;
222
223      // \brief The member function to notificate the observer about
224      // more item is erased from the container.
225      //
226      // The erase() member function notificates the observer about more item
227      // is erased from the container. It have to be overrided in the
228      // subclasses.
229      virtual void erase(const std::vector<Item>& items) = 0;
230
231      // \brief The member function to notificate the observer about the
232      // container is built.
233      //
234      // The build() member function notificates the observer about the
235      // container is built from an empty container. It have to be
236      // overrided in the subclasses.
237      virtual void build() = 0;
238
239      // \brief The member function to notificate the observer about all
240      // items are erased from the container.
241      //
242      // The clear() member function notificates the observer about all
243      // items are erased from the container. It have to be overrided in
244      // the subclasses.
245      virtual void clear() = 0;
246
247    };
248
249  protected:
250
251    const Container* container;
252
253    typedef std::list<ObserverBase*> Observers;
254    Observers _observers;
255    lemon::bits::Lock _lock;
256
257  public:
258
259    // \brief Default constructor.
260    //
261    // The default constructor of the AlterationNotifier.
262    // It creates an empty notifier.
263    AlterationNotifier()
264      : container(0) {}
265
266    // \brief Constructor.
267    //
268    // Constructor with the observed container parameter.
269    AlterationNotifier(const Container& _container)
270      : container(&_container) {}
271
272    // \brief Copy Constructor of the AlterationNotifier.
273    //
274    // Copy constructor of the AlterationNotifier.
275    // It creates only an empty notifier because the copiable
276    // notifier's observers have to be registered still into that notifier.
277    AlterationNotifier(const AlterationNotifier& _notifier)
278      : container(_notifier.container) {}
279
280    // \brief Destructor.
281    //
282    // Destructor of the AlterationNotifier.
283    ~AlterationNotifier() {
284      typename Observers::iterator it;
285      for (it = _observers.begin(); it != _observers.end(); ++it) {
286        (*it)->_notifier = 0;
287      }
288    }
289
290    // \brief Sets the container.
291    //
292    // Sets the container.
293    void setContainer(const Container& _container) {
294      container = &_container;
295    }
296
297  protected:
298
299    AlterationNotifier& operator=(const AlterationNotifier&);
300
301  public:
302
303    // \brief First item in the container.
304    //
305    // Returns the first item in the container. It is
306    // for start the iteration on the container.
307    void first(Item& item) const {
308      container->first(item);
309    }
310
311    // \brief Next item in the container.
312    //
313    // Returns the next item in the container. It is
314    // for iterate on the container.
315    void next(Item& item) const {
316      container->next(item);
317    }
318
319    // \brief Returns the id of the item.
320    //
321    // Returns the id of the item provided by the container.
322    int id(const Item& item) const {
323      return container->id(item);
324    }
325
326    // \brief Returns the maximum id of the container.
327    //
328    // Returns the maximum id of the container.
329    int maxId() const {
330      return container->maxId(Item());
331    }
332
333  protected:
334
335    void attach(ObserverBase& observer) {
336      _lock.lock();
337      observer._index = _observers.insert(_observers.begin(), &observer);
338      observer._notifier = this;
339      _lock.unlock();
340    }
341
342    void detach(ObserverBase& observer) {
343      _lock.lock();
344      _observers.erase(observer._index);
345      observer._index = _observers.end();
346      observer._notifier = 0;
347      _lock.unlock();
348    }
349
350  public:
351
352    // \brief Notifies all the registed observers about an item added to
353    // the container.
354    //
355    // It notifies all the registed observers about an item added to
356    // the container.
357    void add(const Item& item) {
358      typename Observers::reverse_iterator it;
359      try {
360        for (it = _observers.rbegin(); it != _observers.rend(); ++it) {
361          (*it)->add(item);
362        }
363      } catch (...) {
364        typename Observers::iterator jt;
365        for (jt = it.base(); jt != _observers.end(); ++jt) {
366          (*jt)->erase(item);
367        }
368        throw;
369      }
370    }
371
372    // \brief Notifies all the registed observers about more item added to
373    // the container.
374    //
375    // It notifies all the registed observers about more item added to
376    // the container.
377    void add(const std::vector<Item>& items) {
378      typename Observers::reverse_iterator it;
379      try {
380        for (it = _observers.rbegin(); it != _observers.rend(); ++it) {
381          (*it)->add(items);
382        }
383      } catch (...) {
384        typename Observers::iterator jt;
385        for (jt = it.base(); jt != _observers.end(); ++jt) {
386          (*jt)->erase(items);
387        }
388        throw;
389      }
390    }
391
392    // \brief Notifies all the registed observers about an item erased from
393    // the container.
394    //
395    // It notifies all the registed observers about an item erased from
396    // the container.
397    void erase(const Item& item) throw() {
398      typename Observers::iterator it = _observers.begin();
399      while (it != _observers.end()) {
400        try {
401          (*it)->erase(item);
402          ++it;
403        } catch (const ImmediateDetach&) {
404          (*it)->_index = _observers.end();
405          (*it)->_notifier = 0;
406          it = _observers.erase(it);
407        }
408      }
409    }
410
411    // \brief Notifies all the registed observers about more item erased
412    // from the container.
413    //
414    // It notifies all the registed observers about more item erased from
415    // the container.
416    void erase(const std::vector<Item>& items) {
417      typename Observers::iterator it = _observers.begin();
418      while (it != _observers.end()) {
419        try {
420          (*it)->erase(items);
421          ++it;
422        } catch (const ImmediateDetach&) {
423          (*it)->_index = _observers.end();
424          (*it)->_notifier = 0;
425          it = _observers.erase(it);
426        }
427      }
428    }
429
430    // \brief Notifies all the registed observers about the container is
431    // built.
432    //
433    // Notifies all the registed observers about the container is built
434    // from an empty container.
435    void build() {
436      typename Observers::reverse_iterator it;
437      try {
438        for (it = _observers.rbegin(); it != _observers.rend(); ++it) {
439          (*it)->build();
440        }
441      } catch (...) {
442        typename Observers::iterator jt;
443        for (jt = it.base(); jt != _observers.end(); ++jt) {
444          (*jt)->clear();
445        }
446        throw;
447      }
448    }
449
450    // \brief Notifies all the registed observers about all items are
451    // erased.
452    //
453    // Notifies all the registed observers about all items are erased
454    // from the container.
455    void clear() {
456      typename Observers::iterator it = _observers.begin();
457      while (it != _observers.end()) {
458        try {
459          (*it)->clear();
460          ++it;
461        } catch (const ImmediateDetach&) {
462          (*it)->_index = _observers.end();
463          (*it)->_notifier = 0;
464          it = _observers.erase(it);
465        }
466      }
467    }
468  };
469
470}
471
472#endif
Note: See TracBrowser for help on using the repository browser.