NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.5: NDN, CCN, CCNx, content centric networks
API Documentation
signal.hpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2018 Regents of the University of California.
4  *
5  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6  *
7  * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8  * terms of the GNU Lesser General Public License as published by the Free Software
9  * Foundation, either version 3 of the License, or (at your option) any later version.
10  *
11  * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13  * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14  *
15  * You should have received copies of the GNU General Public License and GNU Lesser
16  * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17  * <http://www.gnu.org/licenses/>.
18  *
19  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20  */
21 
22 #ifndef NDN_UTIL_SIGNAL_SIGNAL_HPP
23 #define NDN_UTIL_SIGNAL_SIGNAL_HPP
24 
26 
27 #include <list>
28 
29 namespace ndn {
30 namespace util {
31 namespace signal {
32 
33 class DummyExtraArg;
34 
50 template<typename Owner, typename ...TArgs>
51 class Signal : noncopyable
52 {
53 public: // API for anyone
56  typedef function<void(const TArgs&...)> Handler;
57 
58  Signal();
59 
60  ~Signal();
61 
67  connect(Handler handler);
68 
74  connectSingleShot(Handler handler);
75 
76 private: // API for owner
79  bool
80  isEmpty() const;
81 
89  void
90  operator()(const TArgs&... args);
91 
95  void
96  operator()(const TArgs&... args, const DummyExtraArg&);
97 
98  // make Owner a friend of Signal<Owner, ...> so that API for owner can be called
99  friend Owner;
100 
101 private: // internal implementation
102  typedef Signal<Owner, TArgs...> Self;
103  struct Slot;
104 
109  typedef std::list<Slot> SlotList;
110 
113  struct Slot
114  {
117  Handler handler;
118 
129  shared_ptr<function<void()>> disconnect;
130  };
131 
134  SlotList m_slots;
135 
138  bool m_isExecuting;
139 
143  typename SlotList::iterator m_currentSlot;
144 
147  void
148  disconnect(typename SlotList::iterator it);
149 };
150 
151 template<typename Owner, typename ...TArgs>
153  : m_isExecuting(false)
154 {
155 }
156 
157 template<typename Owner, typename ...TArgs>
159 {
160  BOOST_ASSERT(!m_isExecuting);
161 }
162 
163 template<typename Owner, typename ...TArgs>
166 {
167  auto it = m_slots.insert(m_slots.end(), {std::move(handler), nullptr});
168  it->disconnect = make_shared<function<void()>>([=] { disconnect(it); });
169 
170  return signal::Connection(weak_ptr<function<void()>>(it->disconnect));
171 }
172 
173 template<typename Owner, typename ...TArgs>
176 {
177  auto it = m_slots.insert(m_slots.end(), {nullptr, nullptr});
178  it->disconnect = make_shared<function<void()>>([=] { disconnect(it); });
179  signal::Connection conn(weak_ptr<function<void()>>(it->disconnect));
180 
181  it->handler = [conn, handler = std::move(handler)] (const TArgs&... args) mutable {
182  handler(args...);
183  conn.disconnect();
184  };
185 
186  return conn;
187 }
188 
189 template<typename Owner, typename ...TArgs>
190 void
192 {
193  if (m_isExecuting) {
194  // during signal emission, only the currently executing handler can be disconnected
195  BOOST_ASSERT_MSG(it == m_currentSlot, "cannot disconnect another handler from a handler");
196 
197  // this serves to indicate that the current slot needs to be erased from the list
198  // after it finishes executing; we cannot do it here because of bug #2333
199  m_currentSlot = m_slots.end();
200 
201  // expire all weak_ptrs, to prevent double disconnections
202  it->disconnect.reset();
203  }
204  else {
205  m_slots.erase(it);
206  }
207 }
208 
209 template<typename Owner, typename ...TArgs>
210 bool
211 Signal<Owner, TArgs...>::isEmpty() const
212 {
213  return !m_isExecuting && m_slots.empty();
214 }
215 
216 template<typename Owner, typename ...TArgs>
217 void
218 Signal<Owner, TArgs...>::operator()(const TArgs&... args)
219 {
220  BOOST_ASSERT_MSG(!m_isExecuting, "cannot emit signal from a handler");
221 
222  if (m_slots.empty()) {
223  return;
224  }
225 
226  auto it = m_slots.begin();
227  auto last = std::prev(m_slots.end());
228  m_isExecuting = true;
229 
230  try {
231  bool isLast = false;
232  while (!isLast) {
233  m_currentSlot = it;
234  isLast = it == last;
235 
236  m_currentSlot->handler(args...);
237 
238  if (m_currentSlot == m_slots.end())
239  it = m_slots.erase(it);
240  else
241  ++it;
242  }
243  }
244  catch (...) {
245  m_isExecuting = false;
246  throw;
247  }
248 
249  m_isExecuting = false;
250 }
251 
252 template<typename Owner, typename ...TArgs>
253 void
254 Signal<Owner, TArgs...>::operator()(const TArgs&... args, const DummyExtraArg&)
255 {
256  this->operator()(args...);
257 }
258 
259 } // namespace signal
260 
261 // expose as ndn::util::Signal
262 using signal::Signal;
263 
264 } // namespace util
265 } // namespace ndn
266 
267 #endif // NDN_UTIL_SIGNAL_SIGNAL_HPP
Connection connect(Handler handler)
connects a handler to the signal
Definition: signal.hpp:165
Copyright (c) 2011-2015 Regents of the University of California.
represents a connection to a signal
Definition: connection.hpp:34
provides a lightweight signal / event system
Definition: signal.hpp:51
Connection connectSingleShot(Handler handler)
connects a single-shot handler to the signal
Definition: signal.hpp:175
Table::const_iterator iterator
Definition: cs-internal.hpp:41
(implementation detail) a filler for extra argument
Definition: emit.hpp:42
function< void(const TArgs &...)> Handler
represents a function that can connect to the signal
Definition: signal.hpp:56