signal.h
1 /*
2 ** ClanLib SDK
3 ** Copyright (c) 1997-2016 The ClanLib Team
4 **
5 ** This software is provided 'as-is', without any express or implied
6 ** warranty. In no event will the authors be held liable for any damages
7 ** arising from the use of this software.
8 **
9 ** Permission is granted to anyone to use this software for any purpose,
10 ** including commercial applications, and to alter it and redistribute it
11 ** freely, subject to the following restrictions:
12 **
13 ** 1. The origin of this software must not be misrepresented; you must not
14 ** claim that you wrote the original software. If you use this software
15 ** in a product, an acknowledgment in the product documentation would be
16 ** appreciated but is not required.
17 ** 2. Altered source versions must be plainly marked as such, and must not be
18 ** misrepresented as being the original software.
19 ** 3. This notice may not be removed or altered from any source distribution.
20 **
21 ** Note: Some of the libraries ClanLib may link to may have additional
22 ** requirements or restrictions.
23 **
24 ** File Author(s):
25 **
26 ** Magnus Norddahl
27 */
28 
29 #pragma once
30 
31 #include "bind_member.h"
32 #include <memory>
33 #include <functional>
34 #include <vector>
35 
36 namespace clan
37 {
40 
41  class SlotImpl;
42 
43  class Slot
44  {
45  public:
46  Slot() { }
47 
48  operator bool() const { return static_cast<bool>(impl); }
49 
50  template<typename T>
51  explicit Slot(T impl) : impl(impl) { }
52 
53  private:
54  std::shared_ptr<SlotImpl> impl;
55  };
56 
57  class SlotImpl
58  {
59  public:
60  SlotImpl() { }
61  SlotImpl(const SlotImpl &) = delete;
62  SlotImpl &operator=(const SlotImpl &) = delete;
63  virtual ~SlotImpl() { }
64  };
65 
66  template<typename SlotImplType>
67  class SignalImpl
68  {
69  public:
70  std::vector<std::weak_ptr<SlotImplType>> slots;
71  };
72 
73  template<typename FuncType>
74  class SlotImplT : public SlotImpl
75  {
76  public:
77  SlotImplT(const std::weak_ptr<SignalImpl<SlotImplT>> &signal, const std::function<FuncType> &callback) : signal(signal), callback(callback)
78  {
79  }
80 
82  {
83  std::shared_ptr<SignalImpl<SlotImplT>> sig = signal.lock();
84  if (sig)
85  {
86  for (auto it = sig->slots.begin(); it != sig->slots.end(); ++it)
87  {
88  // todo: investigate if "it->lock().get() == this" is required
89  if (it->expired() || it->lock().get() == this)
90  {
91  it = sig->slots.erase(it);
92  if (it == sig->slots.end())
93  break;
94  }
95  }
96  }
97  }
98 
99  std::weak_ptr<SignalImpl<SlotImplT>> signal;
100  std::function<FuncType> callback;
101  };
102 
103  template<typename FuncType>
104  class Signal
105  {
106  public:
107  Signal() : impl(std::make_shared<SignalImpl<SlotImplT<FuncType>>>()) { }
108 
109  template<typename... Args>
110  void operator()(Args&&... args)
111  {
112  std::vector<std::weak_ptr<SlotImplT<FuncType>>> slots = impl->slots;
113  for (std::weak_ptr<SlotImplT<FuncType>> &weak_slot : slots)
114  {
115  std::shared_ptr<SlotImplT<FuncType>> slot = weak_slot.lock();
116  if (slot)
117  {
118  slot->callback(std::forward<Args>(args)...);
119  }
120  }
121  }
122 
123  Slot connect(const std::function<FuncType> &func)
124  {
125  auto slot_impl = std::make_shared<SlotImplT<FuncType>>(impl, func);
126  impl->slots.push_back(slot_impl);
127  return Slot(slot_impl);
128  }
129 
130  template<typename InstanceType, typename MemberFuncType>
131  Slot connect(InstanceType instance, MemberFuncType func)
132  {
133  return connect(bind_member(instance, func));
134  }
135 
136  private:
137  std::shared_ptr<SignalImpl<SlotImplT<FuncType>>> impl;
138  };
139 
141  {
142  public:
143  template<typename FuncType, typename InstanceType, typename MemberFuncType>
144  void connect(Signal<FuncType> &signal, InstanceType instance, MemberFuncType func)
145  {
146  slots.push_back(signal.connect(instance, func));
147  }
148 
149  template<typename FuncType, typename CallbackType>
150  void connect(Signal<FuncType> &signal, CallbackType func)
151  {
152  slots.push_back(signal.connect(func));
153  }
154 
155  private:
156  std::vector<Slot> slots;
157  };
158 
160 }
Definition: clanapp.h:35
SlotImplT(const std::weak_ptr< SignalImpl< SlotImplT >> &signal, const std::function< FuncType > &callback)
Definition: signal.h:77
std::function< R(Args...)> bind_member(T *instance, R(T::*method)(Args...))
Definition: bind_member.h:40
STL namespace.
SlotImpl & operator=(const SlotImpl &)=delete
void connect(Signal< FuncType > &signal, InstanceType instance, MemberFuncType func)
Definition: signal.h:144
Signal()
Definition: signal.h:107
std::vector< std::weak_ptr< SlotImplType > > slots
Definition: signal.h:70
SlotImpl()
Definition: signal.h:60
Definition: signal.h:74
Definition: signal.h:104
void operator()(Args &&...args)
Definition: signal.h:110
Slot connect(const std::function< FuncType > &func)
Definition: signal.h:123
Slot()
Definition: signal.h:46
std::function< FuncType > callback
Definition: signal.h:100
Definition: signal.h:140
Definition: signal.h:43
std::weak_ptr< SignalImpl< SlotImplT > > signal
Definition: signal.h:99
void connect(Signal< FuncType > &signal, CallbackType func)
Definition: signal.h:150
~SlotImplT()
Definition: signal.h:81
Definition: signal.h:57
Slot connect(InstanceType instance, MemberFuncType func)
Definition: signal.h:131
Slot(T impl)
Definition: signal.h:51
Definition: signal.h:67
virtual ~SlotImpl()
Definition: signal.h:63