// Copyright (C) 2004, 2006 International Business Machines and others. // All Rights Reserved. // This code is published under the Common Public License. // // $Id: IpObserver.hpp 1019 2007-06-24 03:52:34Z andreasw $ // // Authors: Carl Laird, Andreas Waechter IBM 2004-08-13 #ifndef __IPOBSERVER_HPP__ #define __IPOBSERVER_HPP__ #include "IpUtils.hpp" #include #include //#define IP_DEBUG_OBSERVER #if COIN_IPOPT_CHECKLEVEL > 2 # define IP_DEBUG_OBSERVER #endif #ifdef IP_DEBUG_OBSERVER # include "IpDebug.hpp" #endif namespace Ipopt { /** Forward declarations */ class Subject; /** Slight Variation of the Observer Design Pattern. * This class implements the Observer class of the * Observer Design Pattern. An Observer "Attach"es * to a Subject, indicating that it would like to * be notified of changes in the Subject. * Any derived class wishing to recieve notifications * from a Subject should inherit off of * Observer and overload the protected method, * RecieveNotification_(...). */ class Observer { public: #ifdef IP_DEBUG_OBSERVER static const Index dbg_verbosity; #endif /**@name Constructors/Destructors */ //@{ /** Default Constructor */ Observer() {} /** Default destructor */ virtual ~Observer(); //@} /** Enumeration specifying the type of notification */ enum NotifyType { NT_All, NT_BeingDestroyed, NT_Changed }; protected: /** Derived classes should call this method * to request an "Attach" to a Subject. Do * not call "Attach" explicitly on the Subject * since further processing is done here */ void RequestAttach(NotifyType notify_type, const Subject* subject); /** Derived classes should call this method * to request a "Detach" to a Subject. Do * not call "Detach" explicitly on the Subject * since further processing is done here */ void RequestDetach(NotifyType notify_type, const Subject* subject); /** Derived classes should overload this method to * recieve the requested notification from * attached Subjects */ virtual void RecieveNotification(NotifyType notify_type, const Subject* subject)=0; private: /**@name Default Compiler Generated Methods * (Hidden to avoid implicit creation/calling). * These methods are not implemented and * we do not want the compiler to implement * them for us, so we declare them private * and do not define them. This ensures that * they will not be implicitly created/called. */ //@{ /** Copy Constructor */ Observer(const Observer&); /** Overloaded Equals Operator */ void operator=(const Observer&); //@} /** A list of the subjects currently being * observed. */ std::vector subjects_; /** Private Method for Recieving Notification * should only be called by the friend class * Subject. This method will, in turn, call * the overloaded RecieveNotification method * for the derived class to process. */ void ProcessNotification(NotifyType notify_type, const Subject* subject); friend class Subject; }; /** Slight Variation of the Observer Design Pattern (Subject part). * This class implements the Subject class of the Observer Design * Pattern. An Observer "Attach"es to a Subject, indicating that it * would like to be notified of changes in the Subject. Any * derived class that is to be observed has to inherit off the * Subject base class. If the subject needs to notify the * Observer, it calls the Notify method. */ class Subject { public: #ifdef IP_DEBUG_OBSERVER static const Index dbg_verbosity; #endif /**@name Constructors/Destructors */ //@{ /** Default Constructor */ Subject() {} /** Default destructor */ virtual ~Subject(); //@} /**@name Methods to Add and Remove Observers. * Currently, the notify_type flags are not used, * and Observers are attached in general and will * recieve all notifications (of the type requested * and possibly of types not requested). It is * up to the observer to ignore the types they * are not interested in. The NotifyType in the * parameter list is so a more efficient mechanism * depending on type could be implemented later if * necessary.*/ //@{ /** Attach the specified observer * (i.e., begin recieving notifications). */ void AttachObserver(Observer::NotifyType notify_type, Observer* observer) const; /** Detach the specified observer * (i.e., no longer recieve notifications). */ void DetachObserver(Observer::NotifyType notify_type, Observer* observer) const; //@} protected: void Notify(Observer::NotifyType notify_type) const; private: /**@name Default Compiler Generated Methods * (Hidden to avoid implicit creation/calling). * These methods are not implemented and * we do not want the compiler to implement * them for us, so we declare them private * and do not define them. This ensures that * they will not be implicitly created/called. */ //@{ /** Copy Constructor */ Subject(const Subject&); /** Overloaded Equals Operator */ void operator=(const Subject&); //@} mutable std::vector observers_; }; /* inline methods */ inline Observer::~Observer() { #ifdef IP_DEBUG_OBSERVER DBG_START_METH("Observer::~Observer", dbg_verbosity); if (DBG_VERBOSITY()>=1) { for (Index i=0; i<(Index)subjects_.size(); i++) { DBG_PRINT((1,"subjects_[%d] = 0x%x\n", i, subjects_[i])); } } #endif // Detach all subjects for (Int i=(Int)(subjects_.size()-1); i>=0; i--) { #ifdef IP_DEBUG_OBSERVER DBG_PRINT((1,"About to detach subjects_[%d] = 0x%x\n", i, subjects_[i])); #endif RequestDetach(NT_All, subjects_[i]); } } inline void Observer::RequestAttach(NotifyType notify_type, const Subject* subject) { #ifdef IP_DEBUG_OBSERVER DBG_START_METH("Observer::RequestAttach", dbg_verbosity); // Add the subject to the list if it does not already exist std::vector::iterator attached_subject; attached_subject = std::find(subjects_.begin(), subjects_.end(), subject); DBG_ASSERT(attached_subject == subjects_.end()); DBG_ASSERT(subject); #endif // add the subject to the list subjects_.push_back(subject); // Attach the observer to the subject subject->AttachObserver(notify_type, this); } inline void Observer::RequestDetach(NotifyType notify_type, const Subject* subject) { #ifdef IP_DEBUG_OBSERVER DBG_START_METH("Observer::RequestDetach", dbg_verbosity); DBG_PRINT((1, "Requesting detach of subject: 0x%x\n", subject)); DBG_ASSERT(subject); #endif if (subject) { std::vector::iterator attached_subject; attached_subject = std::find(subjects_.begin(), subjects_.end(), subject); #ifdef IP_DEBUG_OBSERVER DBG_ASSERT(attached_subject != subjects_.end()); #endif if (attached_subject != subjects_.end()) { #ifdef IP_DEBUG_OBSERVER DBG_PRINT((1, "Removing subject: 0x%x from the list\n", subject)); #endif subjects_.erase(attached_subject); } // Detach the observer from the subject subject->DetachObserver(notify_type, this); } } inline void Observer::ProcessNotification(NotifyType notify_type, const Subject* subject) { #ifdef IP_DEBUG_OBSERVER DBG_START_METH("Observer::ProcessNotification", dbg_verbosity); DBG_ASSERT(subject); #endif if (subject) { std::vector::iterator attached_subject; attached_subject = std::find(subjects_.begin(), subjects_.end(), subject); // We must be processing a notification for a // subject that was previously attached. #ifdef IP_DEBUG_OBSERVER DBG_ASSERT(attached_subject != subjects_.end()); #endif this->RecieveNotification(notify_type, subject); if (notify_type == NT_BeingDestroyed) { // the subject is going away, remove it from our list subjects_.erase(attached_subject); } } } inline Subject::~Subject() { #ifdef IP_DEBUG_OBSERVER DBG_START_METH("Subject::~Subject", dbg_verbosity); #endif std::vector::iterator iter; for (iter = observers_.begin(); iter != observers_.end(); iter++) { (*iter)->ProcessNotification(Observer::NT_BeingDestroyed, this); } } inline void Subject::AttachObserver(Observer::NotifyType notify_type, Observer* observer) const { #ifdef IP_DEBUG_OBSERVER DBG_START_METH("Subject::AttachObserver", dbg_verbosity); // current implementation notifies all observers of everything // they must filter the notifications that they are not interested // in (i.e. a hub, not a router) DBG_ASSERT(observer); std::vector::iterator attached_observer; attached_observer = std::find(observers_.begin(), observers_.end(), observer); DBG_ASSERT(attached_observer == observers_.end()); DBG_ASSERT(observer); #endif observers_.push_back(observer); } inline void Subject::DetachObserver(Observer::NotifyType notify_type, Observer* observer) const { #ifdef IP_DEBUG_OBSERVER DBG_START_METH("Subject::DetachObserver", dbg_verbosity); DBG_ASSERT(observer); #endif if (observer) { std::vector::iterator attached_observer; attached_observer = std::find(observers_.begin(), observers_.end(), observer); #ifdef IP_DEBUG_OBSERVER DBG_ASSERT(attached_observer != observers_.end()); #endif if (attached_observer != observers_.end()) { observers_.erase(attached_observer); } } } inline void Subject::Notify(Observer::NotifyType notify_type) const { #ifdef IP_DEBUG_OBSERVER DBG_START_METH("Subject::Notify", dbg_verbosity); #endif std::vector::iterator iter; for (iter = observers_.begin(); iter != observers_.end(); iter++) { (*iter)->ProcessNotification(notify_type, this); } } } // namespace Ipopt #endif