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 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_ */


ecl_sigslots
Author(s): Daniel Stonier
autogenerated on Thu Jan 2 2014 11:13:07