Go to the documentation of this file.00001 
00010 
00011 
00012 
00013 
00014 #ifndef ECL_SIGSLOTS_SIGSLOT_HPP_
00015 #define ECL_SIGSLOTS_SIGSLOT_HPP_
00016 
00017 
00018 
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 
00032 
00033 
00034 namespace ecl {
00035 
00036 
00037 
00038 
00045 template <typename Data=Void>
00046 class SigSlot {
00047 public:
00048         
00049 
00050 
00051         typedef typename Topic<Data>::Subscribers Subscribers; 
00052         typedef typename std::map<std::string, const Subscribers*> PublicationMap; 
00054         
00055 
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                 disconnect(); 
00093                 mutex.lock(); 
00094                 delete function;
00095         }
00096 
00097         const unsigned int& handles() const { return number_of_handles; } 
00098         void incrHandles() { ++number_of_handles; } 
00099         void decrHandles() { --number_of_handles; } 
00106         void emit(Data data) {
00107                 typename PublicationMap::const_iterator topic_iter;
00108                 typename Subscribers::const_iterator slots_iter;
00109                 for ( topic_iter = publications.begin(); topic_iter != publications.end(); ++topic_iter ) {
00110                         const Subscribers* subscribers = topic_iter->second;
00111                         for ( slots_iter = subscribers->begin(); slots_iter != subscribers->end(); ++slots_iter ) {
00112                                 SigSlot<Data> *sigslot = *slots_iter;
00113                                 sigslot->process(data);
00114                         }
00115                 }
00116         }
00123         void process(Data data) {
00124                 mutex.trylock(); 
00125                 ++processing_count;
00126                 (*function)(data);
00127                 if ( --processing_count == 0 ) {
00128                         mutex.unlock();
00129                 }
00130         }
00138         void connectSignal(const std::string& topic) {
00139                 
00140                 
00141                 
00142                 
00143                 
00144                 
00145                 
00146                 
00147                 publications.insert( std::pair<std::string, const Subscribers*>(topic, SigSlotsManager<Data>::connectSignal(topic,this)) );
00148         }
00156         void connectSlot(const std::string& topic) {
00157                 std::pair< std::set<std::string>::iterator,bool > ret;
00158         
00159                 ret = subscriptions.insert(topic); 
00160                 if ( ret.second ) {
00161                         SigSlotsManager<Data>::connectSlot(topic,this);
00162                 } 
00163         }
00167         void disconnect(const std::string &topic) {
00168                 std::set<std::string>::const_iterator listen_iter = subscriptions.find(topic);
00169                 publications.erase(topic); 
00170                 SigSlotsManager<Void>::disconnect(topic,this);
00171         }
00177         void disconnect() {
00178                 std::set<std::string>::iterator iter;
00179                 for ( iter = subscriptions.begin(); iter != subscriptions.end(); ++iter ) {
00180                         SigSlotsManager<Data>::disconnect(*iter, this);
00181                 }
00182                 subscriptions.clear();
00183                 typename std::map<std::string,const Subscribers*>::iterator emit_iter;
00184                 for ( emit_iter = publications.begin(); emit_iter != publications.end(); ++emit_iter ) {
00185                         SigSlotsManager<Data>::disconnect(emit_iter->first, this);
00186                 }
00187                 publications.clear();
00188         }
00189 
00190         const std::set<std::string>& subscribedTopics() { return subscriptions; }
00191 
00192 private:
00193         Mutex mutex;
00194         unsigned int processing_count; 
00195         unsigned int number_of_handles; 
00196         std::set<std::string> subscriptions; 
00197         PublicationMap publications; 
00198 
00199         UnaryFunction<Data,void> *function;
00200 };
00201 
00202 
00203 
00204 
00205 
00213 template<>
00214 class SigSlot<Void> {
00215 public:
00216         
00217         typedef Topic<Void>::Subscribers Subscribers; 
00218         typedef std::map<std::string, const Subscribers*> PublicationMap; 
00224         SigSlot() : processing_count(0), number_of_handles(1) {
00225                 function = new BoundNullaryMemberFunction<SigSlot,void>(&SigSlot::emit,*this);
00226         }
00232         SigSlot(VoidFunction f) : processing_count(0), number_of_handles(1) {
00233                 function = new NullaryFreeFunction<void>(f);
00234         }
00242         template<typename C>
00243         SigSlot(void (C::*f)(void), C &c) : processing_count(0), number_of_handles(1) {
00244                 function = new BoundNullaryMemberFunction<C,void>(f,c);
00245         }
00246 
00254         ~SigSlot() {
00255                 disconnect(); 
00256                 mutex.lock(); 
00257                 delete function;
00258         }
00259 
00260         const unsigned int& handles() const { return number_of_handles; } 
00261         void incrHandles() { ++number_of_handles; } 
00262         void decrHandles() { --number_of_handles; } 
00269         void emit() {
00270                 PublicationMap::const_iterator topic_iter;
00271                 Subscribers::const_iterator slots_iter;
00272                 for ( topic_iter = publications.begin(); topic_iter != publications.end(); ++topic_iter ) {
00273                         const Subscribers* subscribers = topic_iter->second;
00274                         for ( slots_iter = subscribers->begin(); slots_iter != subscribers->end(); ++slots_iter ) {
00275                                 SigSlot *sigslot = *slots_iter;
00276                                 sigslot->process();
00277                         }
00278                 }
00279         }
00286         void process(Void void_arg = Void()) {
00287                 mutex.trylock(); 
00288                 ++processing_count;
00289                 (*function)();
00290                 if ( --processing_count == 0 ) {
00291                         mutex.unlock();
00292                 }
00293         }
00301         void connectSignal(const std::string& topic) {
00302                 
00303                 
00304                 
00305                 
00306                 
00307                 
00308                 
00309                 
00310                 publications.insert( std::pair<std::string, const Subscribers*>(topic, SigSlotsManager<Void>::connectSignal(topic,this)) );
00311         }
00315         void connectSlot(const std::string& topic){
00316                 std::pair< std::set<std::string>::iterator,bool > ret;
00317                 ret = subscriptions.insert(topic); 
00318                 if ( ret.second ) {
00319                         SigSlotsManager<Void>::connectSlot(topic,this);
00320                 } 
00321         }
00329         void disconnect(const std::string &topic) {
00330                 std::set<std::string>::const_iterator listen_iter = subscriptions.find(topic);
00331                 publications.erase(topic); 
00332                 SigSlotsManager<Void>::disconnect(topic,this);
00333         }
00339         void disconnect() {
00340                 std::set<std::string>::iterator iter;
00341                 for ( iter = subscriptions.begin(); iter != subscriptions.end(); ++iter ) {
00342                         SigSlotsManager<Void>::disconnect(*iter, this);
00343                 }
00344                 subscriptions.clear();
00345                 std::map<std::string,const Subscribers*>::iterator emit_iter;
00346                 for ( emit_iter = publications.begin(); emit_iter != publications.end(); ++emit_iter ) {
00347                         SigSlotsManager<Void>::disconnect(emit_iter->first, this);
00348                 }
00349                 publications.clear();
00350         }
00351 
00352 private:
00353         Mutex mutex;
00354         unsigned int processing_count; 
00355         unsigned int number_of_handles; 
00356         std::set<std::string> subscriptions; 
00357         PublicationMap publications; 
00358 
00359         NullaryFunction<void> *function;
00360 };
00361 
00362 } 
00363 
00364 #endif