12d6ff445SShuo Chen#ifndef MUDUO_BASE_SIGNALSLOT_H 22d6ff445SShuo Chen#define MUDUO_BASE_SIGNALSLOT_H 32d6ff445SShuo Chen 42d6ff445SShuo Chen#include "Mutex.h" 52d6ff445SShuo Chen 62d6ff445SShuo Chen#include <boost/function.hpp> 72d6ff445SShuo Chen#include <boost/noncopyable.hpp> 82d6ff445SShuo Chen#include <boost/shared_ptr.hpp> 92d6ff445SShuo Chen#include <boost/weak_ptr.hpp> 102d6ff445SShuo Chen 112d6ff445SShuo Chen#include <vector> 122d6ff445SShuo Chen 132d6ff445SShuo Chennamespace muduo 142d6ff445SShuo Chen{ 152d6ff445SShuo Chen 162d6ff445SShuo Chennamespace detail 172d6ff445SShuo Chen{ 182d6ff445SShuo Chen 192d6ff445SShuo Chentemplate<typename Callback> 202d6ff445SShuo Chenstruct SlotImpl; 212d6ff445SShuo Chen 222d6ff445SShuo Chentemplate<typename Callback> 232d6ff445SShuo Chenstruct SignalImpl : boost::noncopyable 242d6ff445SShuo Chen{ 252d6ff445SShuo Chen typedef std::vector<boost::weak_ptr<SlotImpl<Callback> > > SlotList; 262d6ff445SShuo Chen 272d6ff445SShuo Chen SignalImpl() 282d6ff445SShuo Chen : slots_(new SlotList) 292d6ff445SShuo Chen { 302d6ff445SShuo Chen } 312d6ff445SShuo Chen 322d6ff445SShuo Chen void copyOnWrite() 332d6ff445SShuo Chen { 342d6ff445SShuo Chen mutex_.assertLocked(); 352d6ff445SShuo Chen if (!slots_.unique()) 362d6ff445SShuo Chen { 372d6ff445SShuo Chen slots_.reset(new SlotList(*slots_)); 382d6ff445SShuo Chen } 392d6ff445SShuo Chen assert(slots_.unique()); 402d6ff445SShuo Chen } 412d6ff445SShuo Chen 422d6ff445SShuo Chen void clean() 432d6ff445SShuo Chen { 442d6ff445SShuo Chen MutexLockGuard lock(mutex_); 452d6ff445SShuo Chen copyOnWrite(); 462d6ff445SShuo Chen SlotList& list(*slots_); 472d6ff445SShuo Chen typename SlotList::iterator it(list.begin()); 482d6ff445SShuo Chen while (it != list.end()) 492d6ff445SShuo Chen { 502d6ff445SShuo Chen if (it->expired()) 512d6ff445SShuo Chen { 522d6ff445SShuo Chen it = list.erase(it); 532d6ff445SShuo Chen } 542d6ff445SShuo Chen else 552d6ff445SShuo Chen { 562d6ff445SShuo Chen ++it; 572d6ff445SShuo Chen } 582d6ff445SShuo Chen } 592d6ff445SShuo Chen } 602d6ff445SShuo Chen 612d6ff445SShuo Chen MutexLock mutex_; 622d6ff445SShuo Chen boost::shared_ptr<SlotList> slots_; 632d6ff445SShuo Chen}; 642d6ff445SShuo Chen 652d6ff445SShuo Chentemplate<typename Callback> 662d6ff445SShuo Chenstruct SlotImpl : boost::noncopyable 672d6ff445SShuo Chen{ 682d6ff445SShuo Chen typedef SignalImpl<Callback> Data; 694dbbbb3dSShuo Chen SlotImpl(const boost::shared_ptr<Data>& data, Callback&& cb) 702d6ff445SShuo Chen : data_(data), cb_(cb), tie_(), tied_(false) 712d6ff445SShuo Chen { 722d6ff445SShuo Chen } 732d6ff445SShuo Chen 744dbbbb3dSShuo Chen SlotImpl(const boost::shared_ptr<Data>& data, Callback&& cb, 754dbbbb3dSShuo Chen const boost::shared_ptr<void>& tie) 764dbbbb3dSShuo Chen : data_(data), cb_(cb), tie_(tie), tied_(true) 772d6ff445SShuo Chen { 782d6ff445SShuo Chen } 792d6ff445SShuo Chen 802d6ff445SShuo Chen ~SlotImpl() 812d6ff445SShuo Chen { 822d6ff445SShuo Chen boost::shared_ptr<Data> data(data_.lock()); 832d6ff445SShuo Chen if (data) 842d6ff445SShuo Chen { 852d6ff445SShuo Chen data->clean(); 862d6ff445SShuo Chen } 872d6ff445SShuo Chen } 882d6ff445SShuo Chen 892d6ff445SShuo Chen boost::weak_ptr<Data> data_; 902d6ff445SShuo Chen Callback cb_; 912d6ff445SShuo Chen boost::weak_ptr<void> tie_; 922d6ff445SShuo Chen bool tied_; 932d6ff445SShuo Chen}; 942d6ff445SShuo Chen 952d6ff445SShuo Chen} 962d6ff445SShuo Chen 972d6ff445SShuo Chen/// This is the handle for a slot 982d6ff445SShuo Chen/// 992d6ff445SShuo Chen/// The slot will remain connected to the signal fot the life time of the 1002d6ff445SShuo Chen/// returned Slot object (and its copies). 1012d6ff445SShuo Chentypedef boost::shared_ptr<void> Slot; 1022d6ff445SShuo Chen 1032d6ff445SShuo Chentemplate<typename Signature> 1042d6ff445SShuo Chenclass Signal; 1052d6ff445SShuo Chen 1062d6ff445SShuo Chentemplate <typename RET, typename... ARGS> 1072d6ff445SShuo Chenclass Signal<RET(ARGS...)> : boost::noncopyable 1082d6ff445SShuo Chen{ 1092d6ff445SShuo Chen public: 1102d6ff445SShuo Chen typedef std::function<void (ARGS...)> Callback; 1112d6ff445SShuo Chen typedef detail::SignalImpl<Callback> SignalImpl; 1122d6ff445SShuo Chen typedef detail::SlotImpl<Callback> SlotImpl; 1132d6ff445SShuo Chen 1142d6ff445SShuo Chen Signal() 1152d6ff445SShuo Chen : impl_(new SignalImpl) 1162d6ff445SShuo Chen { 1172d6ff445SShuo Chen } 1182d6ff445SShuo Chen 1192d6ff445SShuo Chen ~Signal() 1202d6ff445SShuo Chen { 1212d6ff445SShuo Chen } 1222d6ff445SShuo Chen 1234dbbbb3dSShuo Chen Slot connect(Callback&& func) 1242d6ff445SShuo Chen { 125cefd3540SShuo Chen boost::shared_ptr<SlotImpl> slotImpl( 126cefd3540SShuo Chen new SlotImpl(impl_, std::forward<Callback>(func))); 1272d6ff445SShuo Chen add(slotImpl); 1282d6ff445SShuo Chen return slotImpl; 1292d6ff445SShuo Chen } 1302d6ff445SShuo Chen 1314dbbbb3dSShuo Chen Slot connect(Callback&& func, const boost::shared_ptr<void>& tie) 1322d6ff445SShuo Chen { 1334dbbbb3dSShuo Chen boost::shared_ptr<SlotImpl> slotImpl(new SlotImpl(impl_, func, tie)); 1342d6ff445SShuo Chen add(slotImpl); 1352d6ff445SShuo Chen return slotImpl; 1362d6ff445SShuo Chen } 1372d6ff445SShuo Chen 1382d6ff445SShuo Chen void call(ARGS&&... args) 1392d6ff445SShuo Chen { 1402d6ff445SShuo Chen SignalImpl& impl(*impl_); 1412d6ff445SShuo Chen boost::shared_ptr<typename SignalImpl::SlotList> slots; 1422d6ff445SShuo Chen { 1432d6ff445SShuo Chen MutexLockGuard lock(impl.mutex_); 1442d6ff445SShuo Chen slots = impl.slots_; 1452d6ff445SShuo Chen } 1462d6ff445SShuo Chen typename SignalImpl::SlotList& s(*slots); 1472d6ff445SShuo Chen for (typename SignalImpl::SlotList::const_iterator it = s.begin(); it != s.end(); ++it) 1482d6ff445SShuo Chen { 1492d6ff445SShuo Chen boost::shared_ptr<SlotImpl> slotImpl = it->lock(); 1502d6ff445SShuo Chen if (slotImpl) 1512d6ff445SShuo Chen { 1522d6ff445SShuo Chen boost::shared_ptr<void> guard; 1532d6ff445SShuo Chen if (slotImpl->tied_) 1542d6ff445SShuo Chen { 1552d6ff445SShuo Chen guard = slotImpl->tie_.lock(); 1562d6ff445SShuo Chen if (guard) 1572d6ff445SShuo Chen { 1582d6ff445SShuo Chen slotImpl->cb_(args...); 1592d6ff445SShuo Chen } 1602d6ff445SShuo Chen } 1612d6ff445SShuo Chen else 1622d6ff445SShuo Chen { 1632d6ff445SShuo Chen slotImpl->cb_(args...); 1642d6ff445SShuo Chen } 1652d6ff445SShuo Chen } 1662d6ff445SShuo Chen } 1672d6ff445SShuo Chen } 1682d6ff445SShuo Chen 1692d6ff445SShuo Chen private: 1702d6ff445SShuo Chen 1712d6ff445SShuo Chen void add(const boost::shared_ptr<SlotImpl>& slot) 1722d6ff445SShuo Chen { 1732d6ff445SShuo Chen SignalImpl& impl(*impl_); 1742d6ff445SShuo Chen { 1752d6ff445SShuo Chen MutexLockGuard lock(impl.mutex_); 1762d6ff445SShuo Chen impl.copyOnWrite(); 1772d6ff445SShuo Chen impl.slots_->push_back(slot); 1782d6ff445SShuo Chen } 1792d6ff445SShuo Chen } 1802d6ff445SShuo Chen 1812d6ff445SShuo Chen const boost::shared_ptr<SignalImpl> impl_; 1822d6ff445SShuo Chen}; 1832d6ff445SShuo Chen 1842d6ff445SShuo Chen} 1852d6ff445SShuo Chen 1862d6ff445SShuo Chen#endif // MUDUO_BASE_SIGNALSLOT_H 187