alpar@209: /* -*- mode: C++; indent-tabs-mode: nil; -*- deba@57: * alpar@209: * This file is a part of LEMON, a generic C++ optimization library. deba@57: * alpar@440: * Copyright (C) 2003-2009 deba@57: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport deba@57: * (Egervary Research Group on Combinatorial Optimization, EGRES). deba@57: * deba@57: * Permission to use, modify and distribute this software is granted deba@57: * provided that this copyright notice appears in all copies. For deba@57: * precise terms see the accompanying LICENSE file. deba@57: * deba@57: * This software is provided "AS IS" with no warranty of any kind, deba@57: * express or implied, and with no claim as to its suitability for any deba@57: * purpose. deba@57: * deba@57: */ deba@57: deba@57: #ifndef LEMON_BITS_ALTERATION_NOTIFIER_H deba@57: #define LEMON_BITS_ALTERATION_NOTIFIER_H deba@57: deba@57: #include deba@57: #include deba@57: deba@220: #include deba@57: kpeter@314: //\ingroup graphbits kpeter@314: //\file kpeter@314: //\brief Observer notifier for graph alteration observers. deba@57: deba@57: namespace lemon { deba@57: kpeter@314: // \ingroup graphbits kpeter@314: // kpeter@314: // \brief Notifier class to notify observes about alterations in kpeter@314: // a container. kpeter@314: // kpeter@361: // The simple graphs can be refered as two containers: a node container kpeter@361: // and an edge container. But they do not store values directly, they kpeter@361: // are just key continars for more value containers, which are the kpeter@361: // node and edge maps. kpeter@314: // kpeter@361: // The node and edge sets of the graphs can be changed as we add or erase kpeter@314: // nodes and edges in the graph. LEMON would like to handle easily kpeter@314: // that the node and edge maps should contain values for all nodes or kpeter@314: // edges. If we want to check on every indicing if the map contains kpeter@314: // the current indicing key that cause a drawback in the performance kpeter@361: // in the library. We use another solution: we notify all maps about kpeter@314: // an alteration in the graph, which cause only drawback on the kpeter@314: // alteration of the graph. kpeter@314: // kpeter@361: // This class provides an interface to a node or edge container. kpeter@361: // The first() and next() member functions make possible kpeter@361: // to iterate on the keys of the container. kpeter@361: // The id() function returns an integer id for each key. kpeter@361: // The maxId() function gives back an upper bound of the ids. kpeter@314: // kpeter@314: // For the proper functonality of this class, we should notify it kpeter@361: // about each alteration in the container. The alterations have four type: kpeter@361: // add(), erase(), build() and clear(). The add() and kpeter@361: // erase() signal that only one or few items added or erased to or kpeter@361: // from the graph. If all items are erased from the graph or if a new graph kpeter@361: // is built from an empty graph, then it can be signaled with the kpeter@314: // clear() and build() members. Important rule that if we erase items kpeter@361: // from graphs we should first signal the alteration and after that erase kpeter@314: // them from the container, on the other way on item addition we should kpeter@314: // first extend the container and just after that signal the alteration. kpeter@314: // kpeter@314: // The alteration can be observed with a class inherited from the kpeter@361: // ObserverBase nested class. The signals can be handled with kpeter@314: // overriding the virtual functions defined in the base class. The kpeter@314: // observer base can be attached to the notifier with the kpeter@361: // attach() member and can be detached with detach() function. The kpeter@314: // alteration handlers should not call any function which signals kpeter@314: // an other alteration in the same notifier and should not kpeter@314: // detach any observer from the notifier. kpeter@314: // kpeter@361: // Alteration observers try to be exception safe. If an add() or kpeter@361: // a clear() function throws an exception then the remaining kpeter@314: // observeres will not be notified and the fulfilled additions will kpeter@361: // be rolled back by calling the erase() or clear() functions. kpeter@361: // Hence erase() and clear() should not throw exception. kpeter@361: // Actullay, they can throw only \ref ImmediateDetach exception, kpeter@361: // which detach the observer from the notifier. kpeter@314: // kpeter@361: // There are some cases, when the alteration observing is not completly kpeter@314: // reliable. If we want to carry out the node degree in the graph kpeter@361: // as in the \ref InDegMap and we use the reverseArc(), then it cause kpeter@314: // unreliable functionality. Because the alteration observing signals kpeter@361: // only erasing and adding but not the reversing, it will stores bad kpeter@361: // degrees. Apart form that the subgraph adaptors cannot even signal kpeter@361: // the alterations because just a setting in the filter map can modify kpeter@361: // the graph and this cannot be watched in any way. kpeter@314: // kpeter@314: // \param _Container The container which is observed. kpeter@314: // \param _Item The item type which is obserbved. deba@57: deba@57: template deba@57: class AlterationNotifier { deba@57: public: deba@57: deba@57: typedef True Notifier; deba@57: deba@57: typedef _Container Container; deba@57: typedef _Item Item; deba@57: kpeter@361: // \brief Exception which can be called from clear() and kpeter@361: // erase(). kpeter@314: // kpeter@361: // From the clear() and erase() function only this kpeter@314: // exception is allowed to throw. The exception immediatly kpeter@314: // detaches the current observer from the notifier. Because the kpeter@361: // clear() and erase() should not throw other exceptions kpeter@314: // it can be used to invalidate the observer. deba@57: struct ImmediateDetach {}; deba@57: kpeter@314: // \brief ObserverBase is the base class for the observers. kpeter@314: // kpeter@314: // ObserverBase is the abstract base class for the observers. kpeter@314: // It will be notified about an item was inserted into or kpeter@314: // erased from the graph. kpeter@314: // kpeter@314: // The observer interface contains some pure virtual functions kpeter@314: // to override. The add() and erase() functions are kpeter@361: // to notify the oberver when one item is added or erased. kpeter@314: // kpeter@314: // The build() and clear() members are to notify the observer kpeter@314: // about the container is built from an empty container or kpeter@314: // is cleared to an empty container. deba@57: class ObserverBase { deba@57: protected: deba@57: typedef AlterationNotifier Notifier; deba@57: deba@57: friend class AlterationNotifier; deba@57: kpeter@314: // \brief Default constructor. kpeter@314: // kpeter@314: // Default constructor for ObserverBase. deba@57: ObserverBase() : _notifier(0) {} deba@57: kpeter@314: // \brief Constructor which attach the observer into notifier. kpeter@314: // kpeter@314: // Constructor which attach the observer into notifier. deba@57: ObserverBase(AlterationNotifier& nf) { deba@57: attach(nf); deba@57: } deba@57: kpeter@314: // \brief Constructor which attach the obserever to the same notifier. kpeter@314: // kpeter@314: // Constructor which attach the obserever to the same notifier as kpeter@314: // the other observer is attached to. deba@57: ObserverBase(const ObserverBase& copy) { alpar@209: if (copy.attached()) { deba@57: attach(*copy.notifier()); alpar@209: } deba@57: } alpar@209: kpeter@314: // \brief Destructor deba@57: virtual ~ObserverBase() { deba@57: if (attached()) { deba@57: detach(); deba@57: } deba@57: } deba@57: kpeter@314: // \brief Attaches the observer into an AlterationNotifier. kpeter@314: // kpeter@314: // This member attaches the observer into an AlterationNotifier. deba@57: void attach(AlterationNotifier& nf) { alpar@209: nf.attach(*this); deba@57: } alpar@209: kpeter@314: // \brief Detaches the observer into an AlterationNotifier. kpeter@314: // kpeter@314: // This member detaches the observer from an AlterationNotifier. deba@57: void detach() { deba@57: _notifier->detach(*this); deba@57: } alpar@209: kpeter@314: // \brief Gives back a pointer to the notifier which the map kpeter@314: // attached into. kpeter@314: // kpeter@314: // This function gives back a pointer to the notifier which the map kpeter@314: // attached into. deba@57: Notifier* notifier() const { return const_cast(_notifier); } alpar@209: kpeter@314: // Gives back true when the observer is attached into a notifier. deba@57: bool attached() const { return _notifier != 0; } deba@57: deba@57: private: deba@57: deba@57: ObserverBase& operator=(const ObserverBase& copy); deba@57: deba@57: protected: alpar@209: deba@57: Notifier* _notifier; deba@57: typename std::list::iterator _index; deba@57: kpeter@314: // \brief The member function to notificate the observer about an kpeter@314: // item is added to the container. kpeter@314: // kpeter@314: // The add() member function notificates the observer about an item kpeter@314: // is added to the container. It have to be overrided in the kpeter@314: // subclasses. deba@57: virtual void add(const Item&) = 0; deba@57: kpeter@314: // \brief The member function to notificate the observer about kpeter@314: // more item is added to the container. kpeter@314: // kpeter@314: // The add() member function notificates the observer about more item kpeter@314: // is added to the container. It have to be overrided in the kpeter@314: // subclasses. deba@57: virtual void add(const std::vector& items) = 0; deba@57: kpeter@314: // \brief The member function to notificate the observer about an kpeter@314: // item is erased from the container. kpeter@314: // kpeter@314: // The erase() member function notificates the observer about an kpeter@314: // item is erased from the container. It have to be overrided in kpeter@314: // the subclasses. deba@57: virtual void erase(const Item&) = 0; deba@57: kpeter@314: // \brief The member function to notificate the observer about kpeter@314: // more item is erased from the container. kpeter@314: // kpeter@314: // The erase() member function notificates the observer about more item kpeter@314: // is erased from the container. It have to be overrided in the kpeter@314: // subclasses. deba@57: virtual void erase(const std::vector& items) = 0; deba@57: kpeter@314: // \brief The member function to notificate the observer about the kpeter@314: // container is built. kpeter@314: // kpeter@314: // The build() member function notificates the observer about the kpeter@314: // container is built from an empty container. It have to be kpeter@314: // overrided in the subclasses. deba@57: virtual void build() = 0; deba@57: kpeter@314: // \brief The member function to notificate the observer about all kpeter@314: // items are erased from the container. kpeter@314: // kpeter@314: // The clear() member function notificates the observer about all kpeter@314: // items are erased from the container. It have to be overrided in kpeter@314: // the subclasses. deba@57: virtual void clear() = 0; deba@57: deba@57: }; alpar@209: deba@57: protected: deba@57: deba@57: const Container* container; deba@57: alpar@209: typedef std::list Observers; deba@57: Observers _observers; deba@57: alpar@209: deba@57: public: deba@57: kpeter@314: // \brief Default constructor. kpeter@314: // kpeter@314: // The default constructor of the AlterationNotifier. kpeter@314: // It creates an empty notifier. alpar@209: AlterationNotifier() deba@57: : container(0) {} deba@57: kpeter@314: // \brief Constructor. kpeter@314: // kpeter@314: // Constructor with the observed container parameter. alpar@209: AlterationNotifier(const Container& _container) deba@57: : container(&_container) {} deba@57: kpeter@314: // \brief Copy Constructor of the AlterationNotifier. kpeter@314: // kpeter@314: // Copy constructor of the AlterationNotifier. kpeter@314: // It creates only an empty notifier because the copiable kpeter@314: // notifier's observers have to be registered still into that notifier. alpar@209: AlterationNotifier(const AlterationNotifier& _notifier) deba@57: : container(_notifier.container) {} deba@57: kpeter@314: // \brief Destructor. kpeter@314: // kpeter@314: // Destructor of the AlterationNotifier. deba@57: ~AlterationNotifier() { deba@57: typename Observers::iterator it; deba@57: for (it = _observers.begin(); it != _observers.end(); ++it) { alpar@209: (*it)->_notifier = 0; deba@57: } deba@57: } deba@57: kpeter@314: // \brief Sets the container. kpeter@314: // kpeter@314: // Sets the container. deba@57: void setContainer(const Container& _container) { deba@57: container = &_container; deba@57: } deba@57: deba@57: protected: deba@57: deba@57: AlterationNotifier& operator=(const AlterationNotifier&); deba@57: deba@57: public: deba@57: kpeter@314: // \brief First item in the container. kpeter@314: // kpeter@314: // Returns the first item in the container. It is kpeter@314: // for start the iteration on the container. deba@57: void first(Item& item) const { deba@57: container->first(item); deba@57: } deba@57: kpeter@314: // \brief Next item in the container. kpeter@314: // kpeter@314: // Returns the next item in the container. It is kpeter@314: // for iterate on the container. deba@57: void next(Item& item) const { deba@57: container->next(item); deba@57: } deba@57: kpeter@314: // \brief Returns the id of the item. kpeter@314: // kpeter@314: // Returns the id of the item provided by the container. deba@57: int id(const Item& item) const { deba@57: return container->id(item); deba@57: } deba@57: kpeter@314: // \brief Returns the maximum id of the container. kpeter@314: // kpeter@314: // Returns the maximum id of the container. deba@57: int maxId() const { deba@57: return container->maxId(Item()); deba@57: } alpar@209: deba@57: protected: deba@57: deba@57: void attach(ObserverBase& observer) { deba@57: observer._index = _observers.insert(_observers.begin(), &observer); deba@57: observer._notifier = this; alpar@209: } deba@57: deba@57: void detach(ObserverBase& observer) { deba@57: _observers.erase(observer._index); deba@57: observer._index = _observers.end(); deba@57: observer._notifier = 0; deba@57: } deba@57: deba@57: public: alpar@209: kpeter@314: // \brief Notifies all the registed observers about an item added to kpeter@314: // the container. kpeter@314: // kpeter@314: // It notifies all the registed observers about an item added to kpeter@314: // the container. deba@57: void add(const Item& item) { deba@57: typename Observers::reverse_iterator it; deba@57: try { deba@57: for (it = _observers.rbegin(); it != _observers.rend(); ++it) { deba@57: (*it)->add(item); deba@57: } deba@57: } catch (...) { deba@57: typename Observers::iterator jt; deba@57: for (jt = it.base(); jt != _observers.end(); ++jt) { deba@57: (*jt)->erase(item); deba@57: } deba@57: throw; deba@57: } alpar@209: } deba@57: kpeter@314: // \brief Notifies all the registed observers about more item added to kpeter@314: // the container. kpeter@314: // kpeter@314: // It notifies all the registed observers about more item added to kpeter@314: // the container. deba@57: void add(const std::vector& items) { deba@57: typename Observers::reverse_iterator it; deba@57: try { deba@57: for (it = _observers.rbegin(); it != _observers.rend(); ++it) { deba@57: (*it)->add(items); deba@57: } deba@57: } catch (...) { deba@57: typename Observers::iterator jt; deba@57: for (jt = it.base(); jt != _observers.end(); ++jt) { deba@57: (*jt)->erase(items); deba@57: } deba@57: throw; deba@57: } alpar@209: } deba@57: kpeter@314: // \brief Notifies all the registed observers about an item erased from kpeter@314: // the container. kpeter@314: // kpeter@314: // It notifies all the registed observers about an item erased from kpeter@314: // the container. deba@57: void erase(const Item& item) throw() { deba@57: typename Observers::iterator it = _observers.begin(); deba@57: while (it != _observers.end()) { deba@57: try { deba@57: (*it)->erase(item); deba@57: ++it; deba@57: } catch (const ImmediateDetach&) { deba@57: (*it)->_index = _observers.end(); deba@57: (*it)->_notifier = 0; deba@230: it = _observers.erase(it); deba@57: } deba@57: } deba@57: } deba@57: kpeter@314: // \brief Notifies all the registed observers about more item erased kpeter@314: // from the container. kpeter@314: // kpeter@314: // It notifies all the registed observers about more item erased from kpeter@314: // the container. deba@57: void erase(const std::vector& items) { deba@57: typename Observers::iterator it = _observers.begin(); deba@57: while (it != _observers.end()) { deba@57: try { deba@57: (*it)->erase(items); deba@57: ++it; deba@57: } catch (const ImmediateDetach&) { deba@57: (*it)->_index = _observers.end(); deba@57: (*it)->_notifier = 0; deba@230: it = _observers.erase(it); deba@57: } deba@57: } deba@57: } deba@57: kpeter@314: // \brief Notifies all the registed observers about the container is kpeter@314: // built. kpeter@314: // kpeter@314: // Notifies all the registed observers about the container is built kpeter@314: // from an empty container. deba@57: void build() { deba@57: typename Observers::reverse_iterator it; deba@57: try { deba@57: for (it = _observers.rbegin(); it != _observers.rend(); ++it) { deba@57: (*it)->build(); deba@57: } deba@57: } catch (...) { deba@57: typename Observers::iterator jt; deba@57: for (jt = it.base(); jt != _observers.end(); ++jt) { deba@57: (*jt)->clear(); deba@57: } deba@57: throw; deba@57: } deba@57: } deba@57: kpeter@314: // \brief Notifies all the registed observers about all items are kpeter@314: // erased. kpeter@314: // kpeter@314: // Notifies all the registed observers about all items are erased kpeter@314: // from the container. deba@57: void clear() { deba@57: typename Observers::iterator it = _observers.begin(); deba@57: while (it != _observers.end()) { deba@57: try { deba@57: (*it)->clear(); deba@57: ++it; deba@57: } catch (const ImmediateDetach&) { deba@57: (*it)->_index = _observers.end(); deba@57: (*it)->_notifier = 0; deba@230: it = _observers.erase(it); deba@57: } deba@57: } deba@57: } deba@57: }; deba@57: deba@57: } deba@57: deba@57: #endif