1#ifndef MUDUO_BASE_SIGNALSLOT_H 2#define MUDUO_BASE_SIGNALSLOT_H 3 4#include "Mutex.h" 5 6#include <boost/function.hpp> 7#include <boost/noncopyable.hpp> 8#include <boost/shared_ptr.hpp> 9#include <boost/weak_ptr.hpp> 10 11#include <vector> 12 13namespace muduo 14{ 15 16namespace detail 17{ 18 19template<typename Callback> 20struct SlotImpl; 21 22template<typename Callback> 23struct SignalImpl : boost::noncopyable 24{ 25 typedef std::vector<boost::weak_ptr<SlotImpl<Callback> > > SlotList; 26 27 SignalImpl() 28 : slots_(new SlotList) 29 { 30 } 31 32 void copyOnWrite() 33 { 34 mutex_.assertLocked(); 35 if (!slots_.unique()) 36 { 37 slots_.reset(new SlotList(*slots_)); 38 } 39 assert(slots_.unique()); 40 } 41 42 void clean() 43 { 44 MutexLockGuard lock(mutex_); 45 copyOnWrite(); 46 SlotList& list(*slots_); 47 typename SlotList::iterator it(list.begin()); 48 while (it != list.end()) 49 { 50 if (it->expired()) 51 { 52 it = list.erase(it); 53 } 54 else 55 { 56 ++it; 57 } 58 } 59 } 60 61 MutexLock mutex_; 62 boost::shared_ptr<SlotList> slots_; 63}; 64 65template<typename Callback> 66struct SlotImpl : boost::noncopyable 67{ 68 typedef SignalImpl<Callback> Data; 69 SlotImpl(const boost::shared_ptr<Data>& data, Callback&& cb) 70 : data_(data), cb_(cb), tie_(), tied_(false) 71 { 72 } 73 74 SlotImpl(const boost::shared_ptr<Data>& data, Callback&& cb, 75 const boost::shared_ptr<void>& tie) 76 : data_(data), cb_(cb), tie_(tie), tied_(true) 77 { 78 } 79 80 ~SlotImpl() 81 { 82 boost::shared_ptr<Data> data(data_.lock()); 83 if (data) 84 { 85 data->clean(); 86 } 87 } 88 89 boost::weak_ptr<Data> data_; 90 Callback cb_; 91 boost::weak_ptr<void> tie_; 92 bool tied_; 93}; 94 95} 96 97/// This is the handle for a slot 98/// 99/// The slot will remain connected to the signal fot the life time of the 100/// returned Slot object (and its copies). 101typedef boost::shared_ptr<void> Slot; 102 103template<typename Signature> 104class Signal; 105 106template <typename RET, typename... ARGS> 107class Signal<RET(ARGS...)> : boost::noncopyable 108{ 109 public: 110 typedef std::function<void (ARGS...)> Callback; 111 typedef detail::SignalImpl<Callback> SignalImpl; 112 typedef detail::SlotImpl<Callback> SlotImpl; 113 114 Signal() 115 : impl_(new SignalImpl) 116 { 117 } 118 119 ~Signal() 120 { 121 } 122 123 Slot connect(Callback&& func) 124 { 125 boost::shared_ptr<SlotImpl> slotImpl( 126 new SlotImpl(impl_, std::forward<Callback>(func))); 127 add(slotImpl); 128 return slotImpl; 129 } 130 131 Slot connect(Callback&& func, const boost::shared_ptr<void>& tie) 132 { 133 boost::shared_ptr<SlotImpl> slotImpl(new SlotImpl(impl_, func, tie)); 134 add(slotImpl); 135 return slotImpl; 136 } 137 138 void call(ARGS&&... args) 139 { 140 SignalImpl& impl(*impl_); 141 boost::shared_ptr<typename SignalImpl::SlotList> slots; 142 { 143 MutexLockGuard lock(impl.mutex_); 144 slots = impl.slots_; 145 } 146 typename SignalImpl::SlotList& s(*slots); 147 for (typename SignalImpl::SlotList::const_iterator it = s.begin(); it != s.end(); ++it) 148 { 149 boost::shared_ptr<SlotImpl> slotImpl = it->lock(); 150 if (slotImpl) 151 { 152 boost::shared_ptr<void> guard; 153 if (slotImpl->tied_) 154 { 155 guard = slotImpl->tie_.lock(); 156 if (guard) 157 { 158 slotImpl->cb_(args...); 159 } 160 } 161 else 162 { 163 slotImpl->cb_(args...); 164 } 165 } 166 } 167 } 168 169 private: 170 171 void add(const boost::shared_ptr<SlotImpl>& slot) 172 { 173 SignalImpl& impl(*impl_); 174 { 175 MutexLockGuard lock(impl.mutex_); 176 impl.copyOnWrite(); 177 impl.slots_->push_back(slot); 178 } 179 } 180 181 const boost::shared_ptr<SignalImpl> impl_; 182}; 183 184} 185 186#endif // MUDUO_BASE_SIGNALSLOT_H 187