$search
00001 00010 /***************************************************************************** 00011 ** Ifdefs 00012 *****************************************************************************/ 00013 00014 #ifndef ECL_SIGSLOTS_SIGSLOT_HPP_ 00015 #define ECL_SIGSLOTS_SIGSLOT_HPP_ 00016 00017 /***************************************************************************** 00018 ** Includes 00019 *****************************************************************************/ 00020 00021 #include <map> 00022 #include <set> 00023 #include <string> 00024 #include <ecl/config/macros.hpp> 00025 #include <ecl/threads/mutex.hpp> 00026 #include <ecl/utilities/function_objects.hpp> 00027 #include <ecl/utilities/void.hpp> 00028 #include "manager.hpp" 00029 00030 /***************************************************************************** 00031 ** Namespaces 00032 *****************************************************************************/ 00033 00034 namespace ecl { 00035 00036 /***************************************************************************** 00037 ** Interface [General] 00038 *****************************************************************************/ 00045 template <typename Data=Void> 00046 class ECL_PUBLIC SigSlot { 00047 public: 00048 /********************* 00049 ** Typedefs 00050 **********************/ 00051 typedef typename Topic<Data>::Subscribers Subscribers; 00052 typedef typename std::map<std::string, const Subscribers*> PublicationMap; 00054 /********************* 00055 ** C&D 00056 **********************/ 00061 SigSlot() : processing_count(0), number_of_handles(1) { 00062 function = new PartiallyBoundUnaryMemberFunction< SigSlot<Data> ,Data,void >( &SigSlot<Data>::emit, *this); 00063 } 00069 SigSlot(void (*f)(Data)) : processing_count(0), number_of_handles(1) { 00070 function = new UnaryFreeFunction<Data>(f); 00071 } 00079 template<typename C> 00080 SigSlot(void (C::*f)(Data), C &c) : processing_count(0), number_of_handles(1) { 00081 function = new PartiallyBoundUnaryMemberFunction<C,Data,void>(f,c); 00082 } 00083 00091 ~SigSlot(); 00092 00093 const unsigned int& handles() const { return number_of_handles; } 00094 void incrHandles() { ++number_of_handles; } 00095 void decrHandles() { --number_of_handles; } 00102 void emit(Data data); 00109 void process(Data data); 00117 void connectSignal(const std::string& topic); 00125 void connectSlot(const std::string& topic); 00129 void disconnect(const std::string &topic); 00135 void disconnect(); 00136 00137 const std::set<std::string>& subscribedTopics() { return subscriptions; } 00138 00139 private: 00140 Mutex mutex; 00141 unsigned int processing_count; // number of running process()' 00142 unsigned int number_of_handles; // number of handles to this sigslot (allows copying) 00143 std::set<std::string> subscriptions; // topics this sigslot is listening to 00144 PublicationMap publications; // topics this sigslot is posting to, as well as the subscribers on the other end 00145 00146 UnaryFunction<Data,void> *function; 00147 }; 00148 00149 /***************************************************************************** 00150 ** Implementation [General] 00151 *****************************************************************************/ 00152 template<typename Data> 00153 SigSlot<Data>::~SigSlot() { 00154 disconnect(); // stop any new processing from connected signals 00155 mutex.lock(); // acts like a barrier - holds up here if function still processing stuff. 00156 delete function; 00157 } 00158 00159 template<typename Data> 00160 void SigSlot<Data>::emit(Data data) { 00161 typename PublicationMap::const_iterator topic_iter; 00162 typename Subscribers::const_iterator slots_iter; 00163 for ( topic_iter = publications.begin(); topic_iter != publications.end(); ++topic_iter ) { 00164 const Subscribers* subscribers = topic_iter->second; 00165 for ( slots_iter = subscribers->begin(); slots_iter != subscribers->end(); ++slots_iter ) { 00166 SigSlot<Data> *sigslot = *slots_iter; 00167 sigslot->process(data); 00168 } 00169 } 00170 }; 00171 00172 template<typename Data> 00173 void SigSlot<Data>::process(Data data) { 00174 mutex.trylock(); // Only lock if its not already locked. 00175 ++processing_count; 00176 (*function)(data); 00177 if ( --processing_count == 0 ) { 00178 mutex.unlock(); 00179 } 00180 00181 } 00182 00183 template<typename Data> 00184 void SigSlot<Data>::connectSignal(const std::string& topic) { 00185 // Logic: 00186 // - if already publishing to this topic 00187 // - don't do anything 00188 // - else 00189 // - if topic doesn't exist 00190 // - Manager will automatically create a new topic 00191 // - Manager returns the subscribers handle 00192 // - Topic name and subscribers handle are stored locally here in publications 00193 publications.insert( std::pair<std::string, const Subscribers*>(topic, SigSlotsManager<Data>::connectSignal(topic,this)) ); 00194 } 00195 00196 template<typename Data> 00197 void SigSlot<Data>::connectSlot(const std::string& topic) { 00198 std::pair< std::set<std::string>::iterator,bool > ret; 00199 // std::cout << "Topic: " << topic << std::endl; 00200 ret = subscriptions.insert(topic); // Doesn't matter if it already exists. 00201 if ( ret.second ) { 00202 SigSlotsManager<Data>::connectSlot(topic,this); 00203 } // else { already subscribed to this topic } 00204 } 00205 template<typename Data> 00206 void SigSlot<Data>::disconnect(const std::string &topic) { 00207 std::set<std::string>::const_iterator listen_iter = subscriptions.find(topic); 00208 publications.erase(topic); // Doesn't matter if it finds it or not. 00209 SigSlotsManager<Void>::disconnect(topic,this); 00210 } 00211 00212 template<typename Data> 00213 void SigSlot<Data>::disconnect() { 00214 std::set<std::string>::iterator iter; 00215 for ( iter = subscriptions.begin(); iter != subscriptions.end(); ++iter ) { 00216 SigSlotsManager<Data>::disconnect(*iter, this); 00217 } 00218 subscriptions.clear(); 00219 typename std::map<std::string,const Subscribers*>::iterator emit_iter; 00220 for ( emit_iter = publications.begin(); emit_iter != publications.end(); ++emit_iter ) { 00221 SigSlotsManager<Data>::disconnect(emit_iter->first, this); 00222 } 00223 publications.clear(); 00224 } 00225 00226 /***************************************************************************** 00227 ** Interface [Void] 00228 *****************************************************************************/ 00229 00237 template<> 00238 class ECL_PUBLIC SigSlot<Void> { 00239 public: 00240 // typedef std::set<SigSlot<Void>*> Subscribers 00241 typedef Topic<Void>::Subscribers Subscribers; 00242 typedef std::map<std::string, const Subscribers*> PublicationMap; 00248 SigSlot() : processing_count(0), number_of_handles(1) { 00249 function = new BoundNullaryMemberFunction<SigSlot,void>(&SigSlot::emit,*this); 00250 } 00256 SigSlot(VoidFunction f) : processing_count(0), number_of_handles(1) { 00257 function = new NullaryFreeFunction<void>(f); 00258 } 00266 template<typename C> 00267 SigSlot(void (C::*f)(void), C &c) : processing_count(0), number_of_handles(1) { 00268 function = new BoundNullaryMemberFunction<C,void>(f,c); 00269 } 00270 00278 ~SigSlot(); 00279 00280 const unsigned int& handles() const { return number_of_handles; } 00281 void incrHandles() { ++number_of_handles; } 00282 void decrHandles() { --number_of_handles; } 00289 void emit(); 00296 void process(Void void_arg = Void()); 00304 void connectSignal(const std::string& topic); 00308 void connectSlot(const std::string& topic); 00316 void disconnect(const std::string &topic); 00322 void disconnect(); 00323 00324 private: 00325 Mutex mutex; 00326 unsigned int processing_count; // number of running process()' 00327 unsigned int number_of_handles; // number of handles to this sigslot (allows copying) 00328 std::set<std::string> subscriptions; // topics this sigslot is listening to 00329 PublicationMap publications; // topics this sigslot is posting to, as well as the subscribers on the other end 00330 00331 NullaryFunction<void> *function; 00332 }; 00333 00334 } // namespace ecl 00335 00336 #endif /* ECL_SIGSLOTS_SIGSLOT_HPP_ */