Choreonoid  1.8
Signal.h
Go to the documentation of this file.
1 
5 #ifndef CNOID_UTIL_SIGNAL_H
6 #define CNOID_UTIL_SIGNAL_H
7 
8 #include "Referenced.h"
9 #include <functional>
10 #include <tuple>
11 
12 namespace cnoid {
13 
14 namespace signal_private {
15 
16 template<typename T>
17 class function_traits
18 {
19  static_assert(sizeof( T ) == 0, "function_traits<T>: T is not a function type");
20 };
21 
22 template<typename R, typename... Ts>
23 struct function_traits<R(Ts...)>
24 {
25  constexpr static const std::size_t arity = sizeof...(Ts);
26  using result_type = R;
27 };
28 
29 template<typename R, typename... Ts>
30 struct function_traits<R(Ts...) const> : function_traits<R(Ts...)> {};
31 
32 
33 template<class F, class... Ts, class... Us>
34 typename std::enable_if<
35  sizeof...(Us) == sizeof...(Ts),
36  typename F::result_type>::type
37 apply_impl(F& func, std::tuple<Ts...>&, Us*... us)
38 {
39  return func(*us...);
40 }
41 
42 template<class F, class... Ts, class... Us>
43 typename std::enable_if<
44  sizeof...(Us) < sizeof...(Ts),
45  typename F::result_type>::type
46 apply_impl(F& func, std::tuple<Ts...>& args, Us*... us)
47 {
48  return apply_impl(func, args, us..., &std::get<sizeof...(Us)>(args));
49 }
50 
51 template<class F, class... Args>
52 typename F::result_type
53 apply(F& fun, std::tuple<Args...>& args)
54 {
55  return apply_impl(fun, args);
56 }
57 
58 template<typename T>
59 struct last_value
60 {
61  typedef T result_type;
62 
63  template<typename InputIterator>
64  T operator()(InputIterator iter, InputIterator last) const {
65  T value;
66  while (iter != last){
67  if(iter.isReady()){
68  value = *iter;
69  }
70  ++iter;
71  }
72  return value;
73  }
74 };
75 
76 
77 template<>
78 struct last_value<void> {
79  public:
80  template<typename InputIterator>
81  void operator()(InputIterator iter, InputIterator last) const{
82  while (iter != last){
83  if(iter.isReady()) *iter;
84  ++iter;
85  }
86  }
87 };
88 
89 
90 class SlotHolderBase : public Referenced
91 {
92 public:
93  SlotHolderBase() : isBlocked(false) { }
94  virtual void disconnect() = 0;
95  virtual bool connected() const = 0;
96  virtual void changeOrder(int orderId) = 0;
97 
98  bool isBlocked;
99 };
100 
101 
102 template<typename SlotHolderType, typename... Args>
103 class SlotCallIterator
104 {
105  typedef typename SlotHolderType::result_type result_type;
106 
118  ref_ptr<SlotHolderType> currentSlotHolder;
119 
120  std::tuple<Args...>& args;
121 
122 public:
123  void seekActiveSlot(){
124  while(currentSlotHolder && currentSlotHolder->isBlocked){
125  currentSlotHolder = currentSlotHolder->next;
126  }
127  }
128 
129  SlotCallIterator(SlotHolderType* firstSlot, std::tuple<Args...>& args)
130  : currentSlotHolder(firstSlot), args(args) { }
131 
132  SlotCallIterator(const SlotCallIterator& org)
133  : currentSlotHolder(org.currentSlotHolder), args(org.args) { }
134 
135  bool operator==(const SlotCallIterator& rhs) const {
136  return (currentSlotHolder == rhs.currentSlotHolder);
137  }
138 
139  bool operator!=(const SlotCallIterator& rhs) const {
140  return (currentSlotHolder != rhs.currentSlotHolder);
141  }
142 
143  SlotCallIterator& operator++() {
144  currentSlotHolder = currentSlotHolder->next;
145  return *this;
146  }
147 
148  bool isReady() const {
149  return !currentSlotHolder->isBlocked;
150  }
151 
152  result_type operator*() const {
153  return apply(currentSlotHolder->func, args);
154  }
155 };
156 
157 } // namespace signal_private
158 
159 
160 template<
161  typename TSignature,
162  typename Combiner = signal_private::last_value<
163  typename signal_private::function_traits<TSignature>::result_type>
164  >
165 class Signal;
166 
167 
168 namespace signal_private {
169 
170 template<typename Signature, typename Combiner>
171 class SlotHolder : public SlotHolderBase
172 {
173 public:
174  typedef std::function<Signature> FuncType;
175  FuncType func;
176 
177  typedef ref_ptr<SlotHolder> SlotHolderPtr;
178  SlotHolderPtr next;
179  SlotHolder* prev;
180 
181  typedef Signal<Signature, Combiner> SignalType;
182  SignalType* owner;
183 
184  typedef typename signal_private::function_traits<Signature>::result_type result_type;
185 
186  SlotHolder(const FuncType& func)
187  : func(func), prev(nullptr), owner(nullptr) {
188  }
189 
190  virtual void disconnect() override {
191  if(owner) owner->remove(this);
192  }
193 
194  virtual bool connected() const override {
195  return owner != nullptr;
196  }
197 
198  virtual void changeOrder(int orderId) override {
199  if(owner) owner->changeOrder(this, orderId);
200  }
201 };
202 
203 } // namespace signal_private
204 
205 
207 {
209 
210 public:
212  Connection(signal_private::SlotHolderBase* slot) : slot(slot) { }
213  Connection(const Connection& org) : slot(org.slot) { }
214  Connection(Connection&&) = default;
215 
217  slot = rhs.slot;
218  return *this;
219  }
220 
221  void disconnect() {
222  if(slot) {
223  slot->disconnect();
224  slot.reset();
225  }
226  }
227 
228  bool connected() const {
229  return slot && slot->connected();
230  }
231 
232  void block() {
233  if(slot){
234  slot->isBlocked = true;
235  }
236  }
237 
238  void unblock() {
239  if(slot){
240  slot->isBlocked = false;
241  }
242  }
243 
244  bool isBlocked() const {
245  return slot ? slot->isBlocked : false;
246  }
247 
248  enum Order { FIRST = 0, LAST };
249 
251  if(slot){
252  slot->changeOrder(order);
253  }
254  return *this;
255  }
256 
257  class ScopedBlock {
258  Connection* pConnection;
259  public:
260  ScopedBlock(Connection& connection)
261  : pConnection(&connection) {
262  connection.block();
263  }
264  ScopedBlock(ScopedBlock&& org) : pConnection(org.pConnection){
265  org.pConnection = nullptr;
266  }
267  ScopedBlock(const ScopedBlock&) = delete;
268  ScopedBlock& operator=(const ScopedBlock&) = delete;
270  if(pConnection){
271  pConnection->unblock();
272  }
273  }
274  };
275  ScopedBlock scopedBlock(){ return ScopedBlock(*this); }
276 };
277 
278 
280 {
281  Connection connection_;
282 
283 public:
285  ScopedConnection(ScopedConnection&&) = default;
286  ScopedConnection(const ScopedConnection& org) = delete;
287  ScopedConnection(const Connection& org) { connection_ = org; }
288  ~ScopedConnection() { connection_.disconnect(); }
289  void reset() { connection_.disconnect(); }
290  void reset(const Connection& c) { connection_.disconnect(); connection_ = c; }
291  ScopedConnection& operator=(const ScopedConnection& rhs) = delete;
292  ScopedConnection& operator=(const Connection& rhs) { reset(rhs); return *this; }
293  void disconnect() { connection_.disconnect(); }
294  bool connected() const { return connection_.connected(); }
295  void block() { connection_.block(); }
296  void unblock() { connection_.unblock(); }
297  bool isBlocked() const { return connection_.isBlocked(); }
298  ScopedConnection& changeOrder(Connection::Order order) { connection_.changeOrder(order); return *this; }
299  Connection& connection(){ return connection_; }
300  const Connection& connection() const { return connection_; }
301 };
302 
303 
304 template<typename Combiner, typename R, typename... Args>
305 class Signal<R(Args...), Combiner>
306 {
307 public:
308  typedef typename signal_private::function_traits<R(Args...)>::result_type result_type;
309  typedef std::function<R(Args...)> function_type;
311 
312 private:
313  typedef signal_private::SlotHolder<R(Args...), Combiner> SlotHolderType;
315 
316  SlotHolderPtr firstSlot;
317  SlotHolderType* lastSlot;
318 
319 public:
320  Signal() : lastSlot(nullptr) { }
321  Signal(Signal&&) = default;
322  Signal(const Signal& org) = delete;
323  Signal& operator=(const Signal& rhs) = delete;
324 
326  disconnect_all_slots();
327  }
328 
330 
331  SlotHolderType* slot = new SlotHolderType(func);
332 
333  if(!firstSlot){
334  firstSlot = slot;
335  lastSlot = slot;
336  } else {
337  lastSlot->next = slot;
338  slot->prev = lastSlot;
339  lastSlot = slot;
340  }
341  slot->owner = this;
342 
343  return Connection(slot);
344  }
345 
346  void remove(SlotHolderPtr slot){
347  if(slot->owner == this){
348  SlotHolderType* next = slot->next;
349  SlotHolderType* prev = slot->prev;
350  if(next){
351  next->prev = prev;
352  } else {
353  lastSlot = prev;
354  }
355  if(prev){
356  prev->next = next;
357  } else {
358  firstSlot = next;
359  }
360  slot->prev = nullptr;
361  slot->owner = nullptr;
362  slot->isBlocked = true;
363 
369  }
370  }
371 
372  void changeOrder(SlotHolderPtr slot, int orderId){
373  if(slot->owner == this){
374  if(orderId == Connection::FIRST){
375  if(firstSlot != slot){
376  remove(slot);
377  slot->owner = this;
378  if(firstSlot){
379  slot->next = firstSlot;
380  slot->next->prev = slot;
381  }
382  firstSlot = slot;
383  }
384  } else if(orderId == Connection::LAST){
385  if(lastSlot != slot){
386  remove(slot);
387  slot->owner = this;
388  if(lastSlot){
389  lastSlot->next = slot;
390  slot->prev = lastSlot;
391  } else {
392  firstSlot = slot;
393  }
394  lastSlot = slot;
395  }
396  }
397  }
398  }
399 
401  while(firstSlot){
402  remove(firstSlot);
403  }
404  }
405 
406  bool empty() const {
407  return (firstSlot == nullptr);
408  }
409 
410  int numConnections() const {
411  int n = 0;
412  auto slot = firstSlot;
413  while(slot){
414  ++n;
415  slot = slot->next;
416  }
417  return n;
418  }
419 
420  result_type operator()(Args... args){
421  typedef signal_private::SlotCallIterator<SlotHolderType, Args...> IteratorType;
422  Combiner combiner;
423  std::tuple<Args...> argset(args...);
424  return combiner(IteratorType(firstSlot, argset), IteratorType(nullptr, argset));
425  }
426 };
427 
428 
430 {
431 public:
432  typedef bool result_type;
433  template<typename InputIterator>
434  bool operator()(InputIterator iter, InputIterator last) const {
435  bool result = true;
436  while(iter != last){
437  if(iter.isReady()){
438  result &= *iter;
439  }
440  ++iter;
441  }
442  return result;
443  }
444 };
445 
446 
448 {
449 public:
450  typedef bool result_type;
451  template<typename InputIterator>
452  bool operator()(InputIterator iter, InputIterator last) const {
453  bool result = false;
454  while(iter != last){
455  if(iter.isReady()){
456  result |= *iter;
457  }
458  ++iter;
459  }
460  return result;
461  }
462 };
463 
464 
465 template<
466  typename Signature,
467  typename Combiner = signal_private::last_value<
468  typename signal_private::function_traits<Signature>::result_type>
469  >
471 {
472 public:
474 
475  SignalProxy() : signal(nullptr) { }
476  SignalProxy(SignalType& signal) : signal(&signal) { }
477  SignalProxy(const SignalProxy& org) : signal(org.signal) { }
478 
479  SignalProxy& operator=(const SignalProxy& rhs) { signal = rhs.signal; }
480 
481  Connection connect(typename SignalType::Function f){
482  if(signal){
483  return signal->connect(f);
484  } else {
485  return Connection();
486  }
487  };
488 
489 private:
490  SignalType* signal;
491 };
492 
493 } // namespace cnoid;
494 
495 #endif
cnoid::Signal< R(Args...), Combiner >::changeOrder
void changeOrder(SlotHolderPtr slot, int orderId)
Definition: Signal.h:372
Referenced.h
cnoid::Connection::disconnect
void disconnect()
Definition: Signal.h:221
cnoid::LogicalProduct::operator()
bool operator()(InputIterator iter, InputIterator last) const
Definition: Signal.h:434
cnoid::Signal< R(Args...), Combiner >::empty
bool empty() const
Definition: Signal.h:406
cnoid::ScopedConnection::reset
void reset()
Definition: Signal.h:289
cnoid::Connection::Connection
Connection(signal_private::SlotHolderBase *slot)
Definition: Signal.h:212
cnoid::Connection::unblock
void unblock()
Definition: Signal.h:238
cnoid::Connection::ScopedBlock::ScopedBlock
ScopedBlock(ScopedBlock &&org)
Definition: Signal.h:264
cnoid::ScopedConnection
Definition: Signal.h:279
cnoid::Connection::changeOrder
Connection & changeOrder(Order order)
Definition: Signal.h:250
cnoid::Connection::FIRST
@ FIRST
Definition: Signal.h:248
cnoid::Connection::Order
Order
Definition: Signal.h:248
cnoid::LogicalSum::operator()
bool operator()(InputIterator iter, InputIterator last) const
Definition: Signal.h:452
cnoid::Connection::Connection
Connection()
Definition: Signal.h:211
cnoid::Signal< R(Args...), Combiner >::Signal
Signal()
Definition: Signal.h:320
cnoid::ScopedConnection::connection
const Connection & connection() const
Definition: Signal.h:300
cnoid::Connection::ScopedBlock
Definition: Signal.h:257
cnoid::SignalProxy::SignalProxy
SignalProxy(SignalType &signal)
Definition: Signal.h:476
cnoid::LogicalProduct::result_type
bool result_type
Definition: Signal.h:432
cnoid::Signal< R(Args...), Combiner >::Function
function_type Function
Definition: Signal.h:310
cnoid::SignalProxy::connect
Connection connect(typename SignalType::Function f)
Definition: Signal.h:481
cnoid::SignalProxy::SignalProxy
SignalProxy(const SignalProxy &org)
Definition: Signal.h:477
cnoid::SignalProxy::SignalType
Signal< Signature, Combiner > SignalType
Definition: Signal.h:473
cnoid::ref_ptr
Definition: Referenced.h:103
cnoid::ScopedConnection::operator=
ScopedConnection & operator=(const ScopedConnection &rhs)=delete
cnoid::ScopedConnection::isBlocked
bool isBlocked() const
Definition: Signal.h:297
cnoid::Connection::scopedBlock
ScopedBlock scopedBlock()
Definition: Signal.h:275
cnoid::Signal< R(Args...), Combiner >::operator()
result_type operator()(Args... args)
Definition: Signal.h:420
cnoid::Connection::ScopedBlock::ScopedBlock
ScopedBlock(Connection &connection)
Definition: Signal.h:260
cnoid::ScopedConnection::reset
void reset(const Connection &c)
Definition: Signal.h:290
cnoid::Connection::ScopedBlock::~ScopedBlock
~ScopedBlock()
Definition: Signal.h:269
cnoid::Signal< R(Args...), Combiner >::function_type
std::function< R(Args...)> function_type
Definition: Signal.h:309
cnoid::Connection::connected
bool connected() const
Definition: Signal.h:228
cnoid::Connection::LAST
@ LAST
Definition: Signal.h:248
cnoid::Connection::ScopedBlock::operator=
ScopedBlock & operator=(const ScopedBlock &)=delete
cnoid
Definition: AbstractSceneLoader.h:11
cnoid::LogicalProduct
Definition: Signal.h:429
cnoid::ScopedConnection::disconnect
void disconnect()
Definition: Signal.h:293
cnoid::ScopedConnection::operator=
ScopedConnection & operator=(const Connection &rhs)
Definition: Signal.h:292
cnoid::operator==
bool operator==(ref_ptr< T > const &a, ref_ptr< U > const &b)
Definition: Referenced.h:211
cnoid::ScopedConnection::connection
Connection & connection()
Definition: Signal.h:299
cnoid::Connection::Connection
Connection(const Connection &org)
Definition: Signal.h:213
cnoid::Connection::isBlocked
bool isBlocked() const
Definition: Signal.h:244
cnoid::ScopedConnection::changeOrder
ScopedConnection & changeOrder(Connection::Order order)
Definition: Signal.h:298
cnoid::ScopedConnection::~ScopedConnection
~ScopedConnection()
Definition: Signal.h:288
cnoid::Signal< R(Args...), Combiner >::~Signal
~Signal()
Definition: Signal.h:325
cnoid::Signal< R(Args...), Combiner >::disconnect_all_slots
void disconnect_all_slots()
Definition: Signal.h:400
cnoid::Connection::operator=
Connection & operator=(const Connection &rhs)
Definition: Signal.h:216
cnoid::ScopedConnection::ScopedConnection
ScopedConnection(const Connection &org)
Definition: Signal.h:287
cnoid::ScopedConnection::ScopedConnection
ScopedConnection()
Definition: Signal.h:284
cnoid::Signal
Definition: Signal.h:165
cnoid::ScopedConnection::connected
bool connected() const
Definition: Signal.h:294
cnoid::SignalProxy
Definition: Signal.h:470
cnoid::Signal< R(Args...), Combiner >::result_type
signal_private::function_traits< R(Args...)>::result_type result_type
Definition: Signal.h:308
cnoid::operator!=
bool operator!=(ref_ptr< T > const &a, ref_ptr< U > const &b)
Definition: Referenced.h:216
cnoid::LogicalSum
Definition: Signal.h:447
cnoid::Connection::block
void block()
Definition: Signal.h:232
cnoid::Signal< R(Args...), Combiner >::numConnections
int numConnections() const
Definition: Signal.h:410
cnoid::Signal< R(Args...), Combiner >::remove
void remove(SlotHolderPtr slot)
Definition: Signal.h:346
cnoid::ref_ptr::reset
void reset()
Definition: Referenced.h:159
cnoid::LogicalSum::result_type
bool result_type
Definition: Signal.h:450
cnoid::Connection
Definition: Signal.h:206
cnoid::ScopedConnection::block
void block()
Definition: Signal.h:295
cnoid::Signal< R(Args...), Combiner >::connect
Connection connect(const Function &func)
Definition: Signal.h:329
cnoid::ScopedConnection::unblock
void unblock()
Definition: Signal.h:296
cnoid::SignalProxy::SignalProxy
SignalProxy()
Definition: Signal.h:475
cnoid::SignalProxy::operator=
SignalProxy & operator=(const SignalProxy &rhs)
Definition: Signal.h:479