NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.0: 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 
139  shared_ptr<function<void()>> disconnect;
140  };
141 
144  SlotList m_slots;
145 
148  bool m_isExecuting;
149 
153  typename SlotList::iterator m_currentSlot;
154 
157  void
158  disconnect(typename SlotList::iterator it);
159 };
160 
161 template<typename Owner, typename ...TArgs>
163  : m_isExecuting(false)
164 {
165 }
166 
167 template<typename Owner, typename ...TArgs>
169 {
170  BOOST_ASSERT(!m_isExecuting);
171 }
172 
173 template<typename Owner, typename ...TArgs>
176 {
177  typename SlotList::iterator it = m_slots.insert(m_slots.end(), {handler, nullptr});
178  it->disconnect = make_shared<function<void()>>(bind(&Self::disconnect, this, it));
179 
180  return signal::Connection(weak_ptr<function<void()>>(it->disconnect));
181 }
182 
183 template<typename Owner, typename ...TArgs>
186 {
187  typename SlotList::iterator it = m_slots.insert(m_slots.end(), {nullptr, nullptr});
188  it->disconnect = make_shared<function<void()>>(bind(&Self::disconnect, this, it));
189  signal::Connection conn(weak_ptr<function<void()>>(it->disconnect));
190 
191  it->handler = [conn, handler] (const TArgs&... args) mutable {
192  handler(args...);
193  conn.disconnect();
194  };
195 
196  return conn;
197 }
198 
199 template<typename Owner, typename ...TArgs>
200 void
202 {
203  // 'it' could be const_iterator, but gcc 4.6 doesn't support std::list::erase(const_iterator)
204 
205  if (m_isExecuting) {
206  // during signal emission, only the currently executing handler can be disconnected
207  BOOST_ASSERT_MSG(it == m_currentSlot, "cannot disconnect another handler from a handler");
208 
209  // this serves to indicate that the current slot needs to be erased from the list
210  // after it finishes executing; we cannot do it here because of bug #2333
211  m_currentSlot = m_slots.end();
212 
213  // expire all weak_ptrs, to prevent double disconnections
214  it->disconnect.reset();
215  }
216  else {
217  m_slots.erase(it);
218  }
219 }
220 
221 template<typename Owner, typename ...TArgs>
222 bool
224 {
225  return !m_isExecuting && m_slots.empty();
226 }
227 
228 template<typename Owner, typename ...TArgs>
229 void
230 Signal<Owner, TArgs...>::operator()(const TArgs&... args)
231 {
232  BOOST_ASSERT_MSG(!m_isExecuting, "cannot emit signal from a handler");
233 
234  if (m_slots.empty()) {
235  return;
236  }
237 
238  auto it = m_slots.begin();
239  auto last = std::prev(m_slots.end());
240  m_isExecuting = true;
241 
242  try {
243  bool isLast = false;
244  while (!isLast) {
245  m_currentSlot = it;
246  isLast = it == last;
247 
248  m_currentSlot->handler(args...);
249 
250  if (m_currentSlot == m_slots.end())
251  it = m_slots.erase(it);
252  else
253  ++it;
254  }
255  }
256  catch (...) {
257  m_isExecuting = false;
258  throw;
259  }
260 
261  m_isExecuting = false;
262 }
263 
264 template<typename Owner, typename ...TArgs>
265 void
266 Signal<Owner, TArgs...>::operator()(const TArgs&... args, const DummyExtraArg&)
267 {
268  this->operator()(args...);
269 }
270 
271 } // namespace signal
272 
273 // expose as ndn::util::Signal
274 using signal::Signal;
275 
276 } // namespace util
277 } // namespace ndn
278 
279 #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