#ifndef MUDUO_BASE_SIGNALSLOT_H #define MUDUO_BASE_SIGNALSLOT_H #include "Mutex.h" #include #include #include #include #include namespace muduo { namespace detail { template struct SlotImpl; template struct SignalImpl : boost::noncopyable { typedef std::vector > > SlotList; SignalImpl() : slots_(new SlotList) { } void copyOnWrite() { mutex_.assertLocked(); if (!slots_.unique()) { slots_.reset(new SlotList(*slots_)); } assert(slots_.unique()); } void clean() { MutexLockGuard lock(mutex_); copyOnWrite(); SlotList& list(*slots_); typename SlotList::iterator it(list.begin()); while (it != list.end()) { if (it->expired()) { it = list.erase(it); } else { ++it; } } } MutexLock mutex_; boost::shared_ptr slots_; }; template struct SlotImpl : boost::noncopyable { typedef SignalImpl Data; SlotImpl(const boost::shared_ptr& data, Callback&& cb) : data_(data), cb_(cb), tie_(), tied_(false) { } SlotImpl(const boost::shared_ptr& data, Callback&& cb, const boost::shared_ptr& tie) : data_(data), cb_(cb), tie_(tie), tied_(true) { } ~SlotImpl() { boost::shared_ptr data(data_.lock()); if (data) { data->clean(); } } boost::weak_ptr data_; Callback cb_; boost::weak_ptr tie_; bool tied_; }; } /// This is the handle for a slot /// /// The slot will remain connected to the signal fot the life time of the /// returned Slot object (and its copies). typedef boost::shared_ptr Slot; template class Signal; template class Signal : boost::noncopyable { public: typedef std::function Callback; typedef detail::SignalImpl SignalImpl; typedef detail::SlotImpl SlotImpl; Signal() : impl_(new SignalImpl) { } ~Signal() { } Slot connect(Callback&& func) { boost::shared_ptr slotImpl( new SlotImpl(impl_, std::forward(func))); add(slotImpl); return slotImpl; } Slot connect(Callback&& func, const boost::shared_ptr& tie) { boost::shared_ptr slotImpl(new SlotImpl(impl_, func, tie)); add(slotImpl); return slotImpl; } void call(ARGS&&... args) { SignalImpl& impl(*impl_); boost::shared_ptr slots; { MutexLockGuard lock(impl.mutex_); slots = impl.slots_; } typename SignalImpl::SlotList& s(*slots); for (typename SignalImpl::SlotList::const_iterator it = s.begin(); it != s.end(); ++it) { boost::shared_ptr slotImpl = it->lock(); if (slotImpl) { boost::shared_ptr guard; if (slotImpl->tied_) { guard = slotImpl->tie_.lock(); if (guard) { slotImpl->cb_(args...); } } else { slotImpl->cb_(args...); } } } } private: void add(const boost::shared_ptr& slot) { SignalImpl& impl(*impl_); { MutexLockGuard lock(impl.mutex_); impl.copyOnWrite(); impl.slots_->push_back(slot); } } const boost::shared_ptr impl_; }; } #endif // MUDUO_BASE_SIGNALSLOT_H