LCOV - code coverage report
Current view: top level - lemon/lemon/bits - alteration_notifier.h (source / functions) Hit Total Coverage
Test: coverage_sk.info Lines: 56 72 77.8 %
Date: 2020-07-01 15:24:36 Functions: 24 36 66.7 %
Branches: 29 148 19.6 %

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

Generated by: LCOV version 1.11