KDBindings API Documentation  1.0.95
connection_handle.h
Go to the documentation of this file.
1 /*
2  This file is part of KDBindings.
3 
4  SPDX-FileCopyrightText: 2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
5  Author: Sean Harmer <sean.harmer@kdab.com>
6 
7  SPDX-License-Identifier: MIT
8 
9  Contact KDAB at <info@kdab.com> for commercial licensing options.
10 */
11 
12 #pragma once
13 
15 #include <kdbindings/utils.h>
16 #include <memory>
17 
18 namespace KDBindings {
19 
20 template<typename... Args>
21 class Signal;
22 
23 class ConnectionHandle;
24 
25 namespace Private {
26 //
27 // This class defines a virtual interface, that the Signal this ConnectionHandle refers
28 // to must implement.
29 // It allows ConnectionHandle to refer to this non-template class, which then dispatches
30 // to the template implementation using virtual function calls.
31 // It allows ConnectionHandle to be a non-template class.
32 class SignalImplBase : public std::enable_shared_from_this<SignalImplBase>
33 {
34 public:
35  SignalImplBase() = default;
36 
37  virtual ~SignalImplBase() = default;
38 
39  virtual void disconnect(const ConnectionHandle &handle) noexcept = 0;
40  virtual bool blockConnection(const GenerationalIndex &id, bool blocked) = 0;
41  virtual bool isConnectionActive(const GenerationalIndex &id) const noexcept = 0;
42  virtual bool isConnectionBlocked(const GenerationalIndex &id) const = 0;
43 };
44 
45 } // namespace Private
46 
55 {
56 public:
62  ConnectionHandle() = default;
63 
67  ConnectionHandle(const ConnectionHandle &) noexcept = default;
68  ConnectionHandle &operator=(const ConnectionHandle &) noexcept = default;
69 
73  ConnectionHandle(ConnectionHandle &&) noexcept = default;
74  ConnectionHandle &operator=(ConnectionHandle &&) noexcept = default;
75 
91  void disconnect() noexcept
92  {
93  if (auto shared_impl = checkedLock()) {
94  shared_impl->disconnect(*this);
95  }
96 
97  // ConnectionHandle is no longer active;
98  m_signalImpl.reset();
99  }
100 
107  bool isActive() const
108  {
109  return static_cast<bool>(checkedLock());
110  }
111 
128  bool block(bool blocked)
129  {
130  if (auto shared_impl = checkedLock()) {
131  return shared_impl->blockConnection(*m_id, blocked);
132  }
133  throw std::out_of_range("Cannot block a non-active connection!");
134  }
135 
143  bool isBlocked() const
144  {
145  if (auto shared_impl = checkedLock()) {
146  return shared_impl->isConnectionBlocked(*m_id);
147  }
148  throw std::out_of_range("Cannot check whether a non-active connection is blocked!");
149  }
150 
156  template<typename... Args>
157  bool belongsTo(const Signal<Args...> &signal) const
158  {
159  auto shared_impl = m_signalImpl.lock();
160  return shared_impl && shared_impl == std::static_pointer_cast<Private::SignalImplBase>(signal.m_impl);
161  }
162 
163  // Define an operator== function to compare ConnectionHandle objects.
164  bool operator==(const ConnectionHandle &other) const
165  {
166  auto thisSignalImpl = m_signalImpl.lock();
167  auto otherSignalImpl = other.m_signalImpl.lock();
168 
169  // If both signalImpl pointers are valid, compare them along with the IDs.
170  if (thisSignalImpl && otherSignalImpl) {
171  return (thisSignalImpl == otherSignalImpl) && (m_id == other.m_id);
172  }
173 
174  // If neither instance has an ID, and both signalImpl pointers are invalid, consider them equal.
175  if (!m_id.has_value() && !other.m_id.has_value() && !thisSignalImpl && !otherSignalImpl) {
176  return true;
177  }
178 
179  // In all other cases, they are not equal.
180  return false;
181  }
182 
198  void release() const { }
199 
200 private:
201  template<typename...>
202  friend class Signal;
203 
204  std::weak_ptr<Private::SignalImplBase> m_signalImpl;
205  std::optional<Private::GenerationalIndex> m_id;
206 
207  // private, so it is only available from Signal
208  ConnectionHandle(std::weak_ptr<Private::SignalImplBase> signalImpl, std::optional<Private::GenerationalIndex> id)
209  : m_signalImpl{ std::move(signalImpl) }, m_id{ std::move(id) }
210  {
211  }
212  void setId(const Private::GenerationalIndex &id)
213  {
214  m_id = id;
215  }
216 
217  // Checks that the weak_ptr can be locked and that the connection is
218  // still active
219  std::shared_ptr<Private::SignalImplBase> checkedLock() const noexcept
220  {
221  if (m_id.has_value()) {
222  auto shared_impl = m_signalImpl.lock();
223  if (shared_impl && shared_impl->isConnectionActive(*m_id)) {
224  return shared_impl;
225  }
226  }
227  return nullptr;
228  }
229 };
230 
240 {
241 public:
248  ScopedConnection() = default;
249 
251  ScopedConnection(ScopedConnection &&) noexcept = default;
252 
256  ScopedConnection &operator=(const ScopedConnection &) = delete;
257 
259  ScopedConnection &operator=(ScopedConnection &&other) noexcept
260  {
261  m_connection.disconnect();
262  m_connection = std::move(other.m_connection);
263  return *this;
264  }
265 
270  : m_connection(std::move(h))
271  {
272  }
273 
278  {
279  return *this = ScopedConnection(std::move(h));
280  }
281 
286  {
287  return m_connection;
288  }
289 
293  const ConnectionHandle &handle() const
294  {
295  return m_connection;
296  }
297 
302  {
303  return &m_connection;
304  }
305 
310  {
311  return &m_connection;
312  }
313 
320  ~ScopedConnection() noexcept
321  {
322  m_connection.disconnect();
323  }
324 
325 private:
326  ConnectionHandle m_connection;
327 };
328 
329 } // namespace KDBindings
A ConnectionHandle represents the connection of a Signal to a slot (i.e. a function that is called wh...
bool belongsTo(const Signal< Args... > &signal) const
ConnectionHandle(const ConnectionHandle &) noexcept=default
ConnectionHandle & operator=(const ConnectionHandle &) noexcept=default
bool operator==(const ConnectionHandle &other) const
ConnectionHandle(ConnectionHandle &&) noexcept=default
A ScopedConnection is a RAII-style way to make sure a Connection is disconnected.
const ConnectionHandle & handle() const
ScopedConnection()=default
A ScopedConnection can be default constructed.
ScopedConnection & operator=(ConnectionHandle &&h) noexcept
const ConnectionHandle * operator->() const
ScopedConnection(ConnectionHandle &&h) noexcept
ConnectionHandle * operator->()
ScopedConnection(ScopedConnection &&) noexcept=default
A Signal provides a mechanism for communication between objects.
Definition: signal.h:72
The main namespace of the KDBindings library.
Definition: binding.h:21
Definition: utils.h:161

© Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
KDBindings
Reactive programming & data binding in C++
https://github.com/KDAB/KDBindings/
Generated by doxygen 1.9.1