sigslot.hpp
Go to the documentation of this file.
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 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                 disconnect(); // stop any new processing from connected signals
00093                 mutex.lock(); // acts like a barrier - holds up here if function still processing stuff.
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(); // Only lock if its not already locked.
00125                 ++processing_count;
00126                 (*function)(data);
00127                 if ( --processing_count == 0 ) {
00128                         mutex.unlock();
00129                 }
00130         }
00138         void connectSignal(const std::string& topic) {
00139                 // Logic:
00140                 //   - if already publishing to this topic
00141                 //     - don't do anything
00142                 //   - else
00143                 //     - if topic doesn't exist
00144                 //       - Manager will automatically create a new topic
00145                 //     - Manager returns the subscribers handle
00146                 //     - Topic name and subscribers handle are stored locally here in publications
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         //      std::cout << "Topic: " << topic << std::endl;
00159                 ret = subscriptions.insert(topic); // Doesn't matter if it already exists.
00160                 if ( ret.second ) {
00161                         SigSlotsManager<Data>::connectSlot(topic,this);
00162                 } // else { already subscribed to this topic }
00163         }
00167         void disconnect(const std::string &topic) {
00168                 std::set<std::string>::const_iterator listen_iter = subscriptions.find(topic);
00169                 publications.erase(topic); // Doesn't matter if it finds it or not.
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; // number of running process()'
00195         unsigned int number_of_handles; // number of handles to this sigslot (allows copying)
00196         std::set<std::string> subscriptions; // topics this sigslot is listening to
00197         PublicationMap publications; // topics this sigslot is posting to, as well as the subscribers on the other end
00198 
00199         UnaryFunction<Data,void> *function;
00200 };
00201 
00202 /*****************************************************************************
00203 ** Interface [Void]
00204 *****************************************************************************/
00205 
00213 template<>
00214 class SigSlot<Void> {
00215 public:
00216         // typedef std::set<SigSlot<Void>*> Subscribers
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(); // stop any new processing from connected signals
00256                 mutex.lock(); // acts like a barrier - holds up here if function still processing stuff.
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(); // Only lock if its not already locked.
00288                 ++processing_count;
00289                 (*function)();
00290                 if ( --processing_count == 0 ) {
00291                         mutex.unlock();
00292                 }
00293         }
00301         void connectSignal(const std::string& topic) {
00302                 // Logic:
00303                 //   - if already publishing to this topic
00304                 //     - don't do anything
00305                 //   - else
00306                 //     - if topic doesn't exist
00307                 //       - Manager will automatically create a new topic
00308                 //     - Manager returns the subscribers handle
00309                 //     - Topic name and subscribers handle are stored locally here in publications
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); // Doesn't matter if it already exists.
00318                 if ( ret.second ) {
00319                         SigSlotsManager<Void>::connectSlot(topic,this);
00320                 } // else { already subscribed to this topic }
00321         }
00329         void disconnect(const std::string &topic) {
00330                 std::set<std::string>::const_iterator listen_iter = subscriptions.find(topic);
00331                 publications.erase(topic); // Doesn't matter if it finds it or not.
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; // number of running process()'
00355         unsigned int number_of_handles; // number of handles to this sigslot (allows copying)
00356         std::set<std::string> subscriptions; // topics this sigslot is listening to
00357         PublicationMap publications; // topics this sigslot is posting to, as well as the subscribers on the other end
00358 
00359         NullaryFunction<void> *function;
00360 };
00361 
00362 } // namespace ecl
00363 
00364 #endif /* ECL_SIGSLOTS_SIGSLOT_HPP_ */


ecl_sigslots
Author(s): Daniel Stonier
autogenerated on Wed Aug 26 2015 11:27:23