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