signal.h
1 /*
2 ** ClanLib SDK
3 ** Copyright (c) 1997-2015 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
81 ~SlotImplT()
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(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
140 class SlotContainer
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
159 }
clan::SlotImplT::SlotImplT
SlotImplT(const std::weak_ptr< SignalImpl< SlotImplT >> &signal, const std::function< FuncType > &callback)
Definition: signal.h:77
clan::SlotImpl::operator=
SlotImpl & operator=(const SlotImpl &)=delete
clan
Definition: clanapp.h:35
clan::Slot::Slot
Slot()
Definition: signal.h:46
clan::SlotImpl::SlotImpl
SlotImpl()
Definition: signal.h:60
clan::bind_member
std::function< R(Args...)> bind_member(T *instance, R(T::*method)(Args...))
Definition: bind_member.h:38
clan::Signal::Signal
Signal()
Definition: signal.h:107
std
STL namespace.
clan::Signal::connect
Slot connect(const std::function< FuncType > &func)
Definition: signal.h:123
clan::SlotImplT
Definition: signal.h:74
clan::SlotImpl::~SlotImpl
virtual ~SlotImpl()
Definition: signal.h:63
clan::Signal::connect
Slot connect(InstanceType instance, MemberFuncType func)
Definition: signal.h:131
clan::SlotContainer::connect
void connect(Signal< FuncType > &signal, InstanceType instance, MemberFuncType func)
Definition: signal.h:144
clan::SlotImplT::signal
std::weak_ptr< SignalImpl< SlotImplT > > signal
Definition: signal.h:99
clan::SlotImplT::~SlotImplT
~SlotImplT()
Definition: signal.h:81
clan::Signal
Definition: signal.h:104
clan::SlotContainer
Definition: signal.h:140
clan::Slot
Definition: signal.h:43
clan::Signal::operator()
void operator()(Args...args)
Definition: signal.h:110
clan::SignalImpl::slots
std::vector< std::weak_ptr< SlotImplType > > slots
Definition: signal.h:70
clan::Slot::Slot
Slot(T impl)
Definition: signal.h:51
clan::SlotImpl
Definition: signal.h:57
clan::SlotImplT::callback
std::function< FuncType > callback
Definition: signal.h:100
clan::SlotContainer::connect
void connect(Signal< FuncType > &signal, CallbackType func)
Definition: signal.h:150
clan::SignalImpl
Definition: signal.h:67