Go to the documentation of this file.00001 #ifndef H_CAN_DISPATCHER
00002 #define H_CAN_DISPATCHER
00003
00004 #include <socketcan_interface/interface.h>
00005 #include <list>
00006 #include <boost/thread/mutex.hpp>
00007 #include <boost/unordered_map.hpp>
00008 #include <boost/utility.hpp>
00009 #include <boost/foreach.hpp>
00010 #include <boost/weak_ptr.hpp>
00011
00012 namespace can{
00013
00014 template< typename Listener > class SimpleDispatcher{
00015 public:
00016 typedef typename Listener::Callable Callable;
00017 typedef typename Listener::Type Type;
00018 protected:
00019 class DispatcherBase : boost::noncopyable{
00020 class GuardedListener: public Listener{
00021 boost::weak_ptr<DispatcherBase> guard_;
00022 public:
00023 GuardedListener(boost::shared_ptr<DispatcherBase> g, const Callable &callable): Listener(callable), guard_(g){}
00024 virtual ~GuardedListener() {
00025 boost::shared_ptr<DispatcherBase> d = guard_.lock();
00026 if(d){
00027 d->remove(this);
00028 }
00029 }
00030 };
00031
00032 boost::mutex &mutex_;
00033 std::list< Listener* > listeners_;
00034 public:
00035 DispatcherBase(boost::mutex &mutex) : mutex_(mutex) {}
00036 void dispatch_nolock(const Type &obj) const{
00037 for(typename std::list<Listener* >::const_iterator it=listeners_.begin(); it != listeners_.end(); ++it){
00038 (**it)(obj);
00039 }
00040 }
00041 void remove(Listener *d){
00042 boost::mutex::scoped_lock lock(mutex_);
00043 listeners_.remove(d);
00044 }
00045 size_t numListeners(){
00046 boost::mutex::scoped_lock lock(mutex_);
00047 return listeners_.size();
00048 }
00049
00050 static typename Listener::Ptr createListener(boost::shared_ptr<DispatcherBase> dispatcher, const Callable &callable){
00051 boost::shared_ptr<Listener > l(new GuardedListener(dispatcher,callable));
00052 dispatcher->listeners_.push_back(l.get());
00053 return l;
00054 }
00055 };
00056 boost::mutex mutex_;
00057 boost::shared_ptr<DispatcherBase> dispatcher_;
00058 public:
00059 SimpleDispatcher() : dispatcher_(new DispatcherBase(mutex_)) {}
00060 typename Listener::Ptr createListener(const Callable &callable){
00061 boost::mutex::scoped_lock lock(mutex_);
00062 return DispatcherBase::createListener(dispatcher_, callable);
00063 }
00064 void dispatch(const Type &obj){
00065 boost::mutex::scoped_lock lock(mutex_);
00066 dispatcher_->dispatch_nolock(obj);
00067 }
00068 size_t numListeners(){
00069 return dispatcher_->numListeners();
00070 }
00071 operator Callable() { return Callable(this,&SimpleDispatcher::dispatch); }
00072 };
00073
00074 template<typename K, typename Listener, typename Hash = boost::hash<K> > class FilteredDispatcher: public SimpleDispatcher<Listener>{
00075 typedef SimpleDispatcher<Listener> BaseClass;
00076 boost::unordered_map<K, boost::shared_ptr<typename BaseClass::DispatcherBase >, Hash> filtered_;
00077 public:
00078 using BaseClass::createListener;
00079 typename Listener::Ptr createListener(const K &key, const typename BaseClass::Callable &callable){
00080 boost::mutex::scoped_lock lock(BaseClass::mutex_);
00081 boost::shared_ptr<typename BaseClass::DispatcherBase > &ptr = filtered_[key];
00082 if(!ptr) ptr.reset(new typename BaseClass::DispatcherBase(BaseClass::mutex_));
00083 return BaseClass::DispatcherBase::createListener(ptr, callable);
00084 }
00085 void dispatch(const typename BaseClass::Type &obj){
00086 boost::mutex::scoped_lock lock(BaseClass::mutex_);
00087 boost::shared_ptr<typename BaseClass::DispatcherBase > &ptr = filtered_[obj];
00088 if(ptr) ptr->dispatch_nolock(obj);
00089 BaseClass::dispatcher_->dispatch_nolock(obj);
00090 }
00091 operator typename BaseClass::Callable() { return typename BaseClass::Callable(this,&FilteredDispatcher::dispatch); }
00092 };
00093
00094 }
00095 #endif