Ipopt  trunk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
IpObserver.hpp
Go to the documentation of this file.
00001 // Copyright (C) 2004, 2006 International Business Machines and others.
00002 // All Rights Reserved.
00003 // This code is published under the Eclipse Public License.
00004 //
00005 // $Id$
00006 //
00007 // Authors:  Carl Laird, Andreas Waechter     IBM    2004-08-13
00008 
00009 #ifndef __IPOBSERVER_HPP__
00010 #define __IPOBSERVER_HPP__
00011 
00012 #include "IpUtils.hpp"
00013 #include <vector>
00014 #include <algorithm>
00015 
00016 //#define IP_DEBUG_OBSERVER
00017 #if COIN_IPOPT_CHECKLEVEL > 2
00018 # define IP_DEBUG_OBSERVER
00019 #endif
00020 #ifdef IP_DEBUG_OBSERVER
00021 # include "IpDebug.hpp"
00022 #endif
00023 
00024 namespace Ipopt
00025 {
00027   class Subject;
00028 
00039   class Observer
00040   {
00041   public:
00042 #ifdef IP_DEBUG_OBSERVER
00043 
00044     static const Index dbg_verbosity;
00045 #endif
00046 
00050     Observer()
00051     {}
00052 
00054     inline
00055     virtual ~Observer();
00057 
00059     enum NotifyType
00060     {
00061       NT_All,
00062       NT_BeingDestroyed,
00063       NT_Changed
00064     };
00065 
00066   protected:
00072     inline
00073     void RequestAttach(NotifyType notify_type, const Subject* subject);
00074 
00080     inline
00081     void RequestDetach(NotifyType notify_type, const Subject* subject);
00082 
00087     virtual void RecieveNotification(NotifyType notify_type, const Subject* subject)=0;
00088 
00089   private:
00099     Observer(const Observer&);
00100 
00102     void operator=(const Observer&);
00104 
00107     std::vector<const Subject*> subjects_;
00108 
00115     inline
00116     void ProcessNotification(NotifyType notify_type, const Subject* subject);
00117 
00118     friend class Subject;
00119   };
00120 
00129   class Subject
00130   {
00131   public:
00132 #ifdef IP_DEBUG_OBSERVER
00133 
00134     static const Index dbg_verbosity;
00135 #endif
00136 
00140     Subject()
00141     {}
00142 
00144     inline
00145     virtual ~Subject();
00147 
00159 
00162     inline
00163     void AttachObserver(Observer::NotifyType notify_type, Observer* observer) const;
00164 
00167     inline
00168     void DetachObserver(Observer::NotifyType notify_type, Observer* observer) const;
00170 
00171   protected:
00172 
00173     inline
00174     void Notify(Observer::NotifyType notify_type) const;
00175 
00176   private:
00186     Subject(const Subject&);
00187 
00189     void operator=(const Subject&);
00191 
00192     mutable std::vector<Observer*> observers_;
00193 
00194   };
00195 
00196   /* inline methods */
00197   inline
00198   Observer::~Observer()
00199   {
00200 #ifdef IP_DEBUG_OBSERVER
00201     DBG_START_METH("Observer::~Observer", dbg_verbosity);
00202     if (DBG_VERBOSITY()>=1) {
00203       for (Index i=0; i<(Index)subjects_.size(); i++) {
00204         DBG_PRINT((1,"subjects_[%d] = 0x%x\n", i, subjects_[i]));
00205       }
00206     }
00207 #endif
00208     // Detach all subjects
00209     for (Int i=(Int)(subjects_.size()-1); i>=0; i--) {
00210 #ifdef IP_DEBUG_OBSERVER
00211       DBG_PRINT((1,"About to detach subjects_[%d] = 0x%x\n", i, subjects_[i]));
00212 #endif
00213 
00214       RequestDetach(NT_All, subjects_[i]);
00215     }
00216   }
00217 
00218   inline
00219   void Observer::RequestAttach(NotifyType notify_type, const Subject* subject)
00220   {
00221 #ifdef IP_DEBUG_OBSERVER
00222     DBG_START_METH("Observer::RequestAttach", dbg_verbosity);
00223 
00224     // Add the subject to the list if it does not already exist
00225     std::vector<const Subject*>::iterator attached_subject;
00226     attached_subject = std::find(subjects_.begin(), subjects_.end(), subject);
00227     DBG_ASSERT(attached_subject == subjects_.end());
00228     DBG_ASSERT(subject);
00229 #endif
00230 
00231     // add the subject to the list
00232     subjects_.push_back(subject);
00233     // Attach the observer to the subject
00234     subject->AttachObserver(notify_type, this);
00235   }
00236 
00237   inline
00238   void Observer::RequestDetach(NotifyType notify_type, const Subject* subject)
00239   {
00240 #ifdef IP_DEBUG_OBSERVER
00241     DBG_START_METH("Observer::RequestDetach", dbg_verbosity);
00242     DBG_PRINT((1, "Requesting detach of subject: 0x%x\n", subject));
00243     DBG_ASSERT(subject);
00244 #endif
00245 
00246     if (subject) {
00247       std::vector<const Subject*>::iterator attached_subject;
00248       attached_subject = std::find(subjects_.begin(), subjects_.end(), subject);
00249 #ifdef IP_DEBUG_OBSERVER
00250 
00251       DBG_ASSERT(attached_subject != subjects_.end());
00252 #endif
00253 
00254       if (attached_subject != subjects_.end()) {
00255 #ifdef IP_DEBUG_OBSERVER
00256         DBG_PRINT((1, "Removing subject: 0x%x from the list\n", subject));
00257 #endif
00258 
00259         subjects_.erase(attached_subject);
00260       }
00261 
00262       // Detach the observer from the subject
00263       subject->DetachObserver(notify_type, this);
00264     }
00265   }
00266 
00267   inline
00268   void Observer::ProcessNotification(NotifyType notify_type, const Subject* subject)
00269   {
00270 #ifdef IP_DEBUG_OBSERVER
00271     DBG_START_METH("Observer::ProcessNotification", dbg_verbosity);
00272     DBG_ASSERT(subject);
00273 #endif
00274 
00275     if (subject) {
00276       std::vector<const Subject*>::iterator attached_subject;
00277       attached_subject = std::find(subjects_.begin(), subjects_.end(), subject);
00278 
00279       // We must be processing a notification for a
00280       // subject that was previously attached.
00281 #ifdef IP_DEBUG_OBSERVER
00282 
00283       DBG_ASSERT(attached_subject != subjects_.end());
00284 #endif
00285 
00286       this->RecieveNotification(notify_type, subject);
00287 
00288       if (notify_type == NT_BeingDestroyed) {
00289         // the subject is going away, remove it from our list
00290         subjects_.erase(attached_subject);
00291       }
00292     }
00293   }
00294 
00295   inline
00296   Subject::~Subject()
00297   {
00298 #ifdef IP_DEBUG_OBSERVER
00299     DBG_START_METH("Subject::~Subject", dbg_verbosity);
00300 #endif
00301 
00302     std::vector<Observer*>::iterator iter;
00303     for (iter = observers_.begin(); iter != observers_.end(); iter++) {
00304       (*iter)->ProcessNotification(Observer::NT_BeingDestroyed, this);
00305     }
00306   }
00307 
00308   inline
00309   void Subject::AttachObserver(Observer::NotifyType notify_type, Observer* observer) const
00310   {
00311 #ifdef IP_DEBUG_OBSERVER
00312     DBG_START_METH("Subject::AttachObserver", dbg_verbosity);
00313     // current implementation notifies all observers of everything
00314     // they must filter the notifications that they are not interested
00315     // in (i.e. a hub, not a router)
00316     DBG_ASSERT(observer);
00317 
00318     std::vector<Observer*>::iterator attached_observer;
00319     attached_observer = std::find(observers_.begin(), observers_.end(), observer);
00320     DBG_ASSERT(attached_observer == observers_.end());
00321 
00322     DBG_ASSERT(observer);
00323 #endif
00324 
00325     observers_.push_back(observer);
00326   }
00327 
00328   inline
00329   void Subject::DetachObserver(Observer::NotifyType notify_type, Observer* observer) const
00330   {
00331 #ifdef IP_DEBUG_OBSERVER
00332     DBG_START_METH("Subject::DetachObserver", dbg_verbosity);
00333     DBG_ASSERT(observer);
00334 #endif
00335 
00336     if (observer) {
00337       std::vector<Observer*>::iterator attached_observer;
00338       attached_observer = std::find(observers_.begin(), observers_.end(), observer);
00339 #ifdef IP_DEBUG_OBSERVER
00340 
00341       DBG_ASSERT(attached_observer != observers_.end());
00342 #endif
00343 
00344       if (attached_observer != observers_.end()) {
00345         observers_.erase(attached_observer);
00346       }
00347     }
00348   }
00349 
00350   inline
00351   void Subject::Notify(Observer::NotifyType notify_type) const
00352   {
00353 #ifdef IP_DEBUG_OBSERVER
00354     DBG_START_METH("Subject::Notify", dbg_verbosity);
00355 #endif
00356 
00357     std::vector<Observer*>::iterator iter;
00358     for (iter = observers_.begin(); iter != observers_.end(); iter++) {
00359       (*iter)->ProcessNotification(notify_type, this);
00360     }
00361   }
00362 
00363 
00364 } // namespace Ipopt
00365 
00366 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines