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-2019 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 
61 
67  connect(Handler handler);
68 
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 
106  struct Slot
107  {
110  Handler handler;
111 
122  shared_ptr<DisconnectFunction> disconnect;
123  };
124 
129  typedef std::list<Slot> SlotList;
130  SlotList m_slots;
131 
134  bool m_isExecuting;
135 
139  typename SlotList::iterator m_currentSlot;
140 
143  void
144  disconnect(typename SlotList::iterator it);
145 };
146 
147 template<typename Owner, typename ...TArgs>
149  : m_isExecuting(false)
150 {
151 }
152 
153 template<typename Owner, typename ...TArgs>
155 {
156  BOOST_ASSERT(!m_isExecuting);
157 }
158 
159 template<typename Owner, typename ...TArgs>
162 {
163  auto it = m_slots.insert(m_slots.end(), {std::move(handler), nullptr});
164  it->disconnect = make_shared<DisconnectFunction>([=] { disconnect(it); });
165 
166  return signal::Connection(it->disconnect);
167 }
168 
169 template<typename Owner, typename ...TArgs>
172 {
173  auto it = m_slots.insert(m_slots.end(), {nullptr, nullptr});
174  it->disconnect = make_shared<DisconnectFunction>([=] { disconnect(it); });
175  signal::Connection conn(it->disconnect);
176 
177  it->handler = [conn, handler = std::move(handler)] (const TArgs&... args) mutable {
178  handler(args...);
179  conn.disconnect();
180  };
181 
182  return conn;
183 }
184 
185 template<typename Owner, typename ...TArgs>
186 void
187 Signal<Owner, TArgs...>::disconnect(typename SlotList::iterator it)
188 {
189  if (m_isExecuting) {
190  // during signal emission, only the currently executing handler can be disconnected
191  BOOST_ASSERT_MSG(it == m_currentSlot, "cannot disconnect another handler from a handler");
192 
193  // this serves to indicate that the current slot needs to be erased from the list
194  // after it finishes executing; we cannot do it here because of bug #2333
195  m_currentSlot = m_slots.end();
196 
197  // expire all weak_ptrs, to prevent double disconnections
198  it->disconnect.reset();
199  }
200  else {
201  m_slots.erase(it);
202  }
203 }
204 
205 template<typename Owner, typename ...TArgs>
206 bool
207 Signal<Owner, TArgs...>::isEmpty() const
208 {
209  return !m_isExecuting && m_slots.empty();
210 }
211 
212 template<typename Owner, typename ...TArgs>
213 void
214 Signal<Owner, TArgs...>::operator()(const TArgs&... args)
215 {
216  BOOST_ASSERT_MSG(!m_isExecuting, "cannot emit signal from a handler");
217 
218  if (m_slots.empty()) {
219  return;
220  }
221 
222  auto it = m_slots.begin();
223  auto last = std::prev(m_slots.end());
224  m_isExecuting = true;
225 
226  try {
227  bool isLast = false;
228  while (!isLast) {
229  m_currentSlot = it;
230  isLast = it == last;
231 
232  m_currentSlot->handler(args...);
233 
234  if (m_currentSlot == m_slots.end())
235  it = m_slots.erase(it);
236  else
237  ++it;
238  }
239  }
240  catch (...) {
241  m_isExecuting = false;
242  throw;
243  }
244 
245  m_isExecuting = false;
246 }
247 
248 template<typename Owner, typename ...TArgs>
249 void
250 Signal<Owner, TArgs...>::operator()(const TArgs&... args, const DummyExtraArg&)
251 {
252  this->operator()(args...);
253 }
254 
255 } // namespace signal
256 
257 // expose as ndn::util::Signal
258 using signal::Signal;
259 
260 } // namespace util
261 } // namespace ndn
262 
263 #endif // NDN_UTIL_SIGNAL_SIGNAL_HPP
nonstd::optional_lite::std11::move
T & move(T &t)
Definition: optional.hpp:421
ndn::util::signal::Signal::connectSingleShot
Connection connectSingleShot(Handler handler)
connects a single-shot handler to the signal
Definition: signal.hpp:171
ndn::util::signal::Signal::connect
Connection connect(Handler handler)
connects a handler to the signal
Definition: signal.hpp:161
ndn::util::signal::Signal::Handler
function< void(const TArgs &...)> Handler
represents a function that can connect to the signal
Definition: signal.hpp:56
ndn::util::signal::DummyExtraArg
(implementation detail) a filler for extra argument
Definition: emit.hpp:43
ndn::util::signal
Definition: connection.cpp:26
ndn::util::signal::Connection
represents a connection to a signal
Definition: connection.hpp:37
ndn::util::signal::Signal
provides a lightweight signal / event system
Definition: signal.hpp:52
connection.hpp
ndn::util::signal::Signal::Signal
Signal()
Definition: signal.hpp:148
ndn::util::signal::Connection::disconnect
void disconnect()
disconnects from the signal
Definition: connection.cpp:36
ndn::util::signal::Signal::~Signal
~Signal()
Definition: signal.hpp:154
ndn
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-strategy-choice-helper.hpp:34