Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
TrackableSignal.hpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of clio: https://github.com/XRPLF/clio
4 Copyright (c) 2024, the clio developers.
5
6 Permission to use, copy, modify, and distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#pragma once
21
22#include "util/Mutex.hpp"
23
24#include <boost/signals2.hpp>
25#include <boost/signals2/connection.hpp>
26#include <boost/signals2/variadic_signal.hpp>
27
28#include <cstddef>
29#include <functional>
30#include <memory>
31#include <mutex>
32#include <unordered_map>
33
34namespace feed::impl {
35
44template <typename Session, typename... Args>
46 using ConnectionPtr = Session*;
47 using ConnectionSharedPtr = std::shared_ptr<Session>;
48
49 // map of connection and signal connection, key is the pointer of the connection object
50 // allow disconnect to be called in the destructor of the connection
51 using ConnectionsMap = std::unordered_map<ConnectionPtr, boost::signals2::connection>;
52 util::Mutex<ConnectionsMap> connections_;
53
54 using SignalType = boost::signals2::signal<void(Args...)>;
55 SignalType signal_;
56
57public:
68 bool
69 connectTrackableSlot(ConnectionSharedPtr const& trackable, std::function<void(Args...)> slot)
70 {
71 auto connections = connections_.template lock<std::scoped_lock>();
72 if (connections->contains(trackable.get())) {
73 return false;
74 }
75
76 // This class can't hold the trackable's shared_ptr, because disconnect should be able to be
77 // called in the the trackable's destructor. However, the trackable can not be destroyed
78 // when the slot is being called either. `track_foreign` is racey when one shared_ptr is
79 // tracked by multiple signals. Therefore we are storing a weak_ptr of the trackable and
80 // using weak_ptr::lock() to atomically check existence and acquire a shared_ptr during slot
81 // invocation. This guarantees to keep the trackable alive for the duration of the slot call
82 // and avoids potential race conditions.
83 connections->emplace(
84 trackable.get(),
85 signal_.connect([slot, weakTrackable = std::weak_ptr(trackable)](Args&&... args) {
86 if (auto lifeExtender = weakTrackable.lock(); lifeExtender)
87 std::invoke(slot, std::forward<Args...>(args)...);
88 })
89 );
90 return true;
91 }
92
102 bool
103 disconnect(ConnectionPtr trackablePtr)
104 {
105 if (auto connections = connections_.template lock<std::scoped_lock>();
106 connections->contains(trackablePtr)) {
107 connections->operator[](trackablePtr).disconnect();
108 connections->erase(trackablePtr);
109 return true;
110 }
111 return false;
112 }
113
119 void
120 emit(Args const&... args) const
121 {
122 signal_(args...);
123 }
124
128 std::size_t
129 count() const
130 {
131 return connections_.template lock<std::scoped_lock>()->size();
132 }
133};
134} // namespace feed::impl
A thread-safe class to manage a signal and its tracking connections.
Definition TrackableSignal.hpp:45
bool disconnect(ConnectionPtr trackablePtr)
Disconnect a slot to the signal.
Definition TrackableSignal.hpp:103
std::size_t count() const
Get the number of connections.
Definition TrackableSignal.hpp:129
void emit(Args const &... args) const
Calling all slots.
Definition TrackableSignal.hpp:120
bool connectTrackableSlot(ConnectionSharedPtr const &trackable, std::function< void(Args...)> slot)
Connect a slot to the signal, the slot will be called when the signal is emitted and trackable is sti...
Definition TrackableSignal.hpp:69
A container for data that is protected by a mutex. Inspired by Mutex in Rust.
Definition Mutex.hpp:101