IpObserver.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. // Copyright (C) 2004, 2006 International Business Machines and others.
  2. // All Rights Reserved.
  3. // This code is published under the Eclipse Public License.
  4. //
  5. // $Id: IpObserver.hpp 2161 2013-01-01 20:39:05Z stefan $
  6. //
  7. // Authors: Carl Laird, Andreas Waechter IBM 2004-08-13
  8. #ifndef __IPOBSERVER_HPP__
  9. #define __IPOBSERVER_HPP__
  10. #include "IpUtils.hpp"
  11. #include <vector>
  12. #include <algorithm>
  13. //#define IP_DEBUG_OBSERVER
  14. #if COIN_IPOPT_CHECKLEVEL > 2
  15. # define IP_DEBUG_OBSERVER
  16. #endif
  17. #ifdef IP_DEBUG_OBSERVER
  18. # include "IpDebug.hpp"
  19. #endif
  20. namespace Ipopt
  21. {
  22. /** Forward declarations */
  23. class Subject;
  24. /** Slight Variation of the Observer Design Pattern.
  25. * This class implements the Observer class of the
  26. * Observer Design Pattern. An Observer "Attach"es
  27. * to a Subject, indicating that it would like to
  28. * be notified of changes in the Subject.
  29. * Any derived class wishing to recieve notifications
  30. * from a Subject should inherit off of
  31. * Observer and overload the protected method,
  32. * RecieveNotification_(...).
  33. */
  34. class Observer
  35. {
  36. public:
  37. #ifdef IP_DEBUG_OBSERVER
  38. static const Index dbg_verbosity;
  39. #endif
  40. /**@name Constructors/Destructors */
  41. //@{
  42. /** Default Constructor */
  43. Observer()
  44. {}
  45. /** Default destructor */
  46. inline
  47. virtual ~Observer();
  48. //@}
  49. /** Enumeration specifying the type of notification */
  50. enum NotifyType
  51. {
  52. NT_All,
  53. NT_BeingDestroyed,
  54. NT_Changed
  55. };
  56. protected:
  57. /** Derived classes should call this method
  58. * to request an "Attach" to a Subject. Do
  59. * not call "Attach" explicitly on the Subject
  60. * since further processing is done here
  61. */
  62. inline
  63. void RequestAttach(NotifyType notify_type, const Subject* subject);
  64. /** Derived classes should call this method
  65. * to request a "Detach" to a Subject. Do
  66. * not call "Detach" explicitly on the Subject
  67. * since further processing is done here
  68. */
  69. inline
  70. void RequestDetach(NotifyType notify_type, const Subject* subject);
  71. /** Derived classes should overload this method to
  72. * recieve the requested notification from
  73. * attached Subjects
  74. */
  75. virtual void RecieveNotification(NotifyType notify_type, const Subject* subject)=0;
  76. private:
  77. /**@name Default Compiler Generated Methods
  78. * (Hidden to avoid implicit creation/calling).
  79. * These methods are not implemented and
  80. * we do not want the compiler to implement
  81. * them for us, so we declare them private
  82. * and do not define them. This ensures that
  83. * they will not be implicitly created/called. */
  84. //@{
  85. /** Copy Constructor */
  86. Observer(const Observer&);
  87. /** Overloaded Equals Operator */
  88. void operator=(const Observer&);
  89. //@}
  90. /** A list of the subjects currently being
  91. * observed. */
  92. std::vector<const Subject*> subjects_;
  93. /** Private Method for Recieving Notification
  94. * should only be called by the friend class
  95. * Subject. This method will, in turn, call
  96. * the overloaded RecieveNotification method
  97. * for the derived class to process.
  98. */
  99. inline
  100. void ProcessNotification(NotifyType notify_type, const Subject* subject);
  101. friend class Subject;
  102. };
  103. /** Slight Variation of the Observer Design Pattern (Subject part).
  104. * This class implements the Subject class of the Observer Design
  105. * Pattern. An Observer "Attach"es to a Subject, indicating that it
  106. * would like to be notified of changes in the Subject. Any
  107. * derived class that is to be observed has to inherit off the
  108. * Subject base class. If the subject needs to notify the
  109. * Observer, it calls the Notify method.
  110. */
  111. class Subject
  112. {
  113. public:
  114. #ifdef IP_DEBUG_OBSERVER
  115. static const Index dbg_verbosity;
  116. #endif
  117. /**@name Constructors/Destructors */
  118. //@{
  119. /** Default Constructor */
  120. Subject()
  121. {}
  122. /** Default destructor */
  123. inline
  124. virtual ~Subject();
  125. //@}
  126. /**@name Methods to Add and Remove Observers.
  127. * Currently, the notify_type flags are not used,
  128. * and Observers are attached in general and will
  129. * recieve all notifications (of the type requested
  130. * and possibly of types not requested). It is
  131. * up to the observer to ignore the types they
  132. * are not interested in. The NotifyType in the
  133. * parameter list is so a more efficient mechanism
  134. * depending on type could be implemented later if
  135. * necessary.*/
  136. //@{
  137. /** Attach the specified observer
  138. * (i.e., begin recieving notifications). */
  139. inline
  140. void AttachObserver(Observer::NotifyType notify_type, Observer* observer) const;
  141. /** Detach the specified observer
  142. * (i.e., no longer recieve notifications). */
  143. inline
  144. void DetachObserver(Observer::NotifyType notify_type, Observer* observer) const;
  145. //@}
  146. protected:
  147. inline
  148. void Notify(Observer::NotifyType notify_type) const;
  149. private:
  150. /**@name Default Compiler Generated Methods
  151. * (Hidden to avoid implicit creation/calling).
  152. * These methods are not implemented and
  153. * we do not want the compiler to implement
  154. * them for us, so we declare them private
  155. * and do not define them. This ensures that
  156. * they will not be implicitly created/called. */
  157. //@{
  158. /** Copy Constructor */
  159. Subject(const Subject&);
  160. /** Overloaded Equals Operator */
  161. void operator=(const Subject&);
  162. //@}
  163. mutable std::vector<Observer*> observers_;
  164. };
  165. /* inline methods */
  166. inline
  167. Observer::~Observer()
  168. {
  169. #ifdef IP_DEBUG_OBSERVER
  170. DBG_START_METH("Observer::~Observer", dbg_verbosity);
  171. if (DBG_VERBOSITY()>=1) {
  172. for (Index i=0; i<(Index)subjects_.size(); i++) {
  173. DBG_PRINT((1,"subjects_[%d] = 0x%x\n", i, subjects_[i]));
  174. }
  175. }
  176. #endif
  177. // Detach all subjects
  178. for (Int i=(Int)(subjects_.size()-1); i>=0; i--) {
  179. #ifdef IP_DEBUG_OBSERVER
  180. DBG_PRINT((1,"About to detach subjects_[%d] = 0x%x\n", i, subjects_[i]));
  181. #endif
  182. RequestDetach(NT_All, subjects_[i]);
  183. }
  184. }
  185. inline
  186. void Observer::RequestAttach(NotifyType notify_type, const Subject* subject)
  187. {
  188. #ifdef IP_DEBUG_OBSERVER
  189. DBG_START_METH("Observer::RequestAttach", dbg_verbosity);
  190. // Add the subject to the list if it does not already exist
  191. std::vector<const Subject*>::iterator attached_subject;
  192. attached_subject = std::find(subjects_.begin(), subjects_.end(), subject);
  193. DBG_ASSERT(attached_subject == subjects_.end());
  194. DBG_ASSERT(subject);
  195. #endif
  196. // add the subject to the list
  197. subjects_.push_back(subject);
  198. // Attach the observer to the subject
  199. subject->AttachObserver(notify_type, this);
  200. }
  201. inline
  202. void Observer::RequestDetach(NotifyType notify_type, const Subject* subject)
  203. {
  204. #ifdef IP_DEBUG_OBSERVER
  205. DBG_START_METH("Observer::RequestDetach", dbg_verbosity);
  206. DBG_PRINT((1, "Requesting detach of subject: 0x%x\n", subject));
  207. DBG_ASSERT(subject);
  208. #endif
  209. if (subject) {
  210. std::vector<const Subject*>::iterator attached_subject;
  211. attached_subject = std::find(subjects_.begin(), subjects_.end(), subject);
  212. #ifdef IP_DEBUG_OBSERVER
  213. DBG_ASSERT(attached_subject != subjects_.end());
  214. #endif
  215. if (attached_subject != subjects_.end()) {
  216. #ifdef IP_DEBUG_OBSERVER
  217. DBG_PRINT((1, "Removing subject: 0x%x from the list\n", subject));
  218. #endif
  219. subjects_.erase(attached_subject);
  220. }
  221. // Detach the observer from the subject
  222. subject->DetachObserver(notify_type, this);
  223. }
  224. }
  225. inline
  226. void Observer::ProcessNotification(NotifyType notify_type, const Subject* subject)
  227. {
  228. #ifdef IP_DEBUG_OBSERVER
  229. DBG_START_METH("Observer::ProcessNotification", dbg_verbosity);
  230. DBG_ASSERT(subject);
  231. #endif
  232. if (subject) {
  233. std::vector<const Subject*>::iterator attached_subject;
  234. attached_subject = std::find(subjects_.begin(), subjects_.end(), subject);
  235. // We must be processing a notification for a
  236. // subject that was previously attached.
  237. #ifdef IP_DEBUG_OBSERVER
  238. DBG_ASSERT(attached_subject != subjects_.end());
  239. #endif
  240. this->RecieveNotification(notify_type, subject);
  241. if (notify_type == NT_BeingDestroyed) {
  242. // the subject is going away, remove it from our list
  243. subjects_.erase(attached_subject);
  244. }
  245. }
  246. }
  247. inline
  248. Subject::~Subject()
  249. {
  250. #ifdef IP_DEBUG_OBSERVER
  251. DBG_START_METH("Subject::~Subject", dbg_verbosity);
  252. #endif
  253. std::vector<Observer*>::iterator iter;
  254. for (iter = observers_.begin(); iter != observers_.end(); iter++) {
  255. (*iter)->ProcessNotification(Observer::NT_BeingDestroyed, this);
  256. }
  257. }
  258. inline
  259. void Subject::AttachObserver(Observer::NotifyType notify_type, Observer* observer) const
  260. {
  261. #ifdef IP_DEBUG_OBSERVER
  262. DBG_START_METH("Subject::AttachObserver", dbg_verbosity);
  263. // current implementation notifies all observers of everything
  264. // they must filter the notifications that they are not interested
  265. // in (i.e. a hub, not a router)
  266. DBG_ASSERT(observer);
  267. std::vector<Observer*>::iterator attached_observer;
  268. attached_observer = std::find(observers_.begin(), observers_.end(), observer);
  269. DBG_ASSERT(attached_observer == observers_.end());
  270. DBG_ASSERT(observer);
  271. #endif
  272. observers_.push_back(observer);
  273. }
  274. inline
  275. void Subject::DetachObserver(Observer::NotifyType notify_type, Observer* observer) const
  276. {
  277. #ifdef IP_DEBUG_OBSERVER
  278. DBG_START_METH("Subject::DetachObserver", dbg_verbosity);
  279. DBG_ASSERT(observer);
  280. #endif
  281. if (observer) {
  282. std::vector<Observer*>::iterator attached_observer;
  283. attached_observer = std::find(observers_.begin(), observers_.end(), observer);
  284. #ifdef IP_DEBUG_OBSERVER
  285. DBG_ASSERT(attached_observer != observers_.end());
  286. #endif
  287. if (attached_observer != observers_.end()) {
  288. observers_.erase(attached_observer);
  289. }
  290. }
  291. }
  292. inline
  293. void Subject::Notify(Observer::NotifyType notify_type) const
  294. {
  295. #ifdef IP_DEBUG_OBSERVER
  296. DBG_START_METH("Subject::Notify", dbg_verbosity);
  297. #endif
  298. std::vector<Observer*>::iterator iter;
  299. for (iter = observers_.begin(); iter != observers_.end(); iter++) {
  300. (*iter)->ProcessNotification(notify_type, this);
  301. }
  302. }
  303. } // namespace Ipopt
  304. #endif