Notify.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /******************************************************************************
  19. *
  20. * FILE
  21. * $Archive: /Commando/Code/wwlib/Notify.h $
  22. *
  23. * DESCRIPTION
  24. * These templates provide implementation of the Subject-Observer pattern.
  25. *
  26. * PROGRAMMER
  27. * Steve Clinard
  28. * $Author: Denzil_l $
  29. *
  30. * VERSION INFO
  31. * $Modtime: 8/04/01 12:13p $
  32. * $Revision: 4 $
  33. *
  34. ******************************************************************************/
  35. #ifndef __NOTIFY_H__
  36. #define __NOTIFY_H__
  37. // Reduce warning level for STL
  38. #if defined(_MSC_VER)
  39. #pragma warning(push, 3)
  40. #endif
  41. #include <vector>
  42. #include <algorithm>
  43. #if defined(_MSC_VER)
  44. #pragma warning(pop)
  45. #endif
  46. #include <assert.h>
  47. template<typename Event> class Notifier;
  48. template<typename Event> class Observer;
  49. template<typename Event> class Observer
  50. {
  51. public:
  52. typedef std::vector< Notifier<Event>* > NotifierColl;
  53. Observer() :
  54. mNotifiers(NULL)
  55. {}
  56. virtual ~Observer()
  57. {StopObserving();}
  58. //! Handle event notification
  59. virtual void HandleNotification(Event&) = 0;
  60. //! Notifier has ended notification of this event
  61. virtual void NotificationEnded(const Notifier<Event>& notifier)
  62. {
  63. NotifierColl::iterator pos = std::find(mNotifiers.begin(),
  64. mNotifiers.end(), &notifier);
  65. if (pos != mNotifiers.end())
  66. {
  67. mNotifiers.erase(pos);
  68. }
  69. }
  70. //! Request notification of this event
  71. virtual void NotifyMe(Notifier<Event>& notifier)
  72. {notifier.AddObserver(*this);}
  73. //! Stop observing event
  74. void StopObserving()
  75. {
  76. while (mNotifiers.size() > 0)
  77. {
  78. Notifier<Event>* notifier = mNotifiers.back();
  79. assert(notifier && "ERROR: NULL pointer in collection.");
  80. notifier->RemoveObserver(*this);
  81. }
  82. }
  83. protected:
  84. Observer(const Observer<Event>& observer);
  85. const Observer<Event>& operator=(const Observer<Event>&);
  86. private:
  87. friend class Notifier<Event>;
  88. NotifierColl mNotifiers;
  89. };
  90. #define DECLARE_OBSERVER(Event) \
  91. virtual void NotifyMe(Notifier<Event>& observer) \
  92. {Notifier<Event>::AddObserver(observer);}
  93. template<typename Event> class Notifier
  94. {
  95. public:
  96. typedef std::vector< Observer<Event>* > ObserverColl;
  97. Notifier()
  98. {}
  99. virtual ~Notifier()
  100. {
  101. for (int index = mObservers.size(); index--;)
  102. {
  103. mObservers[index]->NotificationEnded(*this);
  104. }
  105. }
  106. //! Send event notification to all observers of this event.
  107. virtual void NotifyObservers(Event& event)
  108. {
  109. for (unsigned int index = 0; index < mObservers.size(); index++)
  110. {
  111. mObservers[index]->HandleNotification(event);
  112. }
  113. }
  114. //! Add an observer of this event
  115. virtual void AddObserver(Observer<Event>& observer)
  116. {
  117. ObserverColl::iterator pos = std::find(mObservers.begin(),
  118. mObservers.end(), &observer);
  119. if (pos == mObservers.end())
  120. {
  121. observer.mNotifiers.push_back(this);
  122. mObservers.push_back(&observer);
  123. }
  124. }
  125. //! Remove an observer of this event
  126. virtual void RemoveObserver(Observer<Event>& observer)
  127. {
  128. ObserverColl::iterator pos = std::find(mObservers.begin(),
  129. mObservers.end(), &observer);
  130. if (pos != mObservers.end())
  131. {
  132. observer.NotificationEnded(*this);
  133. mObservers.erase(pos);
  134. }
  135. }
  136. virtual bool HasObservers(void) const
  137. {return (mObservers.size() > 0);}
  138. private:
  139. //! Observer collection
  140. ObserverColl mObservers;
  141. };
  142. #define DECLARE_NOTIFIER(Event) \
  143. virtual void NotifyObservers(Event& event) \
  144. {Notifier<Event>::NotifyObservers(event);} \
  145. virtual void AddObserver(Observer<Event>& observer) \
  146. {Notifier<Event>::AddObserver(observer);} \
  147. virtual void RemoveObserver(Observer<Event>& observer) \
  148. {Notifier<Event>::RemoveObserver(observer);}
  149. /* The following template is useful for defining unique types to use as Events
  150. * from types such as strings or integers.
  151. *
  152. * The first type must be a class or other unique type. This need not be a
  153. * "real" class. It could be a forward declared class, which is enough to
  154. * make the template class unique.
  155. *
  156. * The second type is the event data. UString and int are obvious choices.
  157. *
  158. * Typedef'ing the template class is a good thing to do.
  159. */
  160. template<typename Type, typename Value>
  161. class TypedEvent
  162. {
  163. public:
  164. TypedEvent(Value& value) :
  165. mValue(value)
  166. {}
  167. inline Value& operator()()
  168. {return mValue;}
  169. inline Value& Subject(void)
  170. {return mValue;}
  171. private:
  172. Value& mValue;
  173. };
  174. template<typename T, typename Object>
  175. class TypedEventPtr
  176. {
  177. public:
  178. TypedEventPtr(Object* subject) :
  179. mSubject(subject)
  180. {}
  181. inline Object* Subject(void)
  182. {return mSubject;}
  183. inline Object* operator()()
  184. {return mSubject;}
  185. private:
  186. Object* mSubject;
  187. };
  188. template<typename A, typename B>
  189. class TypedEventPair
  190. {
  191. public:
  192. TypedEventPair(A itemA, B itemB) :
  193. mItemA(itemA),
  194. mItemB(itemB)
  195. {}
  196. inline A GetItemA(void)
  197. {return mItemA;}
  198. inline B GetItemB(void)
  199. {return mItemB;}
  200. protected:
  201. A mItemA;
  202. B mItemB;
  203. };
  204. #endif // __NOTIFY_H__