klao@946: /* -*- C++ -*- klao@946: * alpar@1956: * This file is a part of LEMON, a generic C++ optimization library alpar@1956: * alpar@1956: * Copyright (C) 2003-2006 alpar@1956: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport alpar@1956: * (Egervary Research Group on Combinatorial Optimization, EGRES). klao@946: * klao@946: * Permission to use, modify and distribute this software is granted klao@946: * provided that this copyright notice appears in all copies. For klao@946: * precise terms see the accompanying LICENSE file. klao@946: * klao@946: * This software is provided "AS IS" with no warranty of any kind, klao@946: * express or implied, and with no claim as to its suitability for any klao@946: * purpose. klao@946: * klao@946: */ klao@946: klao@946: #ifndef LEMON_ALTERATION_OBSERVER_REGISTRY_H klao@946: #define LEMON_ALTERATION_OBSERVER_REGISTRY_H klao@946: klao@946: #include klao@946: #include klao@946: alpar@1946: ///\ingroup graphmapfactory klao@946: ///\file klao@946: ///\brief Observer registry for graph alteration observers. klao@946: klao@946: namespace lemon { klao@946: deba@1910: /// \addtogroin graphmapfactory klao@946: /// @{ klao@946: deba@1414: /// \brief Registry class to register objects observes alterations in deba@1414: /// the graph. deba@1414: /// klao@946: /// This class is a registry for the objects which observe the klao@946: /// alterations in a container. The alteration observers can be attached klao@946: /// to and detached from the registry. The observers have to inherit deba@1038: /// from the \ref AlterationNotifier::ObserverBase and override klao@946: /// the virtual functions in that. klao@946: /// klao@946: /// The most important application of the alteration observing is the deba@1414: /// dynamic map implementation. klao@946: /// klao@946: /// \param _Item The item type what the observers are observing, usually klao@946: /// edge or node. klao@946: /// klao@946: /// \author Balazs Dezso klao@946: klao@946: template deba@1038: class AlterationNotifier { klao@946: public: klao@946: typedef _Item Item; klao@946: klao@946: /// ObserverBase is the base class for the observers. klao@946: klao@946: /// ObserverBase is the abstract base class for the observers. klao@946: /// It will be notified about an item was inserted into or klao@946: /// erased from the graph. klao@946: /// klao@946: /// The observer interface contains some pure virtual functions klao@946: /// to override. The add() and erase() functions are klao@946: /// to notify the oberver when one item is added or klao@946: /// erased. klao@946: /// klao@946: /// The build() and clear() members are to notify the observer alpar@1204: /// about the container is built from an empty container or klao@946: /// is cleared to an empty container. klao@946: /// klao@946: /// \author Balazs Dezso klao@946: klao@946: class ObserverBase { klao@946: protected: deba@1038: typedef AlterationNotifier Registry; klao@946: deba@1038: friend class AlterationNotifier; klao@946: deba@1414: /// \brief Default constructor. deba@1414: /// klao@946: /// Default constructor for ObserverBase. klao@946: /// klao@946: ObserverBase() : registry(0) {} klao@946: deba@1685: ObserverBase(const ObserverBase& copy) { deba@1685: if (copy.attached()) { deba@1685: copy.getRegistry()->attach(*this); deba@1685: } deba@1685: } deba@1685: klao@946: virtual ~ObserverBase() {} klao@946: deba@1414: /// \brief Attaches the observer into an AlterationNotifier. deba@1414: /// deba@1038: /// This member attaches the observer into an AlterationNotifier. klao@946: /// deba@1038: void attach(AlterationNotifier& r) { klao@946: registry = &r; klao@946: registry->attach(*this); klao@946: } klao@946: deba@1414: /// \brief Detaches the observer into an AlterationNotifier. deba@1414: /// deba@1038: /// This member detaches the observer from an AlterationNotifier. klao@946: /// klao@946: void detach() { klao@946: if (registry) { klao@946: registry->detach(*this); klao@946: } klao@946: } klao@946: klao@946: klao@946: /// Gives back a pointer to the registry what the map attached into. klao@946: klao@946: /// This function gives back a pointer to the registry what the map klao@946: /// attached into. klao@946: /// klao@946: Registry* getRegistry() const { return const_cast(registry); } klao@946: klao@946: /// Gives back true when the observer is attached into a registry. klao@946: bool attached() const { return registry != 0; } deba@1685: klao@946: private: klao@946: klao@946: ObserverBase& operator=(const ObserverBase& copy); klao@946: klao@946: protected: klao@946: klao@946: Registry* registry; klao@946: int registry_index; klao@946: klao@946: /// \brief The member function to notificate the observer about an klao@946: /// item is added to the container. klao@946: /// klao@946: /// The add() member function notificates the observer about an item klao@946: /// is added to the container. It have to be overrided in the klao@946: /// subclasses. klao@946: deba@1414: virtual void add(const Item&) = 0; klao@946: deba@1414: /// \brief The member function to notificate the observer about deba@1718: /// more item is added to the container. deba@1414: /// deba@1718: /// The add() member function notificates the observer about more item deba@1414: /// is added to the container. It have to be overrided in the deba@1414: /// subclasses. deba@1414: deba@1414: virtual void add(const std::vector& items) { deba@1414: for (int i = 0; i < (int)items.size(); ++i) { deba@1414: add(items[i]); deba@1414: } deba@1414: } klao@946: klao@946: /// \brief The member function to notificate the observer about an klao@946: /// item is erased from the container. klao@946: /// klao@946: /// The erase() member function notificates the observer about an klao@946: /// item is erased from the container. It have to be overrided in klao@946: /// the subclasses. klao@946: klao@946: virtual void erase(const Item&) = 0; klao@946: deba@1718: /// \brief The member function to notificate the observer about deba@1718: /// more item is erased from the container. deba@1718: /// deba@1718: /// The erase() member function notificates the observer about more item deba@1718: /// is erased from the container. It have to be overrided in the deba@1718: /// subclasses. deba@1414: virtual void erase(const std::vector& items) { deba@1414: for (int i = 0; i < (int)items.size(); ++i) { deba@1701: erase(items[i]); deba@1414: } deba@1414: } deba@1414: klao@946: /// \brief The member function to notificate the observer about the alpar@1204: /// container is built. klao@946: /// klao@946: /// The build() member function notificates the observer about the alpar@1204: /// container is built from an empty container. It have to be klao@946: /// overrided in the subclasses. klao@946: klao@946: virtual void build() = 0; klao@946: klao@946: /// \brief The member function to notificate the observer about all klao@946: /// items are erased from the container. klao@946: /// klao@946: /// The clear() member function notificates the observer about all klao@946: /// items are erased from the container. It have to be overrided in klao@946: /// the subclasses. klao@946: klao@946: virtual void clear() = 0; klao@946: klao@946: }; klao@946: klao@946: protected: klao@946: klao@946: klao@946: typedef std::vector Container; klao@946: klao@946: Container container; klao@946: klao@946: klao@946: public: klao@946: klao@946: /// Default constructor. klao@946: klao@946: /// deba@1038: /// The default constructor of the AlterationNotifier. klao@946: /// It creates an empty registry. deba@1038: AlterationNotifier() {} klao@946: deba@1038: /// Copy Constructor of the AlterationNotifier. klao@946: deba@1038: /// Copy constructor of the AlterationNotifier. klao@946: /// It creates only an empty registry because the copiable klao@946: /// registry's observers have to be registered still into that registry. deba@1039: AlterationNotifier(const AlterationNotifier&) {} klao@946: klao@946: /// Assign operator. klao@946: deba@1038: /// Assign operator for the AlterationNotifier. deba@1040: /// It makes the notifier only empty because the copiable deba@1040: /// notifier's observers have to be registered still into that registry. deba@1039: AlterationNotifier& operator=(const AlterationNotifier&) { klao@946: typename Container::iterator it; klao@946: for (it = container.begin(); it != container.end(); ++it) { klao@946: (*it)->registry = 0; klao@946: } klao@946: } klao@946: klao@946: /// Destructor. klao@946: deba@1038: /// Destructor of the AlterationNotifier. klao@946: /// deba@1038: ~AlterationNotifier() { klao@946: typename Container::iterator it; klao@946: for (it = container.begin(); it != container.end(); ++it) { klao@946: (*it)->registry = 0; klao@946: } klao@946: } klao@946: klao@946: klao@946: protected: klao@946: klao@946: void attach(ObserverBase& observer) { klao@946: container.push_back(&observer); klao@946: observer.registry = this; klao@946: observer.registry_index = container.size()-1; klao@946: } klao@946: klao@946: void detach(ObserverBase& base) { klao@946: container.back()->registry_index = base.registry_index; klao@946: container[base.registry_index] = container.back(); klao@946: container.pop_back(); klao@946: base.registry = 0; klao@946: } klao@946: klao@946: public: klao@946: deba@1414: /// \brief Notifies all the registered observers about an Item added to deba@1414: /// the container. deba@1414: /// deba@1414: /// It notifies all the registered observers about an Item added to deba@1414: /// the container. klao@946: /// deba@1414: void add(const Item& item) { klao@946: typename Container::iterator it; deba@1979: try { deba@1979: for (it = container.begin(); it != container.end(); ++it) { deba@1979: (*it)->add(item); deba@1979: } deba@1979: } catch (...) { deba@1979: typename Container::iterator jt; deba@1979: for (jt = container.begin(); jt != it; ++it) { deba@1979: (*it)->erase(item); deba@1979: } deba@1979: throw; klao@946: } klao@946: } klao@946: deba@1414: /// \brief Notifies all the registered observers about more Item added to deba@1414: /// the container. deba@1414: /// deba@1414: /// It notifies all the registered observers about more Item added to deba@1414: /// the container. deba@1414: /// deba@1414: void add(const std::vector& items) { deba@1414: typename Container::iterator it; deba@1979: try { deba@1979: for (it = container.begin(); it != container.end(); ++it) { deba@1979: (*it)->add(items); deba@1979: } deba@1979: } catch (...) { deba@1979: typename Container::iterator jt; deba@1979: for (jt = container.begin(); jt != it; ++it) { deba@1979: (*it)->erase(items); deba@1979: } deba@1979: throw; deba@1414: } deba@1414: } deba@1414: deba@1414: /// \brief Notifies all the registered observers about an Item erased from deba@1414: /// the container. deba@1414: /// deba@1414: /// It notifies all the registered observers about an Item erased from deba@1414: /// the container. klao@946: /// klao@946: void erase(const Item& key) { klao@946: typename Container::iterator it; klao@946: for (it = container.begin(); it != container.end(); ++it) { klao@946: (*it)->erase(key); klao@946: } klao@946: } deba@1414: deba@1414: /// \brief Notifies all the registered observers about more Item erased deba@1414: /// from the container. deba@1414: /// deba@1414: /// It notifies all the registered observers about more Item erased from deba@1414: /// the container. deba@1414: /// deba@1414: void erase(const std::vector& items) { deba@1414: typename Container::iterator it; deba@1414: for (it = container.begin(); it != container.end(); ++it) { deba@1414: (*it)->erase(items); deba@1414: } deba@1414: } klao@946: deba@1414: /// \brief Notifies all the registered observers about the container is deba@1414: /// built. deba@1414: /// alpar@1204: /// Notifies all the registered observers about the container is built klao@946: /// from an empty container. klao@946: void build() { klao@946: typename Container::iterator it; deba@1979: try { deba@1979: for (it = container.begin(); it != container.end(); ++it) { deba@1979: (*it)->build(); deba@1979: } deba@1979: } catch (...) { deba@1979: typename Container::iterator jt; deba@1979: for (jt = container.begin(); jt != it; ++it) { deba@1979: (*it)->clear(); deba@1979: } deba@1979: throw; klao@946: } klao@946: } klao@946: klao@946: deba@1414: /// \brief Notifies all the registered observers about all Items are deba@1414: /// erased. deba@1414: /// klao@946: /// Notifies all the registered observers about all Items are erased klao@946: /// from the container. klao@946: void clear() { klao@946: typename Container::iterator it; klao@946: for (it = container.begin(); it != container.end(); ++it) { klao@946: (*it)->clear(); klao@946: } klao@946: } klao@946: }; klao@946: klao@946: klao@946: /// @} klao@946: klao@946: klao@946: } klao@946: klao@946: #endif