00001 /* 00002 * Copyright (C) Sergey P. Derevyago, 2003-2004. 00003 * 00004 * Permission to copy, use, modify, sell and distribute this software is granted 00005 * provided this copyright notice appears in all copies. 00006 * This software is provided "as is" without express or implied warranty, and 00007 * with no claim as to its suitability for any purpose. 00008 * 00009 */ 00010 00015 #ifndef __PUBSUB_HPP__ 00016 #define __PUBSUB_HPP__ 00017 00018 #include <list> 00019 00024 namespace PubSub_private { 00025 00031 struct PubImpl { 00033 typedef std::list<void*> list_type; 00035 list_type subs; 00036 00038 bool subscribe(void* sub); 00039 00041 bool unsubscribe(void* sub); 00042 00044 bool isSubscribed(void* sub) const; 00045 00047 int subCount() const { return subs.size(); } 00048 }; 00049 00050 } 00051 00052 template<class M> class Subscriber; 00053 00064 template<class M> 00065 class Publisher { 00066 friend class Subscriber<M>; 00067 00069 PubSub_private::PubImpl impl; 00070 00072 Publisher(const Publisher&); 00074 Publisher& operator=(const Publisher&); 00075 00076 public: 00080 Publisher() {} 00081 00087 virtual ~Publisher(); 00088 00094 bool subscribe(Subscriber<M>& sub); 00095 00102 bool unsubscribe(Subscriber<M>& sub); 00103 00107 bool isSubscribed(Subscriber<M>& sub) const 00108 { 00109 return impl.isSubscribed(&sub); 00110 } 00111 00115 int subCount() const { return impl.subCount(); } 00116 00124 int send(const M& msg); 00125 }; 00126 00135 template<class M> 00136 class Subscriber { 00137 friend class Publisher<M>; 00138 00140 typedef typename std::list<Publisher<M>*> list_type; 00142 list_type pubs; 00143 00145 Subscriber(const Subscriber&); 00147 Subscriber& operator=(const Subscriber&); 00148 00149 public: 00153 Subscriber() {} 00154 00160 virtual ~Subscriber(); 00161 00171 virtual bool regularMsg(const Publisher<M>& pub, const M& msg); 00172 00180 virtual void subscribedMsg(const Publisher<M>& pub); 00181 00189 virtual void unsubscribedMsg(const Publisher<M>& pub); 00190 }; 00191 00192 template<class M> 00193 Publisher<M>::~Publisher() 00194 { 00195 for (PubSub_private::PubImpl::list_type::const_iterator cit=impl.subs.begin(), 00196 cend=impl.subs.end(); cit!=cend; ++cit) { 00197 Subscriber<M>* psub=static_cast<Subscriber<M>*>(*cit); 00198 psub->pubs.remove(this); 00199 00200 try { psub->unsubscribedMsg(*this); } 00201 catch (...) {} // игнорируем 00202 } 00203 } 00204 00205 template<class M> 00206 bool Publisher<M>::subscribe(Subscriber<M>& sub) 00207 { 00208 bool ret=impl.subscribe(&sub); 00209 00210 if (ret) { 00211 sub.pubs.push_back(this); 00212 00213 try { sub.subscribedMsg(*this); } 00214 catch (...) {} // игнорируем 00215 } 00216 00217 return ret; 00218 } 00219 00220 template<class M> 00221 bool Publisher<M>::unsubscribe(Subscriber<M>& sub) 00222 { 00223 bool ret=impl.unsubscribe(&sub); 00224 00225 if (ret) { 00226 sub.pubs.remove(this); 00227 00228 try { sub.unsubscribedMsg(*this); } 00229 catch (...) {} // игнорируем 00230 } 00231 00232 return ret; 00233 } 00234 00235 template<class M> 00236 int Publisher<M>::send(const M& msg) 00237 { 00238 int count=0; 00239 for (PubSub_private::PubImpl::list_type::iterator it=impl.subs.begin(), 00240 end=impl.subs.end(); it!=end; count++) { 00241 Subscriber<M>* psub=static_cast<Subscriber<M>*>(*it); 00242 00243 bool ret=1; 00244 try { ret=psub->regularMsg(*this, msg); } 00245 catch (...) {} // игнорируем 00246 00247 ++it; 00248 if (!ret) unsubscribe(*psub); 00249 } 00250 00251 return count; 00252 } 00253 00254 template<class M> 00255 Subscriber<M>::~Subscriber() 00256 { 00257 for (typename list_type::const_iterator cit=pubs.begin(), cend=pubs.end(); 00258 cit!=cend; ++cit) { 00259 (*cit)->impl.unsubscribe(this); 00260 } 00261 } 00262 00263 template<class M> 00264 bool Subscriber<M>::regularMsg(const Publisher<M>&, const M&) 00265 { 00266 return 1; 00267 } 00268 00269 template<class M> 00270 void Subscriber<M>::subscribedMsg(const Publisher<M>&) 00271 { 00272 } 00273 00274 template<class M> 00275 void Subscriber<M>::unsubscribedMsg(const Publisher<M>&) 00276 { 00277 } 00278 00279 #endif