libosmscout 1.1.1
Loading...
Searching...
No Matches
Signal.h
Go to the documentation of this file.
1#ifndef LIBOSMSCOUT_SIGNAL_H
2#define LIBOSMSCOUT_SIGNAL_H
3
4/*
5 This source is part of the libosmscout library
6 Copyright (C) 2023 Lukas Karas
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
24
25#include <functional>
26#include <mutex>
27#include <set>
28#include <memory>
29#include <vector>
30
31namespace osmscout {
32
33 template<typename... Args>
34 class Slot;
35
45 template<typename... Args>
46 class Signal
47 {
48 private:
49 struct Connection
50 {
51 // Note: when just signal or slot is locked, always lock connection when accessing it
52 mutable std::mutex mutex;
53 Slot<Args...>* slot = nullptr;
54 Signal<Args...>* signal = nullptr;
55 };
56
57 private:
58 // Note: when signal and slot mutexes are locked at the same time, always lock signal's one first
59 mutable std::mutex mutex;
60 std::vector<std::shared_ptr<Connection>> connections;
61
62 public:
63 friend class Slot<Args...>;
64
65 Signal() = default;
66 Signal(const Signal&) = delete;
67 Signal(Signal&&) = delete;
68
69 Signal& operator=(const Signal&) = delete;
70 Signal& operator=(Signal&&) = delete;
71
72 virtual ~Signal();
73
78 void Emit(const Args&... args) const;
79
84
90
93 void Disconnect();
94 };
95
96 template<typename... Args>
97 class Slot
98 {
99 private:
100 // Note: when signal and slot mutexes are locked at the same time, always lock signal's one first
101 mutable std::mutex mutex;
102 const std::function<void(const Args&...)> callback;
103 std::vector<std::shared_ptr<typename Signal<Args...>::Connection>> connections;
104
105 public:
106 friend class Signal<Args...>;
107
111 explicit Slot(const std::function<void(const Args&...)> &callback);
112
113 Slot(const Slot&) = delete;
114 Slot(Slot&&) = delete;
115
116 Slot& operator=(const Slot&) = delete;
117 Slot& operator=(Slot&&) = delete;
118
119 virtual ~Slot();
120
124
125 private:
130 void Call(const Args&... args) const;
131 };
132
133 template<typename... Args>
134 Slot<Args...>::Slot(const std::function<void(const Args&...)> &callback):
135 callback(callback)
136 {}
137
138 template<typename... Args>
139 void Slot<Args...>::Call(const Args&... args) const
140 {
141 callback(args...);
142 }
143
144 template<typename... Args>
145 void Signal<Args...>::Emit(const Args&... args) const
146 {
147 std::unique_lock lock(mutex);
148 for (const auto &con: connections) {
149 std::unique_lock lockCon(con->mutex);
150 if (auto slot = con->slot; slot != nullptr) {
151 slot->Call(args...);
152 }
153 }
154 }
155
156 template<typename... Args>
158 {
159 std::unique_lock lock(mutex);
160 std::unique_lock slotLock(slot.mutex);
161
162 auto con=std::make_shared<Connection>();
163 con->slot = &slot;
164 con->signal = this;
165 connections.push_back(con);
166 slot.connections.push_back(con);
167 }
168
169 template<typename... Args>
171 {
172 std::unique_lock lock(mutex);
173 std::unique_lock slotLock(slot.mutex);
174
175 if (auto it = connections.find([&slot](auto const &con) -> bool { return con && con->slot == &slot; });
176 it != connections.end()) {
177 connections.erase(it);
178 }
179 if (auto it = slot.connections.find([this](auto const &con) -> bool { return con && con->signal == this; });
180 it != slot.connections.end()) {
181 slot.connections.erase(it);
182 }
183 }
184
185 template<typename... Args>
187 {
188 std::unique_lock lock(mutex);
189 for (auto &con: connections) {
190 std::unique_lock lockCon(con->mutex);
191 con->signal = nullptr;
192 con->slot = nullptr;
193 }
194 connections.clear();
195 }
196
197 template<typename... Args>
199 {
200 std::unique_lock lock(mutex);
201 for (auto &con: connections) {
202 std::unique_lock lockCon(con->mutex);
203 con->signal = nullptr;
204 con->slot = nullptr;
205 }
206 connections.clear();
207 }
208
209 template<typename... Args>
213
214 template<typename... Args>
218
219} // namespace
220
221#endif //LIBOSMSCOUT_SIGNAL_H
Definition Signal.h:47
void Connect(Slot< Args... > &slot)
Definition Signal.h:157
Signal(Signal &&)=delete
void Disconnect()
Definition Signal.h:186
Signal & operator=(const Signal &)=delete
void Emit(const Args &... args) const
Definition Signal.h:145
Signal & operator=(Signal &&)=delete
void Disconnect(Slot< Args... > &slot)
Definition Signal.h:170
Signal()=default
Signal(const Signal &)=delete
virtual ~Signal()
Definition Signal.h:210
Definition Signal.h:98
virtual ~Slot()
Definition Signal.h:215
Slot & operator=(const Slot &)=delete
void Disconnect()
Definition Signal.h:198
Slot(const std::function< void(const Args &...)> &callback)
Definition Signal.h:134
Slot & operator=(Slot &&)=delete
Slot(const Slot &)=delete
Slot(Slot &&)=delete
Definition Area.h:39