COIN-OR::LEMON - Graph Library

source: lemon-main/lemon/bits/alteration_notifier.h @ 1197:f179aa1045a4

Last change on this file since 1197:f179aa1045a4 was 1092:dceba191c00d, checked in by Alpar Juttner <alpar@…>, 11 years ago

Apply unify-sources.sh to the source tree

File size: 15.4 KB
RevLine 
[209]1/* -*- mode: C++; indent-tabs-mode: nil; -*-
[57]2 *
[209]3 * This file is a part of LEMON, a generic C++ optimization library.
[57]4 *
[1092]5 * Copyright (C) 2003-2013
[57]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
[220]25#include <lemon/core.h>
[979]26#include <lemon/bits/lock.h>
[57]27
[314]28//\ingroup graphbits
29//\file
30//\brief Observer notifier for graph alteration observers.
[57]31
32namespace lemon {
33
[314]34  // \ingroup graphbits
35  //
36  // \brief Notifier class to notify observes about alterations in
37  // a container.
38  //
[361]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.
[314]43  //
[361]44  // The node and edge sets of the graphs can be changed as we add or erase
[314]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
[361]49  // in the library. We use another solution: we notify all maps about
[314]50  // an alteration in the graph, which cause only drawback on the
51  // alteration of the graph.
52  //
[361]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.
[314]58  //
59  // For the proper functonality of this class, we should notify it
[361]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
[314]65  // clear() and build() members. Important rule that if we erase items
[361]66  // from graphs we should first signal the alteration and after that erase
[314]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
[361]71  // ObserverBase nested class. The signals can be handled with
[314]72  // overriding the virtual functions defined in the base class.  The
73  // observer base can be attached to the notifier with the
[361]74  // attach() member and can be detached with detach() function. The
[314]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  //
[361]79  // Alteration observers try to be exception safe. If an add() or
80  // a clear() function throws an exception then the remaining
[314]81  // observeres will not be notified and the fulfilled additions will
[361]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.
[314]86  //
[361]87  // There are some cases, when the alteration observing is not completly
[314]88  // reliable. If we want to carry out the node degree in the graph
[361]89  // as in the \ref InDegMap and we use the reverseArc(), then it cause
[314]90  // unreliable functionality. Because the alteration observing signals
[361]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.
[314]95  //
96  // \param _Container The container which is observed.
97  // \param _Item The item type which is obserbved.
[57]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
[361]108    // \brief Exception which can be called from clear() and
109    // erase().
[314]110    //
[361]111    // From the clear() and erase() function only this
[314]112    // exception is allowed to throw. The exception immediatly
113    // detaches the current observer from the notifier. Because the
[361]114    // clear() and erase() should not throw other exceptions
[314]115    // it can be used to invalidate the observer.
[57]116    struct ImmediateDetach {};
117
[314]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
[361]126    // to notify the oberver when one item is added or erased.
[314]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.
[57]131    class ObserverBase {
132    protected:
133      typedef AlterationNotifier Notifier;
134
135      friend class AlterationNotifier;
136
[314]137      // \brief Default constructor.
138      //
139      // Default constructor for ObserverBase.
[57]140      ObserverBase() : _notifier(0) {}
141
[314]142      // \brief Constructor which attach the observer into notifier.
143      //
144      // Constructor which attach the observer into notifier.
[57]145      ObserverBase(AlterationNotifier& nf) {
146        attach(nf);
147      }
148
[314]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.
[57]153      ObserverBase(const ObserverBase& copy) {
[209]154        if (copy.attached()) {
[57]155          attach(*copy.notifier());
[209]156        }
[57]157      }
[209]158
[314]159      // \brief Destructor
[57]160      virtual ~ObserverBase() {
161        if (attached()) {
162          detach();
163        }
164      }
165
[314]166      // \brief Attaches the observer into an AlterationNotifier.
167      //
168      // This member attaches the observer into an AlterationNotifier.
[57]169      void attach(AlterationNotifier& nf) {
[209]170        nf.attach(*this);
[57]171      }
[209]172
[314]173      // \brief Detaches the observer into an AlterationNotifier.
174      //
175      // This member detaches the observer from an AlterationNotifier.
[57]176      void detach() {
177        _notifier->detach(*this);
178      }
[209]179
[314]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.
[57]185      Notifier* notifier() const { return const_cast<Notifier*>(_notifier); }
[209]186
[314]187      // Gives back true when the observer is attached into a notifier.
[57]188      bool attached() const { return _notifier != 0; }
189
190    private:
191
192      ObserverBase& operator=(const ObserverBase& copy);
193
194    protected:
[209]195
[57]196      Notifier* _notifier;
197      typename std::list<ObserverBase*>::iterator _index;
198
[314]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.
[57]205      virtual void add(const Item&) = 0;
206
[314]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.
[57]213      virtual void add(const std::vector<Item>& items) = 0;
214
[314]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.
[57]221      virtual void erase(const Item&) = 0;
222
[314]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.
[57]229      virtual void erase(const std::vector<Item>& items) = 0;
230
[314]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.
[57]237      virtual void build() = 0;
238
[314]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.
[57]245      virtual void clear() = 0;
246
247    };
[209]248
[57]249  protected:
250
251    const Container* container;
252
[209]253    typedef std::list<ObserverBase*> Observers;
[57]254    Observers _observers;
[979]255    lemon::bits::Lock _lock;
[209]256
[57]257  public:
258
[314]259    // \brief Default constructor.
260    //
261    // The default constructor of the AlterationNotifier.
262    // It creates an empty notifier.
[209]263    AlterationNotifier()
[57]264      : container(0) {}
265
[314]266    // \brief Constructor.
267    //
268    // Constructor with the observed container parameter.
[209]269    AlterationNotifier(const Container& _container)
[57]270      : container(&_container) {}
271
[314]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.
[209]277    AlterationNotifier(const AlterationNotifier& _notifier)
[57]278      : container(_notifier.container) {}
279
[314]280    // \brief Destructor.
281    //
282    // Destructor of the AlterationNotifier.
[57]283    ~AlterationNotifier() {
284      typename Observers::iterator it;
285      for (it = _observers.begin(); it != _observers.end(); ++it) {
[209]286        (*it)->_notifier = 0;
[57]287      }
288    }
289
[314]290    // \brief Sets the container.
291    //
292    // Sets the container.
[57]293    void setContainer(const Container& _container) {
294      container = &_container;
295    }
296
297  protected:
298
299    AlterationNotifier& operator=(const AlterationNotifier&);
300
301  public:
302
[314]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.
[57]307    void first(Item& item) const {
308      container->first(item);
309    }
310
[314]311    // \brief Next item in the container.
312    //
313    // Returns the next item in the container. It is
314    // for iterate on the container.
[57]315    void next(Item& item) const {
316      container->next(item);
317    }
318
[314]319    // \brief Returns the id of the item.
320    //
321    // Returns the id of the item provided by the container.
[57]322    int id(const Item& item) const {
323      return container->id(item);
324    }
325
[314]326    // \brief Returns the maximum id of the container.
327    //
328    // Returns the maximum id of the container.
[57]329    int maxId() const {
330      return container->maxId(Item());
331    }
[209]332
[57]333  protected:
334
335    void attach(ObserverBase& observer) {
[979]336      _lock.lock();
[57]337      observer._index = _observers.insert(_observers.begin(), &observer);
338      observer._notifier = this;
[979]339      _lock.unlock();
[209]340    }
[57]341
342    void detach(ObserverBase& observer) {
[979]343      _lock.lock();
[57]344      _observers.erase(observer._index);
345      observer._index = _observers.end();
346      observer._notifier = 0;
[979]347      _lock.unlock();
[57]348    }
349
350  public:
[209]351
[314]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.
[57]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      }
[209]370    }
[57]371
[314]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.
[57]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      }
[209]390    }
[57]391
[314]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.
[57]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;
[230]406          it = _observers.erase(it);
[57]407        }
408      }
409    }
410
[314]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.
[57]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;
[230]425          it = _observers.erase(it);
[57]426        }
427      }
428    }
429
[314]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.
[57]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
[314]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.
[57]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;
[230]464          it = _observers.erase(it);
[57]465        }
466      }
467    }
468  };
469
470}
471
472#endif
Note: See TracBrowser for help on using the repository browser.