NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.5: NDN, CCN, CCNx, content centric networks
API Documentation
signal-signal.hpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
22 #ifndef NDN_UTIL_SIGNAL_SIGNAL_HPP
23 #define NDN_UTIL_SIGNAL_SIGNAL_HPP
24 
25 #include "signal-connection.hpp"
26 #include <list>
27 
28 namespace ndn {
29 namespace util {
30 namespace signal {
31 
32 class DummyExtraArg;
33 
49 template<typename Owner, typename ...TArgs>
50 class Signal : noncopyable
51 {
52 public: // API for anyone
55  typedef function<void(const TArgs&...)> Handler;
56 
57  Signal();
58 
59  ~Signal();
60 
66  connect(const Handler& handler);
67 
73  connectSingleShot(const Handler& handler);
74 
75 private: // API for owner
78  bool
79  isEmpty() const;
80 
88  void
89  operator()(const TArgs&...args);
90 
94  void
95  operator()(const TArgs&...args, const DummyExtraArg&);
96 
97  // make Owner a friend of Signal<Owner, ...> so that API for owner can be called
98 #if NDN_CXX_HAVE_CXX_FRIEND_TYPENAME
99  friend Owner;
100 #elif NDN_CXX_HAVE_CXX_FRIEND_TYPENAME_WRAPPER
101  template<typename T>
102  struct TypeWrapper
103  {
104  typedef T Type;
105  }; // http://stackoverflow.com/a/5608542/3729203
106  friend class TypeWrapper<Owner>::Type;
107 #else
108 # error "cannot declare Owner as friend"
109 #endif
110 
111 private: // internal implementation
112  typedef Signal<Owner, TArgs...> Self;
113  struct Slot;
114 
119  typedef std::list<Slot> SlotList;
120 
123  struct Slot
124  {
127  Handler handler;
128 
138  shared_ptr<function<void()>> disconnect;
139  };
140 
143  SlotList m_slots;
144 
147  bool m_isExecuting;
148 
152  typename SlotList::iterator m_currentSlot;
153 
156  void
157  disconnect(typename SlotList::iterator it);
158 };
159 
160 template<typename Owner, typename ...TArgs>
162  : m_isExecuting(false)
163 {
164 }
165 
166 template<typename Owner, typename ...TArgs>
168 {
169  BOOST_ASSERT(!m_isExecuting);
170 }
171 
172 template<typename Owner, typename ...TArgs>
173 inline Connection
175 {
176  typename SlotList::iterator it = m_slots.insert(m_slots.end(), {handler, nullptr});
177  it->disconnect = make_shared<function<void()>>(bind(&Self::disconnect, this, it));
178 
179  return signal::Connection(weak_ptr<function<void()>>(it->disconnect));
180 }
181 
182 template<typename Owner, typename ...TArgs>
183 inline Connection
185 {
186  typename SlotList::iterator it = m_slots.insert(m_slots.end(), {nullptr, nullptr});
187  it->disconnect = make_shared<function<void()>>(bind(&Self::disconnect, this, it));
188  signal::Connection conn(weak_ptr<function<void()>>(it->disconnect));
189 
190  it->handler = [conn, handler] (const TArgs&... args) mutable {
191  handler(args...);
192  conn.disconnect();
193  };
194 
195  return conn;
196 }
197 
198 template<typename Owner, typename ...TArgs>
199 inline void
201 {
202  // it could be const_iterator, but gcc 4.6 doesn't support std::list::erase(const_iterator)
203 
204  if (m_isExecuting) {
205  // during signal emission, only the currently executing handler can be disconnected
206  BOOST_ASSERT_MSG(it == m_currentSlot,
207  "cannot disconnect another handler from a handler");
208  m_currentSlot = m_slots.end(); // prevent disconnect twice
209  }
210  m_slots.erase(it);
211 }
212 
213 template<typename Owner, typename ...TArgs>
214 inline bool
215 Signal<Owner, TArgs...>::isEmpty() const
216 {
217  return !m_isExecuting && m_slots.empty();
218 }
219 
220 template<typename Owner, typename ...TArgs>
221 inline void
222 Signal<Owner, TArgs...>::operator()(const TArgs&... args)
223 {
224  BOOST_ASSERT_MSG(!m_isExecuting, "cannot emit signal from a handler");
225  if (m_slots.empty()) {
226  return;
227  }
228  m_isExecuting = true;
229 
230  typename SlotList::iterator it = m_slots.begin();
231  typename SlotList::iterator last = m_slots.end();
232  --last;
233 
234  try {
235  bool isLast = false;
236  while (!isLast) {
237  m_currentSlot = it;
238  isLast = it == last;
239  ++it;
240 
241  m_currentSlot->handler(args...);
242  }
243  }
244  catch (...) {
245  m_isExecuting = false;
246  throw;
247  }
248  m_isExecuting = false;
249 }
250 
251 template<typename Owner, typename ...TArgs>
252 inline void
253 Signal<Owner, TArgs...>::operator()(const TArgs&... args, const DummyExtraArg&)
254 {
255  this->operator()(args...);
256 }
257 
258 } // namespace signal
259 
260 // expose as ndn::util::Signal
261 using signal::Signal;
262 
263 } // namespace util
264 } // namespace ndn
265 
266 #endif // NDN_UTIL_SIGNAL_SIGNAL_HPP
Connection connectSingleShot(const Handler &handler)
connects a single-shot handler to the signal
Copyright (c) 2011-2015 Regents of the University of California.
represents a connection to a signal
provides a lightweight signal / event system
Table::const_iterator iterator
Definition: cs-internal.hpp:41
Connection connect(const Handler &handler)
connects a handler to the signal
(implementation detail) a filler for extra argument
Definition: signal-emit.hpp:42
function< void(const TArgs &...)> Handler
represents a function that can connect to the signal